Are you looking for a simple and extensible no-code solution to do approvals in PowerApps? Perhaps you have built automation within PowerAutomate and are looking to provide a mechanism to “gate”, or provide a way to confirm your process prior to it executing. Or, you could be using quoting within Dynamics Customer Engagement and want to have your Sales manager review and approve quotes before they are sent to a customer. In any of these scenarios, you have come to the right place.! In this article, I will show you how to create your own custom approvals using PowerAutomate/Flows, Teams, and AdaptiveCards.Â
But first, let’s explore what Adaptive Cards are.Â
To summarize, Adaptive Cards allow you to embed small custom UI elements within a web application (or any application that can render html such as Outlook or Teams) to provide additional information, or in the case of approvals, interactivity. In the following scenario, we will build a simple model within DataVerse to store our approval activities and then build an Adaptive Card which we will expose within Microsoft teams which will notify users when they have approvals that are pending.Â
I will start by creating a custom approval activity in PowerApps. It can be customized with additional attributes as needed. For this blog post, I will keep it simple.Â
Next, let’s create a Flow. I will use the trigger when a record is created, updated, or deleted. I will get the approval request record with the details of From and To and the regarding record. This information will later be used in the adaptive card and Teams.Â
Now, I will initialize some variables that will hold the values to be filled in the adaptive card.Â
Now, I need to set the variables I initialized in the previous step with the From and to values. Â
In the first two steps, I am extracting information from the activity party, setting the formatted values in Name and setting the schema name and id in the second.Â
Since we need the e-mail address, we will first have to call  the Metadata Service and get the correct pluralized EntitySetName.Â
Next, I am getting the record’s e-mail address based on if it was from a system user or a queue.Â
Finally, I am updating the From e-mail.Â
I will repeat the same steps for the recipient:Â
Now that I have all my information, I will use Post an Adaptive Card to a Teams user and wait for a response action.Â
For the message field, build your adaptive card Designer | Adaptive Cards and copy card payload and insert it. I am entering the information from my variables.Â
I’ve used Expense Report as a starting point https://adaptivecards.io/samples/ExpenseReport.html. Once opened in the desginer, switch the host app to Teams Dark mode. To keep things simple for this scenario, I’ve customized it as follows:Â
{Â
   “type”: “AdaptiveCard”,Â
   “body”: [Â
       {Â
           “type”: “Container”,Â
           “style”: “emphasis”,Â
           “items”: [Â
               {Â
                   “type”: “ColumnSet”,Â
                   “columns”: [Â
                       {Â
                           “type”: “Column”,Â
                           “items”: [Â
                               {Â
                                   “type”: “TextBlock”,Â
                                   “size”: “Large”,Â
                                   “weight”: “Bolder”,Â
                                   “text”: “**EXPENSE APPROVAL**”,Â
                                   “wrap”: true,Â
                                   “style”: “heading”Â
                               }Â
                           ],Â
                           “width”: “stretch”Â
                       },Â
                       {Â
                           “type”: “Column”,Â
                           “items”: [Â
                               {Â
                                   “type”: “Image”,Â
                                   “url”: “${status_url}”,Â
                                   “altText”: “${status}”,Â
                                   “height”: “30px”Â
                               }Â
                           ],Â
                           “width”: “auto”Â
                       }Â
                   ]Â
               }Â
           ],Â
           “bleed”: trueÂ
       },Â
       {Â
           “type”: “Container”,Â
           “items”: [Â
               {Â
                   “type”: “ColumnSet”,Â
                   “columns”: [Â
                       {Â
                           “type”: “Column”,Â
                           “items”: [Â
                               {Â
                                   “type”: “TextBlock”,Â
                                   “size”: “ExtraLarge”,Â
                                   “text”: “${purpose}”,Â
                                   “wrap”: true,Â
                                   “style”: “heading”Â
                               }Â
                           ],Â
                           “width”: “stretch”Â
                       },Â
                       {Â
                           “type”: “Column”,Â
                           “width”: “auto”Â
                       }Â
                   ]Â
               },Â
               {Â
                   “type”: “TextBlock”,Â
                   “spacing”: “Small”,Â
                   “size”: “Small”,Â
                   “weight”: “Bolder”,Â
                   “text”: “[${code}](https://adaptivecards.io)”,Â
                   “wrap”: trueÂ
               },Â
               {Â
                   “type”: “FactSet”,Â
                   “spacing”: “Large”,Â
                   “facts”: [Â
                       {Â
                           “title”: “Submitted By”,Â
                           “value”: “**${created_by_name}** ${creater_email}”Â
                       },Â
                       {Â
                           “title”: “Duration”,Â
                           “value”: “${formatTicks(min(select(expenses, x, int(x.created_by))), ‘yyyy-MM-dd’)} – ${formatTicks(max(select(expenses, x, int(x.created_by))), ‘yyyy-MM-dd’)}”Â
                       },Â
                       {Â
                           “title”: “Submitted On”,Â
                           “value”: “${formatDateTime(submitted_date, ‘yyyy-MM-dd’)}”Â
                       },Â
                       {Â
                           “title”: “Reimbursable Amount”,Â
                           “value”: “$${formatNumber(sum(select(expenses, x, if(x.is_reimbursable, x.total, 0))), 2)}”Â
                       },Â
                       {Â
                           “title”: “Awaiting approval from”,Â
                           “value”: “**${approver}** ${approver_email}”Â
                       },Â
                       {Â
                           “title”: “Submitted to”,Â
                           “value”: “**${other_submitter}**  ${other_submitter_email}”Â
                       }Â
                   ]Â
               }Â
           ]Â
       },Â
       {Â
           “type”: “ColumnSet”,Â
           “spacing”: “Large”,Â
           “separator”: true,Â
           “columns”: [Â
               {Â
                   “type”: “Column”,Â
                   “items”: [Â
                       {Â
                           “type”: “TextBlock”,Â
                           “horizontalAlignment”: “Right”,Â
                           “text”: “Total Expense Amount t”,Â
                           “wrap”: trueÂ
                       },Â
                       {Â
                           “type”: “TextBlock”,Â
                           “horizontalAlignment”: “Right”,Â
                           “text”: “Non-reimbursable Amount”,Â
                           “wrap”: trueÂ
                       },Â
                       {Â
                           “type”: “TextBlock”,Â
                           “horizontalAlignment”: “Right”,Â
                           “text”: “Advance Amount”,Â
                           “wrap”: trueÂ
                       }Â
                   ],Â
                   “width”: “stretch”Â
               },Â
               {Â
                   “type”: “Column”,Â
                   “items”: [Â
                       {Â
                           “type”: “TextBlock”,Â
                           “text”: “$${formatNumber(sum(select(expenses, x, x.total)), 2)}”,Â
                           “wrap”: trueÂ
                       },Â
                       {Â
                           “type”: “TextBlock”,Â
                           “text”: “(-) $${formatNumber(sum(select(expenses, x, if(x.is_reimbursable, 0, x.total))), 2)} t”,Â
                           “wrap”: trueÂ
                       },Â
                       {Â
                           “type”: “TextBlock”,Â
                           “text”: “(-) 0.00 t”,Â
                           “wrap”: trueÂ
                       }Â
                   ],Â
                   “width”: “auto”Â
               },Â
               {Â
                   “type”: “Column”,Â
                   “width”: “auto”Â
               }Â
           ]Â
       },Â
       {Â
           “type”: “Container”,Â
           “style”: “emphasis”,Â
           “items”: [Â
               {Â
                   “type”: “ColumnSet”,Â
                   “columns”: [Â
                       {Â
                           “type”: “Column”,Â
                           “items”: [Â
                               {Â
                                   “type”: “TextBlock”,Â
                                   “horizontalAlignment”: “Right”,Â
                                   “text”: “Amount to be Reimbursed”,Â
                                   “wrap”: trueÂ
                               }Â
                           ],Â
                           “width”: “stretch”Â
                       },Â
                       {Â
                           “type”: “Column”,Â
                           “items”: [Â
                               {Â
                                   “type”: “TextBlock”,Â
                                   “weight”: “Bolder”,Â
                                   “text”: “$${formatNumber(sum(select(expenses, x, if(x.is_reimbursable, x.total, 0))), 2)}”,Â
                                   “wrap”: trueÂ
                               }Â
                           ],Â
                           “width”: “auto”Â
                       },Â
                       {Â
                           “type”: “Column”,Â
                           “width”: “auto”Â
                       }Â
                   ]Â
               }Â
           ],Â
           “bleed”: trueÂ
       },Â
       {Â
           “type”: “ColumnSet”,Â
           “columns”: [Â
               {Â
                   “type”: “Column”,Â
                   “verticalContentAlignment”: “Center”,Â
                   “items”: [Â
                       {Â
                           “type”: “TextBlock”,Â
                           “id”: “showHistory”,Â
                           “horizontalAlignment”: “Right”,Â
                           “color”: “Accent”,Â
                           “text”: “Show history”,Â
                           “wrap”: trueÂ
                       },Â
                       {Â
                           “type”: “TextBlock”,Â
                           “id”: “hideHistory”,Â
                           “horizontalAlignment”: “Right”,Â
                           “color”: “Accent”,Â
                           “text”: “Hide history”,Â
                           “wrap”: true,Â
                           “isVisible”: falseÂ
                       }Â
                   ],Â
                   “width”: 1Â
               }Â
           ]Â
       },Â
       {Â
           “type”: “Container”,Â
           “id”: “cardContent4”,Â
           “isVisible”: false,Â
           “items”: [Â
               {Â
                   “type”: “Container”,Â
                   “items”: [Â
                       {Â
                           “type”: “TextBlock”,Â
                           “text”: “* Expense submitted by **${created_by_name}** on {{DATE(${formatDateTime(created_date, ‘yyyy-MM-ddTHH:mm:ssZ’)}, SHORT)}}”,Â
                           “isSubtle”: true,Â
                           “wrap”: trueÂ
                       },Â
                       {Â
                           “type”: “TextBlock”,Â
                           “text”: “* Expense ${expenses[0].status} by **${expenses[0].approver}** on {{DATE(${formatDateTime(approval_date, ‘yyyy-MM-ddTHH:mm:ssZ’)}, SHORT)}}”,Â
                           “isSubtle”: true,Â
                           “wrap”: trueÂ
                       }Â
                   ]Â
               }Â
           ]Â
       },Â
       {Â
           “type”: “Container”Â
       }Â
   ],Â
   “$schema”: “http://adaptivecards.io/schemas/adaptive-card.json“,Â
   “version”: “1.5”,Â
   “fallbackText”: “This card requires Adaptive Cards v1.2 support to be rendered properly.”Â
}Â
Make sure to replace sample values with expressions from PowerAutomate variables of data from Approval Request.
Lastly, we must update the approval request in PowerApps. Once we get the response back from Teams action, I am using the Update a record action and updating the approval activity with the appropriate Activity Status and Status Reason.Â
Here is how the run looks. Â
And there you have it. I hope this blog post got your creative juices flowing and showed you the power of PowerApps, PowerAutomate, Teams, and AdaptiveCards.Â