Question

Converting Teams Webhook with payload type MessageCard to be used in Power Automate "Post to channel when a webhook request is received" workflow

Microsoft decided to deprecate Office 365 connectors. They announced the change on Jul. 3rd, 2024 and all existing connectors will stop working on Oct. 1st, 2024, a quick 3 month turnaround: https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/

We use a Teams Webhook connector to send ticketing info into a Teams channel so our support team gets notifications of a new ticket. The payload from the ticketing system looks like this:

{  
   "@context": "https://schema.org/extensions",  
   "@type": "MessageCard",  
   "themeColor": "0072C6",  
   "title": "Title text....",  
   "text": "Body test...",  
   "potentialAction": []
}

We followed the process placed in Teams to convert our Webhook to a Power Automate workflow, and we receive the following error:

Action 'Send_each_adaptive_card' failed: The execution of template action 'Send_each_adaptive_card' failed: the result of the evaluation of 'foreach' expression '@triggerOutputs()?['body']?['attachments']' is of type 'Null'. The result must be a valid array.

This is because it expects the following format:

{
    "type": "message",
    "attachments": [
        {
            "contentType": "application/vnd.microsoft.card.adaptive",
            "content": {
                "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                "type": "AdaptiveCard",
                "version": "1.0",
                "body": [
                    {
                        "type": "TextBlock",
                        "text": ""
                    }
                ]
            }
        }
    ]
}

This is an image of the workflow:

https://i.sstatic.net/6H1co2UB.png

When reviewing the workflow, it expects the following schema:

{
    "schema": {
        "type": "object",
        "properties": {
            "type": {
                "type": "string"
            },
            "attachments": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "contentType": {
                            "type": "string"
                        },
                        "content": {
                            "type": "object",
                            "properties": {
                                "$schema": {
                                    "type": "string"
                                },
                                "type": {
                                    "type": "string"
                                },
                                "version": {
                                    "type": "string"
                                },
                                "body": {
                                    "type": "array",
                                    "items": {
                                        "type": "object",
                                        "properties": {
                                            "type": {
                                                "type": "string"
                                            }
                                        },
                                        "required": [
                                            "type"
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "required": [
                        "contentType",
                        "content"
                    ]
                }
            }
        }
    }
}

And then the "Send each adaptive card" node parses the object in the following way:

{
  "type": "Foreach",
  "foreach": "@triggerOutputs()?['body']?['attachments']",
  "actions": {
    "Post_your_own_adaptive_card_as_the_Flow_bot_to_a_channel": {
      "type": "OpenApiConnection",
      "inputs": {
        "parameters": {
          "poster": "Flow bot",
          "location": "Channel",
          "body/recipient/groupId": "bf7cf33f-40a6-4621-a8db-c942c38dbe75",
          "body/recipient/channelId": "19:ceb7fa98527f44d18372571c9a3e42dc@thread.tacv2",
          "body/messageBody": "@item()?['content']"
        },
        "host": {
          "apiId": "/providers/Microsoft.PowerApps/apis/shared_teams",
          "connection": "shared_teams",
          "operationId": "PostCardToConversation"
        }
      }
    }
  },
  "runAfter": {}
}

So it is looking for the attachments array and iterating through.

I tried several changes to alter the "foreach" code and parse the MessageCard object, but none were successful. Is there a way to alter the schema or to change the foreach code to properly parse the MessageCard object?

The alternative is for us to take the MessageCard object that we are receiving from the API and convert it to the appropriate format as an object with an array of attachments. We would like to avoid doing this if possible, but it may be the best approach.

Update:

For those that are curious how to transform their payload from MessageCard to AdaptiveCard (which is what our team ended up doing to avoid trying to figure this out in the PowerAutomate workflow), our new payload looks like this now:

    {
        "type": "message",
        "attachments": [
            {
                "contentType": "application/vnd.microsoft.card.adaptive",
                "content": {
                    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                    "type": "AdaptiveCard",
                    "version": "1.0",
                    "msteams": {
                        "width": "Full"
                    },
                    "body": [
                        {
                            "type": "TextBlock",
                            "text": {Title},
                            "weight": "bolder",
                            "size": "medium",
                            "wrap": "true"
                        },
                        {
                            "type": "TextBlock",
                            "text": {Body},
                            "wrap": "true"
                        }
                    ]
                }
            }
        ]
    }
 3  658  3
1 Jan 1970

Solution

 1

I couldn't find anything out of the box to convert MessageCards to Adaptative Cards. My solution was to replace Microsoft Teams webhooks with custom webhooks on all my apps and create a template using the template designer

Then I had to make several changes to the default PowerAutomate workflow

  1. Add an extra step to parse the webhook JSON so I can pick the body sent from my application. This is what my application is sending on the webhook (built with designer):
{
    "type": "AdaptiveCard",
    "body": [
        {
            "type": "Image",
            "url": "${creator.profileImage}",
            "altText": "${creator.name}",
            "size": "Small"
        },
        {
            "type": "TextBlock",
            "size": "Medium",
            "weight": "Bolder",
            "text": "{{.Title}}"
        },
        {
            "type": "TextBlock",
            "spacing": "None",
            "text": "Created {{DATE(${{.StartedAt}},SHORT)}}",
            "isSubtle": true,
            "wrap": true
        },
        {
            "type": "TextBlock",
            "text": "${description}",
            "wrap": true,
            "color": "Attention"
        },
        {
            "type": "FactSet",
            "facts": [
                {
                    "$data": "${properties}",
                    "title": "${key}:",
                    "value": "${value}"
                }
            ]
        }
    ],
    "actions": [
        {
            "type": "Action.OpenUrl",
            "title": "Action.OpenUrl",
            "url": "${viewUrl}"
        }
    ],
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.4"
}
  1. I removed the 'for each' statement to post just one card with the parsed body as the Adaptative Card JSON, like this: Post Card in channel configuration

This is how it looks: PowerAutomate workflow

Hopefully, this will also work for you

2024-07-22
Tomas Luna