#PowerPlatformTip 177: 'See What Actually Changed Between SharePoint Versions with Power Automate'
TL;DR: Call
_api/web/lists/getbytitle('List')/items(ID)/versionswith Send an HTTP request to SharePoint. It returns the field values for each version. Compare the current version against the previous one for the columns you care about to get what changed, old value → new value.
When an item or file is edited in SharePoint, the When an item is created or modified trigger fires, but it only hands you the new state. It never tells you which columns changed or what the previous values were. The version history holds that information; you just have to read it. The /versions REST endpoint returns the full field set for every retained version, so you diff the two most recent ones yourself.
💡 Challenge
You want an audit trail like “Status changed from Draft to Approved, Amount changed from 100 to 250” whenever someone edits a list item or updates a document’s metadata. The SharePoint connector has no “get version differences” action. The modified trigger gives you only the current values, and Get changes for an item or a file (properties only) only tells you which columns changed within a time window (since a trigger window token, a version label or a date), not their old and new values.
✅ Solution
Every list item and every file with versioning enabled exposes a /versions collection through the SharePoint REST API. Each entry contains the field values as they were at that version, plus VersionLabel, Modified, IsCurrentVersion and the editor. Read that collection with Send an HTTP request to SharePoint, take the two newest entries, and compare the columns you care about to produce a before/after delta, no premium connector, no app registration.
🔧 How It’s Done
1. Trigger the flow on the change.
🔸 Use When an item is created or modified (list items) or When a file is created or modified (properties only) (document libraries). Grab the item ID.
🔸 Make sure versioning is enabled on the list/library (List settings → Versioning settings). Without it there is no history to compare.
2. Add Send an HTTP request to SharePoint to read the versions.
🔸 Site Address: your site.
🔸 Method: GET
🔸 Uri:
1
_api/web/lists/getbytitle('Contracts')/items(@{triggerBody()?['ID']})/versions
🔸 Headers:
1
Accept: application/json;odata=nometadata
🔸 The response holds the versions in value. Each entry carries VersionId (a number: 512 for version 1.0, 1024 for 2.0, and so on), VersionLabel, IsCurrentVersion and the column values under their internal names.
3. Put the two newest versions into variables.
🔸 Add a Compose named SortedVersions that sorts the versions newest first, independent of the order SharePoint returns:
1
reverse(sort(body('Send_an_HTTP_request_to_SharePoint')?['value'], 'VersionId'))
🔸 Initialize variable CurrentVersion (type Object), at the top level of the flow:
1
first(outputs('SortedVersions'))
🔸 Initialize variable PreviousVersion (type Object):
1
last(take(outputs('SortedVersions'), 2))
🔸 last(take(..., 2)) returns the second entry, or the current one if the item has only one version, so the expression never runs out of range.
🔸 Guard against first-ever versions with a Condition: only continue when length(outputs('SortedVersions')) is greater than or equal to 2. Put steps 4 and 5 into its True branch.
4. Diff the fields you care about.
🔸 For a targeted audit, compare specific columns directly. Add a Condition:
1
@not(equals(variables('CurrentVersion')?['Status'], variables('PreviousVersion')?['Status']))
🔸 If true, the value changed. Build the message with both sides:
1
Status: @{variables('PreviousVersion')?['Status']} → @{variables('CurrentVersion')?['Status']}
🔸 Add one Condition per column you want to audit, or make it generic: cloud flows have no function to list the property names of an object, so put the internal names of your audit columns into an array, for example ["Status","Amount","DueDate"], and loop over it with Apply to each. Inside the loop compare variables('CurrentVersion')?[item()] with variables('PreviousVersion')?[item()].
🔸 Use internal column names. A column created as Due Date is called DueDate or Due_x0020_Date in the version entries, depending on how it was created.
5. Do something with the delta.
🔸 Write it to an audit list, post it to Teams, or email it. You now have field name, old value and new value for every change.
🔸 For a document library the pattern is identical, getbytitle('Documents')/items(ID)/versions returns the metadata history of the file’s list item.
🎉 Result
On every edit your flow reports exactly which columns changed and their before/after values, straight from SharePoint’s own version history, using one standard HTTP call.
🌟 Key Advantages
🔸 Real old-vs-new values: unlike Get changes, you get the actual previous value, not just the column name.
🔸 No premium, no Graph app registration: Send an HTTP request to SharePoint is part of the standard SharePoint connector.
🔸 Works for items and files: same endpoint pattern for list items and document metadata.
🛠️ FAQ
1. Why not use the Get changes for an item or a file (properties only) action?
It returns information about which columns changed within a window (Since and Until as trigger window token, version label or date), not the old and new values. The /versions endpoint gives you the full value of every field at each version, so you can build a true before/after diff. Both need versioning turned on.
2. The value array only has one entry, why?
Versioning is off, or the item has just one version. Enable versioning in the list/library settings and guard your flow with the length(outputs('SortedVersions')) condition from step 3 before comparing.
3. How do I read Person, Lookup or Choice columns from a version?
Text, number and single Choice columns come back as plain values. Person and Lookup columns come back as an object with LookupId and LookupValue (Person columns also with Email). Compare LookupId, for example variables('CurrentVersion')?['Owner']?['LookupId'], and use LookupValue in the message.
4. Does this work for the file content, not just metadata?
No. This compares metadata/column versions. The content of an older file version is available via _api/web/GetFileByServerRelativeUrl('/sites/<site>/Shared Documents/<file>')/versions(<VersionId>)/$value; comparing two documents is a separate task.
🔗 Related Tips
- #PowerPlatformTip 154: Preserve Author, Editor & Dates on Copied SharePoint Files, keeping history and metadata intact when moving files.
- #PowerPlatformTip 133: SharePoint Updates with Power Automate, No Required Fields Needed, writing back only the fields you need.
- #PowerPlatformTip 58: HTTP Actions, the basics of Send an HTTP request to SharePoint.
This tip is by Marcel Lehmann, Microsoft MVP (Business Applications) and founder of the Power Platform Academy, which runs free live workshops (in German). See the next free workshop dates (in German). For companies that want this implemented for them, see KMUpower: Power Platform consulting & automation for SMEs (DACH).