Quickstart #6: Expense Approval Ambient Agent
Limited Preview: Webhook Triggers & Listener
Webhook Triggers and the Webhook Listener are currently in Limited Preview and may change without notice. Access is invite-only. Self-nomination form is here. Production use is approved but may be subject to interruptions or breaking changes.
What You’ll Build
You’ll create a smart expense approval agent that:
- Auto-approves expenses under $500
- Routes expenses $500+ to the right manager with a chat-based approval request
- Updates your expense system (via Purple API) with approved/denied
The result is a streamlined process for everyone. For expenses over $500, managers receive a simple, direct approval request right in their chat client, allowing them to take action in seconds.

While the user-facing interaction is intentionally simple, the real power is the automation happening behind the scenes. The agent processes every request from your expense system, and for the majority of expenses (those under $500), no manual action is needed at all, they are approved instantly.
Learning Objectives
- Build a Listener to receive expense webhooks
- Create a Compound Action with conditional logic (
switch) - Implement an automated approval branch for expenses under a set threshold.
- Use built-in actions:
batch_get_users,generate_text,create_generic_approval_request - Wire everything in a Plugin with input mapping
- Update the source system to reflect the final “approved” or “rejected” status.
Prerequisites
- Access to the “Agent Studio” App
- Completed Quickstart #5: Notification Ambient Agent
Architecture Overview
The agent’s logic is built around a central Compound Action that is triggered by a Listener. This Compound Action ingests data from the expense system, such as the approver, the requester, and the expense details, and then follows a conditional path based on the expense amount.
Let’s get started!
Phase 0: Generate a unique Session ID & Set up your Connector
You may be able to skip this phase if you’ve completed another Agent Studio Quickstart guide.
You can skip Phase 0 and move onto Phase 1 if:
- You have already created a
first_last_moveworks_purpleconnector, AND - You already have your unique “Session ID” on hand.
This section will walk you through how to set up your own connector to the Moveworks Purple API (which powers the Actions used in the Quickstart guides), so no need to repeat this step if you’ve done it before.
In this guide, you’ll build a Plugin that will actually fetch from and take action on a store of feature requests that’s set up just for you. In preparation for this, follow these steps
- Go to the Moveworks Purple API Tool.
- Click “Create New Session ID”. You should see sample feature requests populate below.
- Do not close the Purple API Tool
Now, you just need to set up a (reusable) connector that will allow you to seamlessly hit the necessary Actions that your Plugin will use.
-
Navigate to the App Picker in the top right corner of Agent Studio.
-
Click on “HTTP Connectors”, which will take you to another browser tab.
-
Click “Create” in the top right corner.
-
Fill out the following information for your Connector (be sure to replace “first” and “last” with your corresponding information).
-
Click “Save” on the bottom right corner.
👍 You’re now fully ready to start building. On to Phase 1 to set up your Actions!
Phase 1: Set up your “Update Approval Status” Action
Let’s set up an Action to update the status of the approval that is being provided by the source system. This action will require three dynamic inputs: approval_id, status, and session_id.
-
Navigate to a new HTTP Action.
-
Set the following title and description for your Action (be sure to replace “first” and “last” with your corresponding information).
-
Enter the details of your API:
-
Click on the “Import” icon to the right of the “TEST” button.

-
Paste the following cURL command:
-
Click “Import” (your Action should now be auto-populated with details).
-
-
Navigate to the “Connector” tab, and select your existing Moveworks Purple Connector (set up in Phase 0)

-
Define 3 formal input arguments to represent the “approval ID”, and “status”, and “session ID” inputs that this Action requires:
-
Click on the “Input Args” button near the top right corner.
-
Click “Create New” in the “Input Arguments” pop up.
-
Fill out the following details for your
approval_idargument: -
Hit “Save”.
-
Click “Create New” again in the “Input Arguments” pop up.
-
Fill out the following details for your
statusargument: -
Hit “Save”.
-
Click “Create New” again in the “Input Arguments” pop up.
-
Fill out the following details for your
session_idargument: -
Hit “Save” and hit the “X” icon to close this “Input Arguments” pop up.
-
-
Hit “Publish”
👍 Nice, your Action is all set up and ready to update approval requests!
Time to construct your Compound Action.
Phase 2: Create Your Compound Action
You will now create a compound action to handle the incoming webhook routed by the listener.
In this phase you will build a compound action with 1) approver, business_justification, requested_by, payload, session_id as input arguments, 2) three actions to resolve the users by email, create a Moveworks approval request, and update the approval in the source system, and 3) switch expressions to conditionally route the expense approval requests. Here’s a reminder of the bird’s-eye view for our Compound Action:
-
Navigate to a new “Compound Action” in the left nav and then click “Create”.

-
Set the following title and description for your Compound Action (be sure to replace “firstname” and “lastname” with your corresponding information).
-
Copy the following expression into the Compound Action Editor
Make sure to replace the action name’s with your action name!
-
Understanding the Compound Action (Guide #6)
This Compound Action routes an expense-approval flow. It can early-approve low-risk requests, then (for everything else) fetches users, summarizes the request with an LLM, creates an approval, and finally updates the source system based on the approver’s decision.
switch(early decision) (Syntax)- Purpose: Short-circuit the workflow for small requests.
- Process: If
data.payload.amount < 500, call your custom actionquickstart_first_last_update_approval_requestto approve immediately, thenreturnwith anearly_return_messageand stop the flow. - Otherwise, fall through to the default branch (do nothing here) and continue.
- mw.batch_get_users_by_email` (Built-in Action)
- Purpose: Resolve both the approver and the requester to Moveworks user objects.
- Inputs:
user_emails: [data.approver, data.requested_by](provided by your trigger mapping). - Output:
data.target_users.user_records[0].user(approver) and[1].user(requester).
mw.generate_text_action(Built-in Action)- Purpose: Create a crisp summary for the approver.
- Process:
system_promptasks the LLM to produce an approver-ready summary.- user_input
usesRENDER()to pass both the **business justification** and the **raw webhook payload** (stringified via$STRINGIFY_JSON(data.payload)`).
- Output:
data.llm_summary_result.generated_output(the formatted approval details).
mw.create_generic_approval_request(Built-in Action)- Purpose: Open an approval with the resolved participants and LLM summary.
- Inputs:
approvers:[ data.target_users.user_records[0].user ]users_requested_for:[ data.target_users.user_records[1].user ]approval_details:data.llm_summary_result.generated_output
- Output:
data.approval_request_result.statusindicates if the approver Approved or Denied.
switch(post-decision update) (Syntax)- Purpose: Sync the final decision back to your source system.
- Process:
- If
data.approval_request_result.status == "DENIED", call your custom actionquickstart_first_last_update_approval_requestwithstatus: 'denied'.
- If
- Default: Call the same custom action with
status: 'approved'. - Inputs to custom action:
approval_id: data.payload.approval_id(from the incoming webhook),status: 'approved' | 'denied',session_id: data.session_id(used for request scoping/traceability).
- Process:
- Purpose: Sync the final decision back to your source system.
-
Define 5 formal input arguments to represent the
approver,requested_by,payload,business_justification, andsession_idinputs that this Compound Action requires.-
Click on the “Input Args” button near the top right corner

-
Click “Create New” in the “Input Arguments” pop up.
-
Fill out the following details for your
approverargument: -
Hit “Save”
-
Click “Create New” again to the “Input Arguments” pop up.
-
Fill out the following details for your
requested_byargument: -
Click “Create New” again to the “Input Arguments” pop up.
-
Fill out the following details for your
payloadargument: -
Click “Create New” again to the “Input Arguments” pop up.
-
Fill out the following details for your
business_justificationargument: -
Click “Create New” again to the “Input Arguments” pop up.
-
Fill out the following details for your
session_idargument: -
Hit “Save” and hit the “X” icon to close this “Input Arguments” pop up.
-
-
Click “Publish”
👍 All done with Actions!
You’re ready to move on — time to create your webhook listener.
Phase 3: Set Up Your Webhook Listener
-
Navigate to a new Listener.
-
Click “Create”.

-
Set the following Title and Description for your listener (be sure to replace firstnameand lastname with your corresponding information).

-
Click “Copy URL” and paste the webhook URL somewhere you can get back to it quick, we will need it in future steps.
-
Click “Publish” to save your listener.
-
When prompted with a confirmation message about security, click “Publish Anyway” to proceed.

Note: Unsecured listeners are intended for testing only. For production environments, always enable signature verification to secure your webhook listener.
Phase 4: Configure and Launch Your Plugin
This section guides you through adding your Listener and Compound Action to a Plugin. A key step will be configuring the data flow, where you’ll specify exactly which fields from the webhook you want to forward to your action.
-
Navigate to a new Plugin (navigate to the library and click “Create”).

-
Set the following title and description for your Plugin (be sure to replace “first” and “last” with your corresponding information).
-
In the “Workflow Overview” section click “System” in the Trigger box.

-
Configure your system trigger to connect your Listener in the slide-out pop up with:
-
Click on the “Body” in the “Workflow Overview

-
Configure your system body to connect your compound action to the plugin
- Select Type - System body
- Select an Action - quickstart_first_last_expense_approval_ca (Select your Action)
- Input Mapping - Copy the below values
- approver: parsed_body.approver
- payload: parsed_body.data
- requested_by: parsed_body.requested_by
- session_id: parsed_body.session_id
- business_justification: parsed_body.details
Understanding the Input Mapping
When the listener receives a webhook, we expect a JSON payload structured like this:
The listener automatically parses this JSON payload into a
parsed_bodyobject. To access the data you need, you simply use dot notation to reference the keys:parsed_body.emailparsed_body.data
This method gives you the flexibility to extract only the specific data your compound action requires, even if the webhook sends a much larger payload.
Note: While this mapping is currently a manual process, we are developing an “Auto Configure” feature to streamline this setup in the future.
-
-
Click “Publish” to launch your Plugin.
👍 And just like that — you’ve finished building your Plugin, and now it’s ready to use!
Congrats! You are now ready to test your plugin. In the next section, you will provided with required tools to help you test it.
Phase 5: Testing
This section guides you through the Moveworks Purple API tool to help you test your plugin by sending webhooks to your listener.
-
Go back to the tab where your Moveworks Purple API Tool is open
-
Click on the Webhooks Tab

-
Configure the field values with your listener information
-
Click on the Approvals Tab
-
Fill out the Approval Form with your information (Make sure to edit the approver and requested by fields)
-
Click on Generate Approval
- You will see an approval being generated in the system for your session ID with the details you entered
-
Click on Generate Webhook Payload
- A payload will be generated for your upcoming webhook
- Make sure to tinker with the
amountfield to test different flows of your plugin.
- A payload will be generated for your upcoming webhook
-
Click on Trigger Webhook
👍 Success! Check the Approvals
Excellent work! You have successfully tested your plugin. Depending on the amount you set, your approval request may have gotten automatically approved or you may have gotten an approval request! You can click on the Refresh Approvals button in the Purple API Tool to see the status updates on the approvals!
