Quickstart #6: Expense Approval Ambient Agent
Quickstart #6: Expense Approval Ambient Agent
Quickstart #6: Expense Approval Ambient Agent
You’ll create a smart expense approval agent that:
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 plugin 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.
switch)batch_get_users, generate_text, create_generic_approval_requestThe plugin’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!
If you’ve already completed the Purple Suite Setup and have your connector configured, skip to Phase 1.
Follow the Purple Suite Setup guide to:
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 two dynamic inputs: approval_id and status.
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 2 formal input arguments to represent the “approval ID” and “status” 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_id argument:
Hit “Save”.
Click “Create New” again in the “Input Arguments” pop up.
Fill out the following details for your status argument:
Hit “Save” and hit the “X” icon to close this “Input Arguments” pop up.
Time to construct 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 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)
data.payload.amount < 500, call your custom action quickstart_first_last_update_approval_request to approve immediately, then return with an early_return_message and stop the flow.user_emails: [data.approver, data.requested_by] (provided by your trigger mapping).data.target_users.user_records[0].user (approver) and [1].user (requester).mw.generate_text_action (Built-in Action)
system_prompt asks the LLM to produce an approver-ready summary.usesRENDER()to pass both the **business justification** and the **raw webhook payload** (stringified via$STRINGIFY_JSON(data.payload)`).data.llm_summary_result.generated_output (the formatted approval details).mw.create_generic_approval_request (Built-in Action)
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_outputdata.approval_request_result.status indicates if the approver Approved or Denied.switch (post-decision update) (Syntax)
data.approval_request_result.status == "DENIED", call your custom action quickstart_first_last_update_approval_request with status: 'denied'.status: 'approved'.approval_id: data.payload.approval_id (from the incoming webhook),status: 'approved' | 'denied'.Define 4 formal input arguments to represent the approver, requested_by, payload, and business_justification inputs 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 approver argument:
Hit “Save”.
Click “Create New” again to the “Input Arguments” pop up.
Fill out the following details for your requested_by argument:
Click “Create New” again to the “Input Arguments” pop up.
Fill out the following details for your payload argument:
Click “Create New” again to the “Input Arguments” pop up.
Fill out the following details for your business_justification argument:
Hit “Save” and hit the “X” icon to close this “Input Arguments” pop up.
You’re ready to move on — time to create your webhook listener.
Set the following Title and Description for your listener (be sure to replace firstname and lastname with your corresponding information).

Note: Unsecured listeners are intended for testing only. For production environments, always enable signature verification to secure your webhook listener.
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.
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
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_body object. To access the data you need, you simply use dot notation to reference the keys:
parsed_body.emailparsed_body.dataThis 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.
Congrats! You are now ready to test your plugin. In the next section, you will provided with required tools to help you test it.
This section guides you through the Moveworks Purple API tool to help you test your plugin by sending webhooks to your listener.

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!
Next step: Test your plugin. See our Testing & Error Handling guide for how to test, debug, and handle errors in production.