Skip to main content

📢 Update -Building low code/no code approval workflows for your team using Microsoft Teams, SharePoint & Flow

As the fastest growing business app in the history of our company, Microsoft Teams is gaining strong foothold in Office 365 enterprise users base. Millions of enterprise employees are now starting their day in Teams, living their day in Teams and wrapping up their day in Teams. One of the core value drivers within this productivity workspace is it’s extensible and customizable platform offering – essentially bringing modern SaaS app experiences within the scaffolding of the product itself. Thanks to 250+ apps on the public app store and countless more on private, organization-specific app catalogs inside Teams, it’s natural for a typical user to expect her organizational tools and most importantly, common workflows will be accessible inside Microsoft Teams itself.

Broadly speaking, there are 2 methods of surfacing your organizational workflows inside Microsoft Teams:

  1. Code from scratch (CFS) – This is where you go all in and get your enterprise developers to write a web application complete with backend database, a frontend experience custom-built for Teams and APIs to read/write information for user’s view/action

  2. No code / low code (LCNC) – This is where you keep it lightweight and quick and get literally anyone eg: administrators, business owners or in general, people who are not full-time software developers to build and configure functional workflows inside Teams.

LCNC democratizes creating and surfacing workflows as “apps” inside Teams – enabling (a) a modern end-user experience in addition to (b) low cost and time of workflow development. During our evangelism and consultative work with some of the top enterprise customers using Microsoft Teams today, approvals is one such kind of workflow that seems to exist universally.

The Goal

Today, let’s see how you can build a simple approval workflow the LCNC way using just SharePoint Online + Microsoft Flow + Microsoft Teams, and nothing else - no web browser, no email, no Microsoft Flow mobile application etc. participating in the mix. The entire workflow will begin and end for all participants within Microsoft Teams itself – resulting in minimum context switching and maximum productivity.

The Problem Statement

Let’s imagine that you manage the Travel Desk for your company. Your team arranges home drops via company-owned shuttle service to employees staying late in the evening beyond regular transport hours. You want to surface a shuttle request workflow within Microsoft Teams whenever a new drop request is made by an employee. One of your Travel Desk team staff needs to look into the request, validate against policy and then approve the same. The requester employee must get notified with the status of their request on Teams itself.


Setting up the Components

  1. SharePoint portal: We’re using a simple, modern SharePoint site public to the entire org titled ‘Vishrut's Workgroup’ for this blog post.
  2. SharePoint list: Within the SharePoint site, a simple, public list titled ‘Cab Request’ has been created. All requests from employees will be collected and actioned upon in this list.



  3. Employee team in Microsoft Teams: A team titled Vishrut’s Workgroup has been created by teamify-ing the SharePoint site created above. This will make it easier to pin the list as a tab since the list is part of the team’s corresponding SharePoint in backend. 

  4. Pin the list as a Channel Tab: Add the SharePoint list as a channel tab in the Staying Late channel of the Vishrut’s Workgroup In real-world, you can expose the list as a SPFx web part inside any Teams channel as a tab.



    Employees staying late in Vishrut’s Workgroup now can use the SharePoint tab in the Staying Late channel to request for shuttle drop using the ‘New’ action.

  5. Travel Desk team in Microsoft Teams: The entire travel desk team is part of the Travel Desk team within Microsoft Teams. Those who can approve employee shuttle drop requests follow the Cab Requests channel to get notified.

Designing the Approval Flow

This is how you – as the manager of the Travel Desk – design a simple approval flow for approvers on your team:



Notifying about a New Approval Request

Here’s how you set it up using connectors in Microsoft Teams and trigger/action in Microsoft Flow:

  1. Add an Incoming Webhook connector to the Cab Request channel in the Travel Desk team. Configure the connector as follows and obtain the webhook URL provided in the dialog. Copy the webhook to the clipboard and save it. You'll need the webhook URL for sending information to Microsoft Teams.



    Once the Incoming Webhook connector is successfully setup, you’ll see the following notification in the channel.



  2. In Microsoft Flow, setup a new “When an item is created -> HTTP” flow i.e. choosing to invoke a REST API whenever an item is created in a given SharePoint list (Cab Request in this case). Use the webhook URL obtained in the previous step in the HTTP action’s URI field. By doing so, you’re piping the request raised in SharePoint list into the Cab Request channel.


    Now, let’s compose the connector card in message card format (which Microsoft Teams supports). While designing the connector card, you can head over to the Card Playground which allows you to see what your card will look like as you edit the associated JSON payload. The card payload goes in the Body of the HTTP action on the Flow page.

    You can add dynamic content available from the SharePoint list in previous step (in context) to show up on the connector card by inserting them directly into the JSON payload in the Body compose box. A reference JSON payload in available on GitHub to get you started. Save the Flow to commit your trigger/action.



  3. Test out the Flow you just created by adding a new item in the SharePoint list from the channel tab in Staying Late channel as follows:


  4. You should see a rich Connector card appear in the Cab Requests channel as follows:


    This is powerful since your Travel Desk team now has the request – from an external system - appearing directly within Microsoft Teams where they can collaborate around the same. For eg: you can @mention a specific team member of yours to check whether the requesting employee’s can avail the shuttle drop facility by company policy or not.


Taking Action on an Approval Request

Notice the Approve and Reject action buttons on the connector card posted into the channel. Your approver can decide to action on the request and even add their comments. The JSON payload for the card you specified in the Body field of the HTTP action contains the actions. Here’s the snippet that defines what should happen when the user chooses the action Approve.



The most important piece in the JSON code above is the “target” value specified which defines the URL endpoint of the service that receives and then acts on the action made by the user (your approver in this case). At a high level. this is what happens when the approver hits Submit on the card:



This means, the target URL is basically an Internet-reachable endpoint which can receive action data. So how do you obtain the target URL for your approval flow?

Obtaining the Target HTTP URL

This is the essence of our low code / no code solution. Usually, target URLs need a web service to be run and exposed on the Internet. However, Microsoft Flow’s trigger “Request — When a HTTP request is received” does exactly this. The trigger generates a HTTP POST URL, which can trigger a Flow whenever an incoming API call hits this target. Therefore, we setup another Flow with this trigger.



We will also need a JSON schema defining the format of the request that will hit this HTTP target endpoint. To simplify schema creation, you can use one of many schema generators available on the web for eg: A reference schema for the connector card is available on GitHub to get you started.

The HTTP POST URL will get generated once you Save the Flow.



This URL needs to be picked up and inserted as the target URL in the Connector card’s JSON Body field defined in the first Flow you’ve setup. Note that the same target URL is specified in case of both actions – Approve and Reject.


Only the Boolean values contained in the ‘approved’ key as part of the HttpPOST body section differentiates between either decision. In the section titled “Updating the SharePoint list item” below, we use the Boolean to populate Request Status Value field in the SharePoint list item.


Updating the SharePoint list item with action data

The subsequent actions for this Flow look like the following:



Basically, the remaining steps of the Flow deal with receiving the HTTP payload coming to the target URL, parsing the same, extracting required information such as the action taken, comments and the identify of the person who’s taken the action in order to store it in the same SharePoint list. This is how it is achieved:


  1. Parsing the HTTP Header: Using the Parse JSON action available in Flow, the HTTP Header (dynamic value from previous step) is parsed. A reference schema for the HTTP request header is available on GitHub to get you started.



  2. Parsing the Action-Authorization field in the request header: The Action-Authorization field in the header for actionable messages contains the bearer token which contains the identify of the user who’s taken the action. The token is obtained using a split expression “split(body('Parse_JSON')?['Action-Authorization'],'.')[1]” in Flow. We’re splitting the bearer token at ‘.’, placing the contents into an array and picking the 2nd element from the array to obtain the JWT token which includes the Azure AD identity of the Office 365 user who took the action. If you wish to decode a JWT token to see it’s fields, use the A reference schema for the JWT token is available on GitHub to get you started.



  3. Obtain identify of the user performing the action: If you go through the Connector documentation, you’ll see that the ‘sub’ parameter contains the Azure AD object ID of the user who took the action. We use an existing User connector in Flow that makes is easier to get user information basis this object ID.



  4. Updating the SharePoint list item: Now that we’ve all the information extracted from the action taken by the Travel Desk team member who reviewed this shuttle request, it’s time to update the SharePoint list item with the required info i.e. the decision/status of the request, the comments of the reviewer and the identify of the reviewer.

    This is achieved by first obtaining the corresponding SharePoint list item using the ID passed into the incoming HTTP request. You may recall that we’d posted the ID specifically in the action body when composing the Connector card JSON itself. The ID passed plays the role of stitching two completely separate Flows you’ve set up. Using the ID passed in the first Flow, you can update the same list item in second Flow.

    You can now update the list item accordingly. The Request Status Value field is populated using an expression “if(triggerBody()?['approved'],'Approved','Rejected')”. Note that this expression is based on the ‘Approved’ boolean’s value from the JSON schema of this Flow’s trigger (When a HTTP request is received). The Comments field is simply populated from the corresponding value in the incoming HTTP request.


Closing the Loop: Feedback in Channel

It is imperative to give both the reviewer and the requesting employee feedback once the approval is executed to it’s logical conclusion.

  1. Feedback for the reviewer: The reviewer and the rest of your Travel Desk team needs to know who’s reviewed a particular shuttle drop request and the outcome. That is why the final step of the 2nd Flow uses the HTTP Response action as follows:

    As per the Connector documentation, you can refresh the Connector card in the Cab Request channel once the reviewer takes action to fully update the card on the fly. The approved card captured the status of the request, the reviewer (in this case I’ve approved my own request!) and a reply message. Notice the updated card does not contain the action buttons. This is very powerful to ensure no other Travel Desk team member can take further action on this request.

    To refresh a card as a result of an HttpPOST action, the JSON payload of the new card is included in the Body section of HTTP Response. You’ll also need to add CARD-UPDATE-IN-BODY: true HTTP header to the response. The reply to show in the channel conversation is returned in the CARD-ACTION-STATUS header in HTTP Response.

    The refreshed Connector card also uses dynamic values thanks to Flow to compose the content. A reference schema for the HTTP Response’s Body section containing the refreshed Connector card is available on GitHub to get you started.


  2. Notifying the Employee who requested the shuttle drop: The employee can be notified over email instantly using Send email action that Flow provides.

    The requesting employee receives an email as follows:


We hope this hands-on blog post has enabled you to set up your first LCNC approval workflow in Microsoft Teams using just SharePoint Online + Microsoft Flow, Connectors in channels and nothing else - no web browser, no email, no Microsoft Flow mobile application etc. Happy approving!

Special thanks to Wajeed Hanif Shaik - our Microsoft Teams platform developer support engineer who was able to get this LCNC approval workflow up and running in a matter of a few hours!

Source Reference : Microsoft Teams Tech Community


Popular posts from this blog

Turn off/ Hide Details panel/ Information Panel on modern SharePoint lists

Not always we require to show changes done by other which is a mandatory feature in SharePoint online.  What is details pane (aka. Information Pane)? Detail pane/ Information shows information regarding the document if you selected a one or its showing recent changes within a list or library. Follow link to Microsoft documentation about details pane. Bad news: Until Microsoft listen to User Voice , there is no straightforward way to enable disable this even you don't want. Good news: We could write a SharePoint framework extension to hack styles until Microsoft give us a permanent solution. How? I found this sample project (Inject CSS into modern SharePoint pages with React) which could reuse to our purpose. Thanks to Hugo for saving my time.  Steps to awesomeness:  Clone the project Resolve dependencies >  npm i Bundle >  gulp bundle --ship Package >  gulp package-solution --ship Upload package into SharePoint App catalog  

📢 Update -Top 10 Microsoft Teams questions from customers around the world

Over the last 4 months, we’ve traveled to 9 countries on Microsoft Ignite | The Tour meeting and speaking with users like you about Microsoft Teams. The insights and feedback at every location has been invaluable — Thank you. During our travels, there have been 10 questions that have repeatedly surfaced. Below are all of the questions — including the answers too, of course!   Can you restrict access to a specific channel in a team? What are best practices for governance, specifically around team creation, naming, and retention? Can I add guests to my team? If so, how? How does external access/federation work? How is this different to guest access? What functionalities do I get in a hybrid environment? Is Teams available for on-prem environments? How do I configure Direct Routing in Microsoft Teams? Why should I move from Skype for Business to Teams? How do I make this transition? I have existing SharePoint sites that I would like to bring into Teams. Can I do that? I need t

Eliminate Duplicates in Microsoft Flow and Azure Logic Apps

There is no straight forward method or Microsoft Flow action  to eliminate values in a collection like Microsft Excel (as of March 2019). This little hack will help you to eliminate/ remove duplicates and create a collection of unique values. Sample scenario: Need to send daily summarized notification to assigned approved with pending approval items. Sample workflow: Initialize an array Iterate collection of data and append items that are not there in the filtered array Side note: This won't be an option to consider if you too concerned about the performance of the workflow but for the time being its an option to consider.