*** title: 'Lab #6b: Moveworks Bender' position: 8 deprecated: false hidden: false metadata: robots: index ------------- ## Overview * **Learning Objectives:** Understand how to leverage Moveworks Bender to configure attribute mappings for users and tickets. Use the DSL & Bender Mapper Playground to validate configurations before applying them. * **Estimated Time:** 15 minutes * **Prerequisites:** * Lab 1 complete (snow connector with sys\_user access) * Lab 2 complete (user identity configured — provides the Bender mapping to test against) *** ### 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 bot 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:** * [Moveworks Help: Bender Data Mapping](https://help.moveworks.com/service-management/core-platform/configuration-languages/moveworks-bender-language-reference) * [Moveworks Help: DSL & Data Mapper Playground](https://help.moveworks.com/agent-studio/configuration-languages/dsl-and-mapper-playground) * [Moveworks Agent Marketplace: Agent Architect](https://marketplace.moveworks.com/chat/new) *** ## 🛠️ 1: Walkthrough ### 1.1: Generate a Moveworks API Key via Agent Studio 1. Navigate to the **`HTTP Connectors`** page via the Waffle Menu to generate a Moveworks API Key ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/0a48926b08848997abef6264d9d0eae76e036309fd8d82444bcc2365039880e4/docs/assets/images/setup-labs/lab6b_f18cf925-a446-4f4a-b61a-b9d26c7e8a28_lab_3_navigate_to_connectors.png) 2. Select the **`Credentials`** module ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/43a5c7edaa717c7821bf04404b0c7731c91aa36037b6490af7d03641c3aa3a9a/docs/assets/images/setup-labs/lab6b_31ff7e02-0001-420c-a3ff-6ed232c5a8fc_lab_4_navigate_to_credentials.png) 3. Click **`Create`** ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/0e361b297897a4c077d9ccf290b0b665ec4d546d52a07036b642b07272cf2a51/docs/assets/images/setup-labs/lab6b_d71423f6-d749-416a-81ef-f4748241ffb6_lab_4_create_credentials.png) 4. Give your credential a name, and generate it as an **`API Key`** and **`Publish`** it ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/62a32b60636f365f64364ea70a63b983fd9bb8af8a7d4ecf59acbc49d304093c/docs/assets/images/setup-labs/lab6b_73f84dfd-395a-4e37-a8a8-150b672a3e60_lab_4_create_api_key.png) 5. Select **`Copy to Clipboard`**, and store this API key on your machine. ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/536ec3dae0a6e3621ad7ec09d7f82a650f06a127eb910c3400fcb0db47750921/docs/assets/images/setup-labs/lab6b_aafdf87a-c6e6-4b6d-b452-936365725151_lab_4_generate_api_key.png) 6. In a separate tab, navigate to the [Moveworks DSL and Data Mapper Playground](https://docs.moveworks.com/agent-studio/configuration-languages/dsl-and-mapper-playground). Enter your API key in the `API Key` section. **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 ## ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/7aa69053537d180e2a71e6c2073bee567aaca82de81829c83e550f12258eb5aa/docs/assets/images/setup-labs/lab6b_1c59baa7-3fdf-4953-be1b-a8055cd06553_lab_4_use_api_key.png) ### 1.2: Get the Default Bender Mapping for Moveworks ServiceNow User Identity 1. In **Moveworks Setup,** navigate to **`User Identity > Import Users > Edit`** ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/bbbd44e2f83b4f13d532722a6848bb2c57c7516e60796d0e431a4d36185d460f/docs/assets/images/setup-labs/lab6b_52f8b307-b077-4992-aee5-8ee22939e68f_user_identity_import_users_edit.png) 2. Now that we have confirmed we can see users, we will use the following configuration example in **`Advanced Mode`** to grab the JSON block representing the configuration for ingesting users from ServiceNow ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/efb4ae8415e093db13ce8d46e567cc8914f1d65d51e6024e5827c23510691081/docs/assets/images/setup-labs/lab6b_d40a5462-f754-492e-8ca2-056f3b6760aa_user_identity_advanced_mode.png) 3. Copy the JSON block that defines the ServiceNow User Ingestion Logic (Also available below) ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/c205e14a7a701ac6c4b024f8c41a5ccb88a245fa479a67670e1b81ba213b36b9/docs/assets/images/setup-labs/lab6b_33c3fd72-5fc3-4282-8192-54e818c39241_dsl_bender_copy_identity.png) ```json { "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)" } ``` 4. Paste it into the Mappers section of the DSL & Bender Playground ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/600925610b9563e0120279e4684a8c6621dff71dea8311b2b8fa6ef81c8d0b76/docs/assets/images/setup-labs/lab6b_6a21e3ea-a229-42af-bd97-98b84481bb1b_dsl_and_bender_paste_json.png) 5. Navigate to API Playground, and query a user record, then copy an instance of the user record **Note:** We’re using a single record here to mirror how Moveworks actually works. The system maps records one by one. Comparing your configuration against a single instance is the best way to preview how the data will look once it's ingested. ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/beed98f3b78daa5de97edc3dc80639ef6c5ec8be83b9d06108060b99d4456e65/docs/assets/images/setup-labs/lab6b_7acd2a14-b1a9-410c-9426-9c078510ef0e_dsl_and_bender_copy_user.png) ```json { "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://mvwrk-feb-2539-instructor-0001.lab.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": "" } } ``` 6. Copy this JSON into the Input Payload for the DSL and Mapper Playground ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/85d96596da304ea8279638ebb71dc4d2626ddf1b2299777d6e051762c32c56b1/docs/assets/images/setup-labs/lab6b_6621d010-918d-4f5c-acda-26440c3872f9_dsl_and_bender_input_mapping.png) 7. Click **`Process`** and see how the bender mapping is applied to the input payload! **Note:** To ensure your Moveworks object representation is accurate, use this iterative process during the build phase. **Always verify that fields are populating exactly as intended** by following these steps: * **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. ## ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/298eb2abf10fd1f448d363c84ed680bb7f4c7bbc2fa1e88c01dd95a1ef8793a5/docs/assets/images/setup-labs/lab6b_5180395f-2750-45cd-bee6-b7c28995f713_dsl_and_bender_process.png) ### 1.3: Leverage Moveworks DSL Architect for Creating New Bender Mappings **Note:** The Moveworks Agent Architect is an AI powered tool connected to Moveworks documentation. The DSL Architect can help you write DSL & Bender logic for all of your configurations! 1. Navigate to the[ Moveworks Agent Architect](https://marketplace.moveworks.com/chat) and select the DSL Architect ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/112da2f527ae9365aee50481d21628edcc4b2b3925261fa29d9102b0ce1b53c5/docs/assets/images/setup-labs/lab6b_00cb8328-ba81-40e6-8271-68a83f0730d1_dsl_architect_select.png) 2. Provide the DSL Architect with the input mapping and what your stated goal is, leverage the following example > 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: ```json { “calendar_integration”: { “display_value”: “Outlook”, “value”: “1” }, “country”: { “display_value”: null, “value”: “” }, “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” } } ``` 3. This will allow Agent Architect to give us an initial JSON construction for us to use in our mapping. Once it has provided it, we will want to **`copy`** the Bender JSON ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/33e64ad6c535b24b67b1538430370c71c80c5424fec4578ad6c338daa131ff23/docs/assets/images/setup-labs/lab6b_b6b2e319-e3eb-41a3-938e-b83e603678c5_dsl_architect_copy_json.png) 4. And then we can paste it into the Editor section and see how how it would transform how our user is mapped within the Moveworks User Roster! ![](https://files.buildwithfern.com/moveworks.docs.buildwithfern.com/8ab6f920ef0225a9e6c72e7517ef21eca71b55e9bb5021827c3e97876617e38c/docs/assets/images/setup-labs/lab6b_f65bd585-0e92-42f2-ac09-30a355e54ceb_image.png) *** ## ✅ 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:** * Consult the [Bender Guide on the Moveworks Help Site](https://docs.moveworks.com/agent-studio/core-platform/configuration-languages/moveworks-bender-language-reference) for a full list of available **Bender Functions** to expand your toolkit. * Leverage the [Moveworks DSL Architect](https://marketplace.moveworks.com/chat) for advise on complex bender configurations that you want to do for an instance. *** ## 🪞 3: Reflecting on This Configuration Through this guide, you’ve learned the following: * How to leverage the DSL & 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: Lab #6b **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 Name** | **Action / Value to Enter** | | --------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | **Moveworks API Key** | Generated within Moveworks Setup → Waffle Menu (HTTP Connectors) → Credentials → Create | | **API Key → Credential Name** | `any_value` | | **API Key → Credential Type** | API Key | | **Data Mapper Playground → Input Payload** | Copy the full JSON record from the code block above (Step 1.2) | | **Data Mapper Playground → Editor** | Copy the Bender mapping JSON from the code block above (Step 1.2) | | [Agent Architect](https://marketplace.moveworks.com/chat) Query | See the example prompt in the code block in Step 1.3 above |