Skip to navigation

Optional Lab: Moveworks Bender

View as Markdown

Overview

  • Learning Objectives: Use Moveworks Bender to configure attribute mappings for users and tickets, and validate them in the DSL and Data Mapper Playground before applying them.
  • Estimated Time: 15 minutes
  • Prerequisites:
    • Lab #4 complete (its user identity configuration is the Bender mapping you test)

Key Concepts

Bender is the transformation engine that sits between connected raw system data and the Moveworks UI. It is essential for formatting data correctly:

  • Bender Mapping: The logic used to tell Moveworks how to display raw JSON values. For example, turning a technical “state” code into a human-readable word.
  • Display Value: A ServiceNow-specific concept where value is a raw ID (e.g., a sys_id) and display_value is the actual text shown to the user.
  • Fallback Logic: The use of the OR operator (e.g., phone.display_value OR "") to provide a default value and prevent the Moveworks AI Assistant from breaking if a field is empty.
  • DSL & Data Mapper Playground: A sandbox where you can paste raw JSON from the API Playground to test if your Bender mappings will work before applying them.

Relevant Documentation:


🛠️ 1: Walkthrough

1.1: Generate a Moveworks API Key via Tool Studio

  1. Open HTTP Connectors from the waffle menu.

  2. Select the Credentials module

  3. Click Create

  4. Give your credential a name, and generate it as an API Key and Publish it

  5. Select Copy to Clipboard, and store this API key on your machine.

  6. In a separate tab, navigate to the Moveworks DSL and Data Mapper Playground. Enter your API key in the API Key section.

Switch the region to match your Moveworks instance before entering your API key. The region selector is in the top-right corner of the page. Use the table below to find your region.

Which region should I use? Your region is determined by your Moveworks login URL. Find org_name in your URL and match it to the table below:

Select in toolData CenterYour login URL contains
USUnited States (default)org_name.moveworks.com
EUEUorg_name.am-eu-central.moveworks.com
CACanadaorg_name.am-ca-central.moveworks.com
AUSAustralia / Asia Pacificorg_name.am-ap-southeast.moveworks.com
GovCloudGovernment Secure Cloudorg_name.moveworksgov.com
US3United States (lab environment)org_name.us3.moveworks.com

For example, if your instance URL is acme.moveworks.com, select US. If it is acme.us3.moveworks.com, select US3.

Note: If you receive an error that states that an on-prem agent cannot connect, try opening the page in an incognito browser window and try again


1.2: Get the Default Bender Mapping for Moveworks ServiceNow User Identity

  1. In Moveworks Setup, navigate to User Identity > Import Users > Edit

  2. Switch to Advanced Mode to see the JSON configuration for ingesting users from ServiceNow.

  3. Copy the JSON block that defines the ServiceNow user ingestion logic (also shown below).

{
"internal_fields": {
"manager_resolver": "$TRIM(IF sys_id THEN sys_id.display_value OR \"\" ELSE NULL)"
},
"phone_number": "$TRIM(IF phone THEN phone.display_value OR \"\" ELSE NULL)",
"user_name": "$TRIM(IF user_name THEN user_name.display_value OR \"\" ELSE NULL)",
"employee_id": "$TRIM(IF employee_number THEN employee_number.display_value OR \"\" ELSE NULL)",
"department": "$TRIM(IF department THEN department.display_value OR \"\" ELSE NULL)",
"full_name": "$TRIM(IF name THEN name.display_value OR \"\" ELSE NULL)",
"user_id_info.user_email": "if $TRIM(IF email THEN email.display_value OR \"\" ELSE NULL) then [$TRIM($TRIM(IF email THEN email.display_value OR \"\" ELSE NULL))] else []",
"city": "$TRIM(IF city THEN city.display_value OR \"\" ELSE NULL)",
"country_code": "$TRIM(IF country THEN country.display_value OR \"\" ELSE NULL)",
"email_addr": "$TRIM(IF email THEN email.display_value OR \"\" ELSE NULL)",
"first_name": "$TRIM(IF first_name THEN first_name.display_value OR \"\" ELSE NULL)",
"timezone": "$TRIM(IF time_zone THEN time_zone.display_value OR \"\" ELSE NULL)",
"cost_center_name": "$TRIM(IF cost_center THEN cost_center.display_value OR \"\" ELSE NULL)",
"role": "$TRIM(IF title THEN title.display_value OR \"\" ELSE NULL)",
"manager_email": "(manager).value.$TRIM()",
"user_id_info.user_itsm_id_info": [
{
"first_name": "$TRIM(IF first_name THEN first_name.display_value OR \"\" ELSE NULL)",
"external_id": "$TRIM(IF sys_id THEN sys_id.display_value OR \"\" ELSE NULL)",
"integration_id": "\"snow\"",
"full_name": "$TRIM(IF name THEN name.display_value OR \"\" ELSE NULL)",
"itsm_user_id": "$TRIM(IF user_name THEN user_name.display_value OR \"\" ELSE NULL)",
"system": "\"SNOW\"",
"last_name": "$TRIM(IF last_name THEN last_name.display_value OR \"\" ELSE NULL)"
}
],
"state": "$TRIM(IF state THEN state.display_value OR \"\" ELSE NULL)",
"user_tags": {
"FILTER()": {
"items": [
"\"BASIC_USER\"",
{
"CONDITIONAL()": {
"condition": "$LOWERCASE(((vip.value OR \"\"))) == $LOWERCASE((\"TRUE\"))",
"on_pass": "\"VIP\""
}
}
]
}
},
"location": "$TRIM(IF location THEN location.display_value OR \"\" ELSE NULL)",
"last_name": "$TRIM(IF last_name THEN last_name.display_value OR \"\" ELSE NULL)"
}
  1. Paste it into the Editor section of the DSL and Data Mapper Playground

  2. In API Playground, query the sys_user table and copy a single user record.

Moveworks maps records one at a time, so testing against a single record previews exactly how ingested data will look.

{
"calendar_integration": {
"display_value": "Outlook",
"value": "1"
},
"country": {
"display_value": null,
"value": ""
},
"user_password": {
"display_value": "********",
"value": ""
},
"last_login_time": {
"display_value": "2019-04-05 22:16:30",
"value": "2019-04-05 22:16:30"
},
"source": {
"display_value": "",
"value": ""
},
"sys_updated_on": {
"display_value": "2025-12-29 10:39:30",
"value": "2025-12-29 10:39:30"
},
"building": {
"display_value": "",
"value": ""
},
"web_service_access_only": {
"display_value": "false",
"value": "false"
},
"notification": {
"display_value": "Enable",
"value": "2"
},
"enable_multifactor_authn": {
"display_value": "false",
"value": "false"
},
"sys_updated_by": {
"display_value": "system",
"value": "system"
},
"sys_created_on": {
"display_value": "2019-04-05 21:09:12",
"value": "2019-04-05 21:09:12"
},
"sys_domain": {
"display_value": "global",
"link": "https://[your-instance].service-now.com/api/now/table/sys_user_group/global",
"value": "global"
},
"state": {
"display_value": "",
"value": ""
},
"fax": {
"display_value": "",
"value": ""
},
"identity_type": {
"display_value": "-",
"value": "unclassified"
},
"vip": {
"display_value": "false",
"value": "false"
},
"sys_created_by": {
"display_value": "admin",
"value": "admin"
},
"zip": {
"display_value": "",
"value": ""
},
"home_phone": {
"display_value": "",
"value": ""
},
"time_format": {
"display_value": null,
"value": ""
},
"last_login": {
"display_value": "2019-04-05",
"value": "2019-04-05"
},
"default_perspective": {
"display_value": "",
"value": ""
},
"active": {
"display_value": "true",
"value": "true"
},
"sys_domain_path": {
"display_value": "/",
"value": "/"
},
"transaction_log": {
"display_value": "",
"value": ""
},
"cost_center": {
"display_value": "",
"value": ""
},
"phone": {
"display_value": "",
"value": ""
},
"name": {
"display_value": "survey user",
"value": "survey user"
},
"employee_number": {
"display_value": "",
"value": ""
},
"password_needs_reset": {
"display_value": "false",
"value": "false"
},
"gender": {
"display_value": null,
"value": ""
},
"city": {
"display_value": "",
"value": ""
},
"hr_integration_source": {
"display_value": "",
"value": ""
},
"failed_attempts": {
"display_value": "0",
"value": "0"
},
"user_name": {
"display_value": "survey.user",
"value": "survey.user"
},
"roles": {
"display_value": "",
"value": ""
},
"manager_hp1": {
"display_value": "/T1}C(",
"value": "/T1}C("
},
"title": {
"display_value": "",
"value": ""
},
"sys_class_name": {
"display_value": "User",
"value": "sys_user"
},
"sys_id": {
"display_value": "005d500b536073005e0addeeff7b12f4",
"value": "005d500b536073005e0addeeff7b12f4"
},
"federated_id": {
"display_value": "UU/OJDA/H2viaQb8VqlJIYSYKwmbkOCLoFDQkTPv7XM=",
"value": "UU/OJDA/H2viaQb8VqlJIYSYKwmbkOCLoFDQkTPv7XM="
},
"internal_integration_user": {
"display_value": "false",
"value": "false"
},
"ldap_server": {
"display_value": "",
"value": ""
},
"mobile_phone": {
"display_value": "",
"value": ""
},
"street": {
"display_value": "",
"value": ""
},
"company": {
"display_value": "",
"value": ""
},
"department": {
"display_value": "",
"value": ""
},
"first_name": {
"display_value": "survey",
"value": "survey"
},
"email": {
"display_value": "survey.user@email.com",
"value": "survey.user@email.com"
},
"introduction": {
"display_value": null,
"value": ""
},
"preferred_language": {
"display_value": null,
"value": ""
},
"u_password_expiry_date": {
"display_value": "",
"value": ""
},
"manager": {
"display_value": "",
"value": ""
},
"locked_out": {
"display_value": "false",
"value": "false"
},
"sys_mod_count": {
"display_value": "2",
"value": "2"
},
"last_name": {
"display_value": "user",
"value": "user"
},
"photo": {
"display_value": "",
"value": ""
},
"avatar": {
"display_value": "",
"value": ""
},
"middle_name": {
"display_value": "",
"value": ""
},
"sys_tags": {
"display_value": "",
"value": ""
},
"time_zone": {
"display_value": null,
"value": ""
},
"schedule": {
"display_value": "",
"value": ""
},
"u_coe_specialization": {
"display_value": "",
"value": ""
},
"correlation_id": {
"display_value": "",
"value": ""
},
"date_format": {
"display_value": null,
"value": ""
},
"location": {
"display_value": "",
"value": ""
}
}
  1. Copy this JSON into the Input Payload for the DSL and Mapper Playground

  2. Click Process to see the Bender mapping applied to the input payload.

Use this loop during any build to confirm fields populate exactly as intended:

  • Retrieve a sample record from your external system.
  • Configure the Bender to map your required fields.
  • Validate the mapping results within the DSL and Data Mapper tool.


1.3: Use the DSL Architect to Draft Bender Mappings

The Moveworks Agent Architect is an AI tool connected to Moveworks documentation. Its DSL Architect drafts DSL and Bender logic.

  1. Open the Moveworks Agent Architect and select the DSL Architect.

  2. Give the DSL Architect the input payload and your goal. Use this example prompt:

text
Based on the following input payload, please generate a complete, valid Bender mapping in both JSON and YAML formats. I am using this for a class, so please include a brief HTML introduction explaining the concepts covered.
Specifically, I need the following 5 complex data transformation examples included in the mapping:
1. String Templating (user_summary): Use RENDER() to create a sentence combining calendar_integration.display_value and sys_updated_on.display_value.
2. Conditional Logic (security_risk_assessment): Use EVAL() with an IF/THEN/ELSE statement to return 'High Risk' if both enable_multifactor_authn.value and web_service_access_only.value are 'false', otherwise 'Standard'.
3. Risk Score (risk_score): Use the CONDITIONAL() operator to return 100 if enable_multifactor_authn.value is 'false', and 0 if it passes.
4. Time Parsing (last_login_epoch): Use EVAL() and $PARSE_TIME() to convert last_login_time.value into an epoch timestamp.
5. Data Fallbacks (location_info): Use COALESCE() to return the first available value among building.display_value, country.display_value, or a hardcoded string '"Unknown Location"'.
Please ensure the JSON is fully closed and valid. Here is the payload:
{
"building": { "display_value": "", "value": "" },
"calendar_integration": { "display_value": "Outlook", "value": "1" },
"country": { "display_value": null, "value": "" },
"enable_multifactor_authn": { "display_value": "false", "value": "false" },
"last_login_time": { "display_value": "2019-04-05 22:16:30", "value": "2019-04-05 22:16:30" },
"sys_updated_on": { "display_value": "2025-12-29 10:39:30", "value": "2025-12-29 10:39:30" },
"web_service_access_only": { "display_value": "false", "value": "false" }
}
  1. The Architect returns a draft Bender mapping. Copy the Bender JSON.

  2. Paste it into the Editor section and click Process to see how it changes the mapped user.


✅ 2: Verification & Next Steps

  1. Finalize:
    • Confirm that the JSON mapping processes successfully without errors.
  2. Inspect:
    • Analyze the functions and dot-walking logic used in the Editor section of the Data Mapping Playground. Review how these functions transform the input and why the resulting output appears the way it does.
  3. Experiment:
    • Modify the Input Payload and Editor values to see how the output changes. Try incorporating different logic or nested fields to test the limits of the mapping.
  4. Reference:

Next: Return to the Moveworks Setup labs to continue with the core labs or pick another optional lab.


🪞 3: Reflecting on This Configuration

Through this lab, you’ve learned the following:

  • How to use the DSL and Data Mapper Playground
  • Where to pull existing configuration JSON values from to test how the configuration will be applied
    • API Playground (Resource)
    • User Identity or Ticketing Configuration (Bender Mapping)
  • Where to find additional examples of the Moveworks Bender language & associated functions
  • How to use the Moveworks Agent Architect to help write complex bender mappings

🧠 4: Knowledge Check

1. Based on the ServiceNow JSON structure, why do we use .display_value in our Bender mappings instead of just the field name?

  • Answer: ServiceNow stores data in objects where value is often a raw ID (like a sys_id) or a code, while display_value contains the human-readable string.

2. In the following Bender snippet from your lab, what is the purpose of the OR ""? $TRIM(IF phone THEN phone.display_value OR "" ELSE NULL)

  • Answer: It provides a fallback to an empty string to prevent the mapping from failing or returning an error if the display_value property is missing.

3. Which Moveworks tool should you use if you want to test how a specific user’s raw ServiceNow data will look after being processed by your Bender configuration?

  • Answer: The DSL and Data Mapper Playground.

4. True or False: The RENDER() function is used for mathematical calculations like risk scores.

  • Answer: False. RENDER() is used for string templating to create human-readable sentences. (Bonus: CONDITIONAL() or EVAL() would be used for scores).

⚙️ 5: Configuration Details

Use the table below to fill in the required fields accurately.

Field NameAction / Value to Enter
Moveworks API KeyGenerated within Moveworks Setup → Waffle Menu (HTTP Connectors) → Credentials → Create
API Key → Credential Nameany_value
API Key → Credential TypeAPI Key
Data Mapper Playground → Input PayloadCopy the full JSON record from the code block above (Step 1.2)
Data Mapper Playground → EditorCopy the Bender mapping JSON from the code block above (Step 1.2)
Agent Architect QuerySee the example prompt in the code block in Step 1.3 above