# Custom routing rules

Custom routing rules (previously known as the DOMS toolkit) help users define factors to consider when selecting the best fulfillment location.

{% hint style="info" %}
Custom routing rules can be created in Backoffice or via API. We recommend using Backoffice to reduce errors. You'll still need to understand how to work with [JSONPath](#introduction-to-jsonpath).
{% endhint %}

You can define fences and ratings:

* [**Fences**](/documentation/by-pillar/advanced-order-routing/fences.md): Exclude facilities from order routing based on to the selected fences.
* [**Ratings**](/documentation/by-pillar/advanced-order-routing/ratings.md): Weigh facilities against each other based on the selected ratings.

The table below outlines the fields for custom routing rule fences and ratings within the [routing strategy endpoint](/documentation/apis/api-reference/routing-strategy-doms.md#post-api-routing-strategies).&#x20;

<table><thead><tr><th>Field</th><th>Type<select><option value="BQFMQ2JEufL7" label="string" color="blue"></option><option value="ybktxGmgoaR0" label="boolean" color="blue"></option><option value="EguBBKHgvGpP" label="number" color="blue"></option><option value="ODcle6tNybMD" label="enum" color="blue"></option><option value="BCi55ZZwc5S0" label="integer" color="blue"></option><option value="7XzmHyLaWihO" label="object" color="blue"></option></select></th><th>Description</th><th>Possible values</th></tr></thead><tbody><tr><td><code>name</code></td><td><span data-option="BQFMQ2JEufL7">string</span></td><td>The name of the fence. It must be unique.</td><td></td></tr><tr><td><code>nameLocalized</code></td><td><span data-option="BQFMQ2JEufL7">string</span></td><td>An object containing the localized names of the fence for different languages.</td><td></td></tr><tr><td><code>description</code></td><td><span data-option="BQFMQ2JEufL7">string</span></td><td>An optional description to say what the fence has to do. Although optional, it's recommended that you provide a meaningful description.</td><td></td></tr><tr><td><code>descriptionLocalized</code></td><td><span data-option="BQFMQ2JEufL7">string</span></td><td>An object containing the localized descriptions for different languages.</td><td></td></tr><tr><td><code>entity1</code></td><td><span data-option="ODcle6tNybMD">enum</span></td><td>The entity type for the left side. For conditional rules, this is the entity that's evaluated first.</td><td><ul><li><code>ORDER</code></li><li><code>ORDERING_FACILITY</code></li><li><code>ORDERING_FACILITY_GROUPS</code></li></ul></td></tr><tr><td><code>entity2</code></td><td><span data-option="ODcle6tNybMD">enum</span></td><td>The entity type for the right side. For conditional rules, this is the entity that gets evaluated second (or not at all).</td><td><ul><li><code>FACILITY</code></li><li><code>CARRIERCONNECTION</code></li><li><code>LISTING</code></li></ul></td></tr><tr><td><code>type</code></td><td><span data-option="ODcle6tNybMD">enum</span></td><td>Defines whether it's a custom fence or rating.</td><td><ul><li><code>ToolkitFence</code></li><li><code>ToolkitRating</code></li></ul></td></tr><tr><td><code>referenceId</code></td><td><span data-option="BQFMQ2JEufL7">string</span></td><td>An identifier for the fence or the rating. Use a descriptive identifier.</td><td></td></tr><tr><td><code>active</code></td><td><span data-option="ybktxGmgoaR0">boolean</span></td><td>Defines whether the fence or rating is active.</td><td><ul><li><code>true</code></li><li><code>false</code></li></ul></td></tr><tr><td><code>order</code></td><td><span data-option="BCi55ZZwc5S0">integer</span></td><td>Fences only. Determines whether the fence should be executed before or after different fences. Lower numbers have precedence over higher numbers.</td><td></td></tr><tr><td><code>maxPenalty</code></td><td><span data-option="BCi55ZZwc5S0">integer</span></td><td>Ratings only. Determines the weight of the rating in comparison to other ratings. The higher the number, the more important it is.</td><td></td></tr><tr><td><code>rule</code></td><td><span data-option="7XzmHyLaWihO">object</span></td><td>Defines the <a href="#conditional-rule">conditional rule settings</a>.</td><td></td></tr><tr><td><code>comparisonRule</code></td><td><span data-option="7XzmHyLaWihO">object</span></td><td>Defines the <a href="#comparison-rule">comparison rule settings</a>.</td><td></td></tr></tbody></table>

## Rules

Two rule types that can be defined:

* [Conditional rule](#conditional-rule)
* [Comparison rule](#comparison-rule)

### Conditional rule

Use `rule` to set up a conditional rule. Conditional rules test a certain property of an entity (`order`, `facility`, `listing`) against a predefined static value. It can be used for comparing each side against a fixed value (for example, an order line item has a quantity greater than 3).&#x20;

It can't be used when using the `comparisonRule` field.&#x20;

A conditional rule must include:

| Field                 | Description                                                                                                                                                                                                                        | Possible values                                                              |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| **`evaluationScope`** | Defines whether the order is evaluated as a single unit (`WHOLE_ENTITY`) or if each `LINE_ITEM` is evaluated separately. See the [evaluation scope section](#evaluation-scope) for more details.                                   | <ul><li><code>WHOLE\_ENTITY</code></li><li><code>LINE\_ITEM</code></li></ul> |
| **`leftPart`**        | The first part that's evaluated. The evaluation result determines whether the right part gets evaluated. It consists of an array of `predicates` and a `predicateConnector` that determines how they are connected.                | See the [conditional rule parts section](#conditional-rule-parts).           |
| **`operator`**        | What the positive evaluation of the left side means for the execution of the fence as a whole. For now, there is only the equals operator.                                                                                         | <ul><li><code>EQUALS</code></li></ul>                                        |
| **`rightPart`**       | The second part is evaluated if the first evaluation passes. Its evaluation result determines the outcome of the fence. It consists of an array of `predicates` and a `predicateConnector` that determines how they are connected. | See the [conditional rule parts section](#conditional-rule-parts).           |

#### Conditional rule parts

The `leftPart` and the `rightPart` of a conditional rule must contain at least one `predicates`. If more than one is used, a `predicateConnector` must also be defined.

| Field                    | Description                                                                                                                                                         | Possible values                                                              |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| **`predicates`**         | An array of one or more predicates.                                                                                                                                 | See the [Conditional rule predicates section](#conditional-rule-predicates). |
| **`predicateConnector`** | `AND` will only make the expression `true` if all predicates evaluate to true. `OR` will make the rule expression `true` if any of the predicates evaluate to true. | <ul><li><code>AND</code></li><li><code>OR</code></li></ul>                   |

#### Conditional rule predicates

`predicates` is an array that consists of the following fields. At least one predicate must be defined. Maximum of 100 predicates.

| Field                    | Description                                                                                                                                             | Possible values                                                                                                                                                                                                                                                  |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`entity`**             | The entity type that can be compared.                                                                                                                   | <ul><li><code>ORDER</code></li><li><code>FACILITY</code></li><li><code>CARRIERCONNECTION</code></li><li><code>LISTING</code></li><li><code>ORDERING\_FACILITY</code> - left side only</li><li><code>ORDERING\_FACILITY\_GROUPS</code> - left side only</li></ul> |
| **`entityOperator`**     | The operators determine how an entity's property should be compared to a given value.                                                                   | See the [Entity operators section](#conditional-rules-entity-operators).                                                                                                                                                                                         |
| **`propertyPath`**       | A [JSONPath](#introduction-to-jsonpath) expression defining the property to look at.                                                                    | See the [JSONPath section](#introduction-to-jsonpath).                                                                                                                                                                                                           |
| **`expectedValue`**      | The expected value that the property should match. For example, `2` (`number`), `"WAREHOUSE"` (`string`), `"2024-02-19T16:16:38.107Z"` (`date-string`). |                                                                                                                                                                                                                                                                  |
| **`transformation`**     | \[optional] A [transformation](#transformers).                                                                                                          | See the [Transformers section](#transformers).                                                                                                                                                                                                                   |
| **`transformationArgs`** | \[optional] The arguments for the transformation, if required.                                                                                          | Depends on the `transformation` used. See the [Transformers section](#transformers).                                                                                                                                                                             |

#### Conditional rules entity operators

An `entityOperator` determines how an entity's property should be compared to a given value. They can be divided into two groups: Single value entity operators and array entity operators.

**Single value entity operators**

These operators can only be used for single values, not for arrays.

| Operator             | Description                                               | Example                                                        |
| -------------------- | --------------------------------------------------------- | -------------------------------------------------------------- |
| `VALUE_EQUALS`       | Actual value equals `expectedValue`                       | `2 == 2`                                                       |
| `VALUE_NOT_EQUALS`   | Actual value is not equal to the `expectedValue`          | `2 != 3`                                                       |
| `VALUE_CONTAINS`     | Actual value contains `expectedValue`                     | The value is `HELLO WORLD`, and the `expectedValue` is `HELLO` |
| `VALUE_NOT_CONTAINS` | Actual value doesn't contain `expectedValue`              | The value is `HELLO WORLD`, and `expectedValue` is `HI`        |
| `LESS_THAN`          | Actual value is less than `expectedValue`                 | `2 < 3`                                                        |
| `LESS_EQUALS`        | Actual value is less than or equal to the `expectedValue` | `2 <= 3`, `3 <= 3`                                             |
| `GREATER_THAN`       | Actual value is greater than the `expectedValue`          | `3 > 2`                                                        |
| `GREATER_EQUALS`     | Actual value is greater than or equal to `expectedValue`  | `3 >= 2`, `2 >= 2`                                             |

**Array entity operators**

These operators can only be used for arrays, not for single values. They can be grouped into three categories:&#x20;

* `ANY`: Requires that at least one element of the array satisfies the following condition. If the array is empty, this condition won't be fulfilled.
* `EVERY`: Requires that every element of the array satisfies the following condition. If the array is empty, this condition will be true because no element doesn't fulfill the condition.
* `NONE`: Requires that no element satisfies the following condition, meaning that every element doesn't satisfy the condition. This condition will always be fulfilled, unless there is an element that satisfies the condition, including for empty arrays.&#x20;

Possible operator values:

{% columns %}
{% column width="33.33333333333333%" %}
`ANY_VALUE_EQUALS`

`ANY_VALUE_GREATER_EQUALS`

`ANY_VALUE_GREATER_THAN`

`ANY_VALUE_LESS_EQUALS`

`ANY_VALUE_LESS_THAN`

`ANY_VALUE_NOT_CONTAINS`
{% endcolumn %}

{% column width="33.33333333333333%" %}
`EVERY_VALUE_EQUALS`

`EVERY_VALUE_GREATER_EQUALS`

`EVERY_VALUE_GREATER_THAN`

`EVERY_VALUE_LESS_EQUALS`

`EVERY_VALUE_LESS_THAN`

`EVERY_VALUE_CONTAINS`

`EVERY_VALUE_NOT_CONTAINS`
{% endcolumn %}

{% column %}
`NO_VALUE_EQUALS`

`NO_VALUE_GREATER_EQUALS`

`NO_VALUE_GREATER_THAN`

`NO_VALUE_LESS_EQUALS`

`NO_VALUE_LESS_THAN`

`NO_VALUE_CONTAINS`

`NO_VALUE_NOT_CONTAINS`
{% endcolumn %}
{% endcolumns %}

**Single value operators versus array operators**

If your actual value is an array, you have to use an array operator. For example, if you use a wildcard operator (`*` or `?()`), you'll get an array of elements (such as `$.orderLineItems[*]`). However, if you use a transformer (such as `COUNT` to get the number of elements or `SUM` to add the quantities of each `orderLineItem`), then you will get a single value and must use a single value operator.

### Comparison rule

Use `comparisonRule` to set up a comparison rule. Comparison rules compare a property of the left-hand side (`order`) with a property of the right-hand side (`order`, `facility`, `listing`). Incompatible with using the rule field.

An example of this could be an order with products of a certain brand that requires a facility tagged with the same brand.

A comparison rule must include:

| Field                    | Description                                                                                                                                                                                      | Possible values                                                              |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
| **`evaluationScope`**    | Defines whether the order is evaluated as a single unit (`WHOLE_ENTITY`) or if each `LINE_ITEM` is evaluated separately. See the [evaluation scope section](#evaluation-scope) for more details. | <ul><li><code>WHOLE\_ENTITY</code></li><li><code>LINE\_ITEM</code></li></ul> |
| **`predicates`**         | An array of one or more predicates.                                                                                                                                                              | See the [Comparison rule predicates section](#comparison-rule-predicates).   |
| **`predicateConnector`** | `AND` will only make the expression `true` if all predicates evaluate to true. `OR` will make the rule expression `true` if any of the predicates evaluate to true.                              | <ul><li><code>AND</code></li><li><code>OR</code></li></ul>                   |

#### Comparison rule predicates

`predicates` is an array that consists of the following fields. At least one predicate must be defined. Maximum of 100 predicates.

| Field                         | Description                                                                              | Possible values                                                                                                                                                                                                                |
| ----------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`entityOperator`**          | The operators determine how an entity's property should be compared to a given value.    | See the [Entity operators section](#conditional-rules-entity-operators-1).                                                                                                                                                     |
| **`leftEntity`**              | The entities that the rating can compare.                                                | <ul><li><code>ORDER</code></li><li><code>FACILITY</code></li><li><code>CARRIERCONNECTION</code></li><li><code>LISTING</code></li><li><code>ORDERING\_FACILITY</code></li><li><code>ORDERING\_FACILITY\_GROUPS</code></li></ul> |
| **`leftPropertyPath`**        | A string containing a [JSONPath](#introduction-to-jsonpath) for the left entity.         | See the [JSONPath section](#introduction-to-jsonpath).                                                                                                                                                                         |
| **`leftTransformation`**      | \[optional] The [transformation](#transformers) for the left entity.                     | See the [Transformers section](#transformers).                                                                                                                                                                                 |
| **`leftTransformationArgs`**  | \[optional] The arguments for the left transformation, if required.                      | Depends on the `transformation` used. See the [Transformers section](#transformers).                                                                                                                                           |
| **`rightEntity`**             | The entities that the rating can compare.                                                | <ul><li><code>ORDER</code></li><li><code>FACILITY</code></li><li><code>CARRIERCONNECTION</code></li><li><code>LISTING</code></li></ul>                                                                                         |
| **`rightPropertyPath`**       | A string containing a [JSONPath](#introduction-to-jsonpath) for the right entity.        | See the [JSONPath section](#introduction-to-jsonpath).                                                                                                                                                                         |
| **`rightTransformation`**     | The [transformation](#transformers) for the right entity.                                | See the [Transformers section](#transformers).                                                                                                                                                                                 |
| **`rightTransformationArgs`** | The transformation arguments for the right [transformation](#transformers), if required. | Depends on the `transformation` used. See the [Transformers section](#transformers).                                                                                                                                           |

#### Comparison rules entity operators

An `entityOperator` determines how an entity's property should be compared to a given value.

| Operator              | Description                                                                                  |
| --------------------- | -------------------------------------------------------------------------------------------- |
| `LEFT_CONTAINS_RIGHT` | The left-hand side should contain all values from the right-hand side.                       |
| `RIGHT_CONTAINS_LEFT` | The right-hand side should contain all values from the left-hand side.                       |
| `ALL_MATCHES`         | The arrays of values should be exactly equal.                                                |
| `NO_MATCHES`          | Values should be different, even when comparing a list with a single value (blocklist case). |

## Introduction to JSONPath

We use JSONPath for creating custom routing rules. You'll need to understand the operators, functions, and filters to ensure the custom routing rule works as expected. You can find the full information in the [JSONPath documentation](https://github.com/json-path/JsonPath). You can also use a [JSONPath expression tester tool](https://jsonpath.com/) to ensure your path is valid.

JSONPaths are used in `propertyPath` for [conditional rules](#conditional-rule-predicates) and `leftPropertyPath` and `rightPropertyPath` for [comparison rules](#comparison-rule).

JSONPaths always begin with `$`, which refers to the entity that's defined in the predicate, for example, an `ORDER`. Nested properties are accessed using `.`. Nested array properties, such as `orderLineItems`, `tags`, or `stickers`, are accessed using array brackets (`[` and `]`) with `*` to indicate a wildcard. For example, `$.orderLineItems[*].quantity`.&#x20;

Instead of a wildcard (`*`), you can use the `?()` syntax. You can then define an arbitrary expression inside the parentheses using the `@` symbol to refer to the entity being tested.

For more specific filtering, use `?()` instead of `*`. Inside the parentheses, define an arbitrary expression using `@` to refer to the entity being tested. You can then access all of its nested attributes and test for an arbitrary condition.

Let's look at some more examples:

| Expression                                                                                   | Description                                                                                                |
| -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `$.tenantOrderId`                                                                            | Gets the order with the specified `tenantOrderId`.                                                         |
| `$.orderLineItems[*].article`                                                                | Gets the articles from all `orderLineItems`, resulting in an array.                                        |
| `$.orderLineItems[?(@.quantity > 3)].article`                                                | Gets the articles from `orderLineItems` with a quantity greater than 3.                                    |
| `$.orderLineItems[?(@.tags.find(tag => tag.id === 'color' && tag.value === 'red'))].article` | Gets the articles of all `OrderLineItems` that have at least one tag of type `color` with the value `red`. |

{% hint style="info" %}
It's recommended to keep your expressions as simple as possible without compromising their functionality to avoid mistakes that could lead to misbehavior of the fence/rating.
{% endhint %}

## Evaluation scope

`evaluationScope` allows you to set how the order will be evaluated. An evaluation scope of `WHOLE_ENTITY` evaluates the order as a single unit. Whereas with the scope `LINE_ITEM`, each order line is evaluated separately.

The difference in `evaluationScope` applies only when the left side of the rule doesn't reference the entire order but operates on the `orderLineItem` level.

### **Evaluation scope example**

Let's say we set up the following custom fence definition:

{% columns %}
{% column %}
Left part

```
entity: ORDER 
propertyPath: $.order.orderLineItems[*].tags[?(@.id == 'FAST_RUNNER')].value 
operator: ANY_VALUE_EQUALS 
expectedValue: true
```

{% endcolumn %}

{% column %}
Right part

```
entity: FACILITY 
propertyPath: $.locationType 
expectedValue: WAREHOUSE
```

{% endcolumn %}
{% endcolumns %}

Depending on whether we set the `evalutionScope` to `WHOLE_ENTITY` or `LINE_ITEM`, we will see different behavior:

<table><thead><tr><th width="366.67230224609375">WHOLE_ENTITY</th><th>LINE_ITEM</th></tr></thead><tbody><tr><td>If at least one <code>orderLineItem</code> has the tag <code>FAST_RUNNER = true</code>, the entire order must be routed to warehouse locations.</td><td>Only <code>orderLineItems</code> with the tag <code>FAST_RUNNER = true</code> must be routed to warehouse locations. The remaining items can potentially also be routed to locations with types other than warehouse.</td></tr></tbody></table>

## Transformers

`transformation` allows for modifying the input to `predicates` before it gets evaluated. This can serve multiple purposes. For example, only look at the number of elements, get the total price of all `orderLineItems`, or only consider the beginning of the `tenantOrderId`.

The transformations currently available are:

* `SUM`: Sums the number values of each element, requires an array of elements
* `COUNT`: Counts the number of elements, requires an array of elements
* `SUBSTRING`: Gets a substring of a value, requires `start` and `end` parameters
* `LAST`: Gets the last `n` characters of a string, requires a `length` parameter

### Count transformation

Applies to orders with 10 or more `orderLineItems`.

```json
{
"propertyPath": "$.orderLineItems[*]",
"transformation": "COUNT",
"entityOperator": "GREATER_THAN",
"expectedValue": 10
}
```

### Sum transformation

Applies to orders where the sum of all `orderLineItems` quantities is 100 or more.

```json
{
"propertyPath": "$.orderLineItems[*].quantity",
"transformation": "SUM",
"entityOperator": "GREATER_THAN",
"expectedValue": 100
}
```

### Substring transformation

Applies to orders where any `orderLineItem` has a `tenantArticleId` that begins with `Coca`. Here, we use `transformationArgs` to ensure that the first 4 letters are used.

```json
{
"propertyPath": "$.orderLineItems[*].article.tenantArticleId",
"transformation": "SUBSTRING",
"entityOperator": "ANY_VALUE_EQUALS",
"expectedValue": "Coca",
"transformationArgs": [0, 4]
}
```

### Last characters transformation

Applies to orders where any `orderLineItem` has a `tenantArticleId` that ends with `Christmas special`

```json
{
"propertyPath": "$.orderLineItems[*].article.tenantArticleId",
"transformation": "LAST",
"entityOperator": "ANY_VALUE_EQUALS",
"expectedValue": "Christmas special"
}
```

## Time specifications

It's possible to define a time specification as an expected value, enabling dynamic comparisons during routing processes. For example, a timestamp stored in a `customAttribute` can be compared against the current time using predefined expressions.

* `{today}`: represents the current day, based on the tenant's configured time zone. This expression refers to a date value (for example, `2025-08-07`).
* `{now}`: represents the current timestamp, calculated in UTC+0. This expression refers to a specific timestamp (for example, `2025-08-07T18:00:00.000Z`).

This functionality, for example, allows routing logic to determine whether an item is eligible for release to sales, based on time-based conditions.

{% hint style="info" %}
When using the `"entityOperator": "EQUALS"` for timestamp comparisons, be aware that it includes minutes and seconds. This may lead to unintended mismatches unless the timestamps are precisely aligned.
{% endhint %}

```json
{
"propertyPath": "$.customAttributes.releaseDate",
"transformation": "null",
"entityOperator": "LESS_EQUALS",
"expectedValue": "{today}",
"entity": "LISTING"
}
```


---

# 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.fulfillmenttools.com/documentation/by-pillar/advanced-order-routing/doms-toolkit.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.
