DEV Community

Cover image for Everything you didn't know you needed to know about Power Automate Savings Calculator
david wyatt
david wyatt Subscriber

Posted on

Everything you didn't know you needed to know about Power Automate Savings Calculator

enable savings

If you have seen this card popping up in your flow details screen you may have wondered what it was, and good news Ive explained the basics here:

But that goes into how to use it, what about how it works, well if you have the strange itch to know more then this is the blog for you (you might also want to see a shrink ๐Ÿ˜‰ ).

So this blog will cover 2 main areas:

  1. How the Rules are Stored
  2. How the Savings are Viewed

1. How the Rules are Stored

Identify Storage Location

The first thing I always do in these situations is take a look at the network traffic when creating a savings rule.

create savings

As You can see in the payload, it is stored in a Dataverse table named Savings Rules.

https://{dataverseUrl}/api/v9.2/savingsrules

saving rule table

Data Structure

You can also see that we have 3 parameters:

ruledata: JSON with all of the details of the rule
starton: When the rule is valid from
workflowid: A lookup column to the workflows (aka process) table.

The first thing to call out is the starton paramater/column, and in the table you will see the endon column. And this is because rules are not edited or deleted, they start and finish. You can see this when you turn off the rule or update it, the orgional rule is given an end data and a new rule is created.

patch savings off

And this kind of makes sense as hostoric savings should not be editable, so Power Automate calculates savings like this:

Date Range 1st -31st

Rule 1: 1st-14th= savings 1
Rule 2: 14th-31st= savings 2
Savings = savings 1 + savings 2

So this means our table can get very full with entries when you play with savings, and even more interesting they are solution aware. Which is good news, but for some reason it includes all of them. So be warned first export and you might end up with mulitple saveings rules in the solution. Good news you can delete them from the solution.

So we know where the data is stored but what about the actually savings data, well its structured like this:

{
  "time":{
    "valueInSeconds":600,
    "frequency":"run"
  },
  "money":{
    "rate":12
  }
}
Enter fullscreen mode Exit fullscreen mode

Time Key
time/frequency = run/hour/day/week

Money Key
money/frequence = hour/day/week (as per run there is no frequency)

The keys are only in the json object if they have been set, so if you set the money-saving rule to off there will be no money key.
Additionally if you set to 'Calculate money savings with user-defined baseline' then a frequency key is added to money.

Heres a couple of examples:

example 1

example 2

example 3

Create Rules

So we know the data is stored in Dataverse so reading and updating the data should be easy, just use the Dataverse API/Power Automate Connectors.

Below we are creating a new rule for a flow, its successful and appears in the table.
successful run

So in theory we can get a list of all of our flows, add rules to it and then do a bulk update to set the rules (great for the thousands of existing flows).

full flow

Sadly it didn't work, the rules are there, but they haven't been activated. So when you go to the flow details screen it still shows the activate savings.

I checked the network traffic and it is sending the rules, but they are not being used. Looking for more API calls I find this simple call that I think is doing the magic:

https://{environmentId}.environment.api.powerplatform.com/powerautomate/savings/type/cloudflow/target/{flowId}?api-version=1

Note this is the PowerPlatform environment id, which removes the - and adds a . for the last 2 didgits, see The 4 API's of the Power Platform for more info.

My guess is that there is some sort cron job/schedule task that runs to calculate savings, and the rule needs to be registered there, but thats a total guess and I really have no idea.

I tried using the HTTP with Microsoft Entra ID (preauthorized) to call the API but it kept failing.

entra id

So sadly that means for now no creation of new rules or updating (except for turning them off as that does work). Hopefully this API will be enabled so that we can do bulk updates, as its not only useful for legacy flows but for org updates like average rate of pay or increased volumes.

2. How the Savings are Viewed

We know where the rules are stored but how do we see the savings generated without going into the UI (ie getting the data into Power BI).

Back to the Network inspector and I identified that the savings were coming from another Dataverse table, the Flow Aggregations.

https://{dataverseUrl}/api/v9.2/flowaggregations

table schemas

But when you look in the table you will see no data available. So it looks like this isn't a standard data table but more of a calculation table (again no idea, just a wild guess that is probably/definitely wrong). So It appears that you send a request and it does some calculations across multiple tables and returns the data from those tables (not from itself, very clever ๐Ÿ˜Ž).

The data is calculated using a FetchXml query, example below

<fetch version="1.0" mapping="logical" count="5000" aggregate="true">
    <entity name="flowaggregation">
        <attribute name="aggregationvalue" alias="sum" aggregate="sum"/>
        <attribute name="workflowid" alias="flowId" groupby="true"/>
        <attribute name="aggregationtype" alias="aggregationType" groupby="true"/>
        <attribute name="timestart" alias="day" groupby="true" dategrouping="day"/>
        <filter type="and">
            <condition attribute="timestart" operator="ge" value="2025-07-23T10:30:00.000Z"/>
            <condition attribute="aggregationtype" operator="in">
                <value>**RoiTime**</value>
            </condition>
        </filter>
    </entity>
<
Enter fullscreen mode Exit fullscreen mode

We can see some key infor in there:

  • Everything is Groupby
  • Max 5000 records
  • Sum RoiTime
  • with filters
    • name="workflowid" (provided in the
    • name="timestart" (day,month,year)

The query is sent twice, one for time and one for cost:

<fetch version="1.0" mapping="logical" count="5000" aggregate="true">
    <entity name="flowaggregation">
        <attribute name="aggregationvalue" alias="sum" aggregate="sum"/>
        <attribute name="workflowid" alias="flowId" groupby="true"/>
        <attribute name="aggregationtype" alias="aggregationType" groupby="true"/>
        <attribute name="timestart" alias="day" groupby="true" dategrouping="day"/>
        <filter type="and">
            <condition attribute="timestart" operator="ge" value="2025-07-23T10:30:00.000Z"/>
            <condition attribute="aggregationtype" operator="in">
                <value>**RoiCost**</value>
            </condition>
        </filter>
    </entity>
</fetch>
Enter fullscreen mode Exit fullscreen mode

You get the following response

{
    "@odata.context": "https://{datverseUrl}/api/data/v9.2/$metadata#flowaggregations",
    "value": -[
       -{
            "sum": 5,
            "flowId": "{flowId}",
            "aggregationType": "RoiTime",
            "day": 30,
            "month": 7,
            "year": 2025
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

aggregationType: "RoiCost" for cost

This means if you want to track trends you will either have to do API call per day or run a schedule and store it somewhere (with the good news that the start/endon setup meaning the data could neve get miss-aligned).


As you can see the savings is baked into the platform in a more, how to say this, creative approach. So it's not as simple as a table for rules and table for savings, but requires random api's and rollup queries.

ย 
๐Ÿ˜Ž Subscribe to David Wyatt

Top comments (2)

Collapse
 
balagmadhu profile image
Bala Madhusoodhanan

Amazing explaination !!! .. Thanks @wyattdave

Collapse
 
scoperesearch profile image
Scope Research

Thanks