What this automates
Expense review is a compliance check pretending to be a judgment call. Someone in finance opens each report, squints at line items, and compares them against a policy document they mostly know by heart. The overwhelming majority of reports are fine — and every one of them costs the same review minutes as the genuinely questionable ones.
This blueprint splits the work the way it should be split: machines check every line against the written policy, humans decide only the lines the machine flagged. It’s the intermediate blueprint because it chains two different AI nodes — a prompt node for extraction, an agent node for judgment — and that division of labor is the lesson worth learning here.
The design
| Step | Node | What it does |
|---|---|---|
| 1 | Submission trigger | Fires when an expense report is submitted — Dataverse row, SharePoint list item, or your expense system’s connector |
| 2 | Prompt node — extract line items | Normalizes the messy submission into a clean list: date, vendor, category, amount, attendees, notes |
| 3 | Agent node (the brain) | Checks each line against the travel-policy SharePoint; returns per-line {compliant, reason} — see below |
| 4 | Condition — every line compliant? | Branches on the structured output |
| 5a | Auto-approve + notify AP | All-compliant path: marks approved, posts the summary to the AP channel/queue |
| 5b | Approvals — route exceptions | Any flagged line: creates an Approval for finance with the agent’s per-line reasoning in the request body |
Why two AI nodes instead of one? The prompt node is the right tool for extraction — a single AI call with output shaping, cheap and deterministic-ish. The agent node is the right tool for the policy check, because it needs knowledge grounding. One agent doing both jobs does both worse and makes failures impossible to localize. With two nodes, node-level testing tells you immediately whether a bad result was bad extraction or bad judgment.
The agent node, configured
Inline agent, Add panel → Agent. Knowledge: the SharePoint site holding your travel and expense policy — this is non-negotiable; without it the agent enforces a generic policy from its training data, which is worse than no automation. No tools, Work IQ off. Output: custom JSON schema — an array of {line_id, compliant (boolean), reason (string)} plus a top-level all_compliant boolean for the branch.
Instructions for the node:
You review expense line items against the company travel and expense
policy in your knowledge source. The extracted line items are below as
dynamic content.
For EACH line, return:
- line_id: copied from input
- compliant: true only if the line clearly satisfies the written policy
- reason: one sentence. If compliant, cite the policy rule it satisfies.
If not, cite the specific rule it appears to violate and what is
missing (receipt, attendee list, pre-approval, over-limit amount).
Rules:
- Judge ONLY against the written policy. If the policy is silent or
ambiguous on a line, mark compliant: false with reason "Policy unclear
— needs human review." Ambiguity is an exception, not a pass.
- You flag; you never decline. Write reasons as findings for a reviewer,
not verdicts to the employee.
- Set all_compliant true only if every single line is compliant.
Line items: [ExtractedLines token]
Submitter: [Submitter token]
Report total: [Total token]
The ambiguity rule is the one people get wrong. The lazy default is “unclear = probably fine,” which quietly converts your agent from a policy checker into a rubber stamp. Unclear goes to a human — that’s the entire safety model.
Build it (a couple of hours)
- Flows → New workflow, trigger on your expense submission source.
- Add the Prompt node for extraction: feed it the raw submission, shape the output as a structured list of line items. Test it with your three ugliest real reports first — extraction is where messy reality bites.
- Add the Agent node: attach the policy SharePoint site as knowledge, set the JSON schema, paste the instructions.
- Node-level test the agent with known-good and known-bad reports, plus one ambiguous one. The ambiguous one must come back flagged. If it doesn’t, fix the instructions before going further.
- Build the branch:
all_complianttrue → approve and post to AP; false → create an Approvals request for the finance reviewer with each flagged line and its reason in the body. - Run in shadow mode for two weeks — workflow checks, humans still review everything — and measure agreement before letting the auto-approve path go live.
Cost and governance notes
- The question everyone asks first: can the workflow reject an expense? No — and keep it that way. The agent flags, finance decides. The auto path only ever approves reports where every line cleared the written policy; nothing in this design declines anything. A flagged line is a routed line, not a rejected one. That distinction is what makes this defensible to auditors, works councils, and the employee whose hotel bill got questioned.
- Credits: two AI calls per report — prompt node is cheap, agent node is the cost. Run the agent usage estimator against monthly report volume; the math almost always wins against reviewer hours, but show the math.
- Policy drift: the agent is only as current as the SharePoint policy. Make finance own that page and re-run your test reports after every policy edit.
- Permissions: the agent node runs as the triggering user; for event triggers that’s effectively your designated account — it needs read access to the policy site, and your DLP policies must permit the agent node in this environment.
Variants worth building once this works
- Threshold tiering: auto-approve only below a euro/dollar cap even when fully compliant; everything above goes to Approvals regardless — a comfortable first rollout posture.
- Submitter feedback loop: on the exception path, also send the submitter a friendly note listing what’s missing, so half the flags fix themselves before finance ever looks.
- Quarterly audit pack: a scheduled workflow that compiles every flagged-then-approved exception into one summary for the controller — the audit trail this automation generates is half its value.