> This page is for API Reference & Tools.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.moveworks.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.moveworks.com/_mcp/server.

# Moveworks Data Mapper Common Examples

# **Overview**

These examples show how to shape real API payloads into the readable, well-formed data a plugin needs. Each one gives you a payload, the mapping that transforms it, and the exact result that mapping produces, so you can adapt a working starting point rather than build from the operator reference.

For the full catalog of operators, see the [Data Mapper / JSON Bender Reference](/api-reference/configuration-languages/moveworks-bender-language-reference). For a broader library of task-oriented recipes covering dates, conditionals, lookups, and dynamic URLs, see [Common DSL & Mapper Patterns](/api-reference/configuration-languages/common-dsl-mapper-patterns).

## Reading the syntax on this page

The mappings below mix two related languages, and knowing which one you are looking at makes them much easier to read.

**Operators** are the `NAME():` keys, such as `MAP()`, `SORT()`, and `EVAL()`. They are the structural layer: they build objects and lists, loop, and branch. Operator names are always uppercase and always end in `()`.

**DSL functions** are the `$`-prefixed calls that appear inside an expression, such as `$CONCAT` and `$FILTER`. They transform values. Every DSL function can be written as either `$FUNC(items, arg)` or `items.$FUNC(arg)`, and lambdas use arrow syntax — `x => x != null`. The [DSL Reference](/api-reference/configuration-languages/moveworks-dsl-reference) documents all of them.

Two details account for most early confusion:

* **A bare string is an expression, not a literal.** `sp_title: data.title` reads the `title` field. To assign the literal text `Complete`, quote it twice — `status: '"Complete"'` — because the outer quotes belong to YAML and the inner quotes make it a string in the expression.
* **Some names exist in both languages with different behavior.** `CONCAT()` the operator and `$CONCAT` the DSL function are not the same thing, and they differ in how they treat empty values. Check which layer you are in before reusing a name.

# **Examples**

## Display a list of items in a single field

Ticketing and request-management payloads often return a list of related records — approvers, tasks, watchers — when what you want to show the user is a single readable line. This example aggregates the `name` of every approver into one comma-separated field called `approvers`.

### Context

The API returns an array of approver objects, each with a name, email, and external identifier. The goal is one string listing every approver name.

### Given Payload Response

```json
{
  "approver_list": [
    {
      "name": "John Doe",
      "email": "john.doe@example.com",
      "external_id": "123456"
    },
    {
      "name": "Jane Smith",
      "email": "jane.smith@example.com",
      "external_id": "7891011"
    },
    {
      "name": "Alex Johnson",
      "email": "alex.johnson@example.com",
      "external_id": "121314"
    }
  ],
  "etc...": {}
}
```

### Bender Mapping

`MAP()` pulls `item.name` out of each object to produce a list of names, then `$CONCAT` joins that list into one string.

#### JSON

```json
{
  "approvers": {
    "EVAL()": {
      "expression": "$CONCAT(users, ', ')",
      "args": {
        "users": {
          "MAP()": {
            "items": "approver_list",
            "converter": "item.name"
          }
        }
      }
    }
  }
}
```

#### YAML

```yaml
approvers:
  EVAL():
    expression: "$CONCAT(users, ', ')"
    args:
      users:
        MAP():
          items: approver_list
          converter: item.name
```

### Expected Result

```json
{
  "approvers": "John Doe, Jane Smith, Alex Johnson"
}
```

> **Warning**
>
> `$CONCAT` inserts the separator exactly as you write it. It never adds a space of its own, so the separator `','` produces `"John Doe,Jane Smith,Alex Johnson"`. Include the space in the separator — `', '` — when you want one.

### Simpler alternative

Because `$MAP` and `$CONCAT` both exist as DSL functions, you can chain them in a single expression and skip the `MAP()` operator and `args` block entirely:

```yaml
approvers: approver_list.$MAP(a => a.name).$CONCAT(', ')
```

This produces the same result. Reach for the operator form when a step needs to build a nested object or list, and the DSL form when you are only transforming values.

## Return unique elements from an array

Duplicate values in a payload lead to repeated rows in a display record or redundant items in a downstream request. This example removes duplicates from an array and returns only the distinct values.

### Context

The API returns an array whose values may repeat. The goal is the same array with every duplicate removed.

There is no `$UNIQUE` function in the language, so deduplication is done in two steps: sort the values so duplicates become adjacent, then keep only the values that differ from the one before them.

### Given Payload Response

```json
{
  "data": [1, 2, 4, 3, 1, 4, 5, 6]
}
```

### Bender Mapping

`SORT()` groups equal values together. `$FILTER` then walks the sorted list and keeps an element when it is the first one (`i == 0`) or when it differs from its predecessor.

#### JSON

```json
{
  "items": {
    "EVAL()": {
      "expression": "sorted_records.$FILTER((x, i) => i == 0 OR x != sorted_records[i - 1])",
      "args": {
        "sorted_records": {
          "SORT()": {
            "items": "data",
            "key": "item"
          }
        }
      }
    }
  }
}
```

#### YAML

```yaml
items:
  EVAL():
    expression: "sorted_records.$FILTER((x, i) => i == 0 OR x != sorted_records[i - 1])"
    args:
      sorted_records:
        SORT():
          items: data
          key: item
```

### Expected Result

```json
{
  "items": [1, 2, 3, 4, 5, 6]
}
```

> **Info**
>
> In a `$FILTER` lambda the first parameter is always the value and the second is the index, so `(x, i)` reads as "value, index". The sorted list is still reachable by name inside the expression, which is what makes `sorted_records[i - 1]` possible.

> **Warning**
>
> This pattern works on lists of primitives — numbers, text, booleans. It fails on a list of objects, because `SORT()` cannot order objects and `!=` compares them structurally. To deduplicate objects, map them down to the single scalar you want to be unique first.

## Remove empty keys from the output mapper in a return statement

APIs frequently return fields as `null`, or omit them entirely. Passing those keys into a return statement gives the LLM empty context to reason over, and many APIs reject request bodies that contain `null` fields. This example builds an object and strips the empty keys out of it before returning.

### Context

A Microsoft Graph system returns purchase-order information, and you want to return only a few of its fields from a plugin. Some of those fields are `null` or missing on any given record.

### Given Payload Response

```json
{
  "data": {
    "title": "PO1234",
    "status": "Complete",
    "email": null,
    "country": "US"
  }
}
```

### Bender Mapping

Build the object you want inside `args`, then run `$FILTER` over it in `expression`. `$FILTER` keeps the entries whose value satisfies the lambda and returns an object of the same shape, minus the dropped keys.

```yaml
- return:
    output_mapper:
      EVAL():
        expression: sharepoint_info.$FILTER(x => x)
        args:
          sharepoint_info:
            sp_title: data.title
            sp_status: data.status
            sp_user: data.email
```

### Expected Result

```json
{
  "sp_title": "PO1234",
  "sp_status": "Complete"
}
```

> **Info**
>
> `args` supplies the data the expression runs against — it is scoping input, not part of the result. The output is whatever `expression` evaluates to, so the filtered object is returned directly and there is no `sharepoint_info` key wrapping it.

> **Warning**
>
> `$FILTER(x => x)` filters on truthiness, not on emptiness. It removes `null`, and it also removes `0`, `false`, `""`, `[]`, and `{}`. A legitimate zero quantity or a `false` flag disappears along with the nulls.
>
> To remove only `null` and keep every other value, compare against `null` explicitly:
>
> ```yaml
> expression: sharepoint_info.$FILTER(x => x != null)
> ```
>
> Against the payload above, this returns `sp_title` and `sp_status` and drops `sp_user`, but it would preserve a `0` or a `false`.