We will build a form where staff submit their automatically calculated mileage by TomTom.

For staff to be able to claim the mileage, they need to enter the start address and the destination address. We went one step further and added waypoints.

In this example, the designer of this solution will need a premium license to be able to build and use a custom connector. Users using the app will only need a standard license. More on that later.

The Get MIleage button does all the magic.

Set(
    varTomTom,
    V1TomTomPA.Run(
        Substitute(
            tiStartAddress_1.Text & "|" & Concat(
                colWaypointsUpdates,
                waypoint,
                "|"
            ) & If(
                CountRows(colWaypointsUpdates) > 0,
                "|",
                ""
            ) & tiDestinationAddress_1.Text,
            Char(10),
            " "
        ) & "~" & cbRouteType.Selected.RouteType & "~" & Text(
            DateValue8_2.SelectedDate,
            "yyyy-mm-dd"
        ) & "T" & HourValue8_2.Selected.Value & ":" & MinuteValue8_2.Selected.Value & ":" & "00" & "+" & "01:00"
    )
);
ClearCollect(
    colWaypointData,
    ForAll(Split(
        varTomTom.waypoint_data,
        ","
    ), {Result: ThisRecord.Value})
);
ClearCollect(
    colWaypointDataCount,
    {}
);
ForAll(
    colWaypointData,
    If(
        CountRows(colWaypointDataCount) <= CountRows(colWaypointsUpdates),
        Patch(
            colWaypointsUpdates,
            Last(
                FirstN(
                    colWaypointsUpdates,
                    CountRows(colWaypointDataCount)
                )
            ),
            {
                mileage: If(
                    Value(Result) = 0 && Value(
                        Last(
                            FirstN(
                                colWaypointData,
                                CountRows(colWaypointDataCount) + 1
                            )
                        ).Result
                    ) = 0,
                    Blank(),
                    Value(Result)
                )
            }
        );
        Collect(
            colWaypointDataCount,
            {}
        );
    )
);
Clear(colInvalidWaypoints);
ForAll(
    colWaypointData,
    If(
        Value(Result) = 0,
        Collect(
            colInvalidWaypoints,
            ThisRecord
        )
    );
    
);
Set(
    varMileage,
    If(
        CountRows(colInvalidWaypoints) = 0,
        (Round(
            Sum(
                colWaypointData,
                Result
            ),
            1
        )),
        0
    )
);

What you will need is two flows. One that is triggered by the Get Mileage button and a child flow with an HTTP trigger triggered by the parent flow.

This is the parent flow triggered by the Get Mileage button.
We only use one parameter passed from Power Apps as we use the title “~” symbol to split it into individual parameters. This saved us a lot of work saving and reloading the flow inside the Power Apps app should we need to add more parameters. The From and To values are required to have the pipe symbol, as this is how TomTom API needs it. Waypoints will also be separated by the pipe symbol. The From address will always be first, followed by waypoints and the string will end with a destination.

We then use the HTTP response values and send them back to Power Apps

The HTTP flow

Here, we will create our first custom connector to validate whether the search query is a valid UK postcode. Postcodes.io is Free, Open Source and based solely on Open Data. TomTom API requires coordinates to calculate routes and mileage, but it sometimes struggles to find the coordinates if we use a name. Employees claiming mileage often use postcodes to help the flow and reduce the failure rate. We use a condition to increase search accuracy.

Go to Data > Custom Connectors and click Create

No authentication required

Next, we will create a validate action

Import a new request by pasting this URL:

https://api.postcodes.io/postcodes/{postcode}/validate

So before we get to calculate the mileage, we need to find the coordinates of the From and To locations.

The Append to array variable action creates an array from From and To coordinates:

TomTom API requires locations to be separated by a colon so we now convert the array into this:
join(variables('varLocationsString'),':')
departAt is needed to calculate the mileage based on traffic conditions at the time of travel.
triggerOutputs()['body']?['departAt']

routeType is required for TomTom API to know what type of route to take when calculating the route/mileage.

Occasionally, users will try to enter addresses that either do not exist or TomTom is unable to find, which is when a more accurate address is required. TomTom API will return various errors, but I prepared some meaningful responses to end users to know what they need to correct:
So if one of those four errors is returned, the error message is passed back to Power Apps and displayed for the user to know that No valid route could be found.

If no errors are found:

The results are passed on to the parent flow and the same results is sent back to the Power Apps app.

The result mileage label in Power Apps:

(varMileage+
If(tgSupportMileage.Value && varIsSLOR && !IsBlank(SupportedPWSmiles.Selected),tiAdjustMileage.Text,
-Abs(tiAdjustMileage.Text))
 + varHome2Work) * varMilesMultification