From 4fec754867b5b99dec44db260f0fb8624ebe96d3 Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Tue, 31 Mar 2026 16:53:51 +0530 Subject: [PATCH 01/16] Update cards-actions.md --- .../cards/cards-actions.md | 1039 +++++++---------- 1 file changed, 448 insertions(+), 591 deletions(-) diff --git a/msteams-platform/task-modules-and-cards/cards/cards-actions.md b/msteams-platform/task-modules-and-cards/cards/cards-actions.md index 91d82bd4974..b853ecaab1b 100644 --- a/msteams-platform/task-modules-and-cards/cards/cards-actions.md +++ b/msteams-platform/task-modules-and-cards/cards/cards-actions.md @@ -1,546 +1,426 @@ ---- -title: Add card actions in a bot -description: Learn about card actions such as openUrl, messageBack, imBack, invoke, and signin, and Adaptive Card actions such as Action.Submit. +--- +title: Adaptive Card actions in Teams SDK +description: Learn about Adaptive Card action types such as Action.Execute, Action.OpenUrl, Action.ShowCard, and Action.ToggleVisibility, and how to handle card actions using the Teams SDK. ms.localizationpriority: medium ms.topic: conceptual -ms.date: 11/07/2024 +ms.date: 03/31/2026 --- # Card actions [!INCLUDE [adaptive-card-redirect](../../includes/adaptive-card-redirect.md)] -Cards used by bots and message extensions in Microsoft Teams support the following activity [`CardAction`](/bot-framework/dotnet/bot-builder-dotnet-add-rich-card-attachments#process-events-within-rich-cards) types: +Adaptive Cards support interactive elements through actions—buttons, links, and input submission triggers that respond to user interaction. You can use these to collect form input, trigger workflows, open URLs, and more. -> [!NOTE] -> The `CardAction` actions differ from `potentialActions` for connector cards for Microsoft 365 Groups when used from connectors. +The Teams SDK provides builder helpers and server-side handlers that simplify working with card actions. The following action types are supported: -| Type | Action | -| --- | --- | -| `openUrl` | Opens a URL in the default browser. | -| `messageBack` | Sends a message and payload to the bot from the user who selected the button or tapped the card. Sends a separate message to the chat stream. | -| `imBack`| Sends a message to the bot from the user who selected the button or tapped the card. This message from user to bot is visible to all conversation participants. | -| `invoke` | Sends a message and payload to the bot from the user who selected the button or tapped the card. This message isn't visible. | -| `signin` | Initiates OAuth flow, allowing bots to connect with secure services. | +| Action type | Use case | Description | +| --- | --- | --- | +| `Action.Execute` | Server-side processing | Sends data to your bot for processing. Best for forms and multi-step workflows. | +| `Action.Submit` | Simple data submission | Legacy action type. Prefer `Action.Execute` for new projects. | +| `Action.OpenUrl` | External navigation | Opens a URL in the user's browser. | +| `Action.ShowCard` | Progressive disclosure | Displays a nested card when selected. | +| `Action.ToggleVisibility` | UI state management | Shows or hides card elements dynamically. | > [!NOTE] -> ->* Teams does not support `CardAction` types not listed in the previous table. ->* Teams does not support the `potentialActions` property. ->* Card actions are different than [suggested actions](/azure/bot-service/bot-builder-howto-add-suggested-actions?view=azure-bot-service-4.0&tabs=javascript&preserve-view=true#suggest-action-using-button) in Bot Framework or Azure Bot Service. ->* If you are using a card action as part of a message extension, the actions do not work until the card is submitted to the channel. The actions do not work while the card is in the compose message box. - -## Action type openUrl +> For complete reference on action types, see the [Adaptive Cards documentation](https://adaptivecards.microsoft.com/?topic=Action.Execute). -`openUrl` action type specifies a URL to launch in the default browser. - -> [!NOTE] -> -> * Your bot doesn't receive any notice on which button was selected. -> * URLs don't support machine names that include numbers. For example, a hostname such as *userhostname123* isn't supported. -> * When using `Action.OpenUrl`, make sure to include the domain of the target URL in the validDomains section of your app manifest. If the domain isn’t listed, Teams displays the message **URL may lead to untrusted content**. +## Create actions with the SDK -With `openUrl`, you can create an action with the following properties: +The SDK provides builder helpers that abstract the underlying JSON. You can create actions using strongly typed classes from the `Microsoft.Teams.Cards` namespace. -| Property | Description | -| --- | --- | -| `title` | Appears as the button label. | -| `value` | This field must contain a full and properly formed URL. | +### Action.Execute -# [JSON](#tab/json) - -The following code shows an example of `openUrl` action type in JSON: - -```json -{ - "type": "openUrl", - "title": "Tabs in Teams", - "value": "https://msdn.microsoft.com/microsoft-teams/tabs" -} -``` +`Action.Execute` is the recommended action type for server-side processing. When a user selects an Execute action, the input values and any configured data are sent to your bot as a `card.action` activity. # [C#](#tab/csharp) -The following code shows an example of `openUrl` action type in C#: +The following code shows an example of an `Action.Execute` action in C#: ```csharp -var button = new CardAction() +using Microsoft.Teams.Cards; + +var action = new ExecuteAction { - Type = ActionTypes.OpenUrl, - Title = "Tabs in Teams", - Value = "https://learn.microsoft.com/microsoftteams/platform/" + Title = "Submit Feedback", + Data = new Union(new SubmitActionData + { + NonSchemaProperties = new Dictionary + { + { "action", "submit_feedback" } + } + }), + AssociatedInputs = AssociatedInputs.Auto }; ``` -# [JavaScript/Node.js](#tab/javascript) +# [JSON](#tab/json) -The following code shows an example of `openUrl` action type in JavaScript: +The following code shows an example of an `Action.Execute` action in JSON: -```javascript -CardFactory.actions([ +```json { - type: 'openUrl', - title: 'Tabs in Teams', - value: 'https://learn.microsoft.com/microsoftteams/platform/' -}]) + "type": "Action.Execute", + "title": "Submit Feedback", + "data": { + "action": "submit_feedback" + }, + "associatedInputs": "auto" +} ``` --- -## Action type messageBack - -With `messageBack`, you can create a fully customized action with the following properties: - -| Property | Description | -| --- | --- | -| `title` | Appears as the button label. | -| `displayText` | Optional. Used by the user in the chat stream when the action is performed. This text isn't sent to your bot. | -| `value` | Sent to your bot when the action is performed. You can encode context for the action, such as unique identifiers or a JSON object. | -| `text` | Sent to your bot when the action is performed. Use this property to simplify bot development. Your code can check a single top-level property to dispatch bot logic. | - -The flexibility of `messageBack` means that your code can't leave a visible user message in the history simply by not using `displayText`. - -# [JSON](#tab/json) - -The following code shows an example of `messageBack` action type in JSON: +### Action.OpenUrl -```json -{ - "buttons": [ - { - "type": "messageBack", - "title": "My MessageBack button", - "displayText": "I clicked this button", - "text": "User just clicked the MessageBack button", - "value": "{\"property\": \"propertyValue\" }" - } - ] -} -``` +`Action.OpenUrl` opens a specified URL in the user's browser. -The `value` property can be either a serialized JSON string or a JSON object. +> [!NOTE] +> When using `Action.OpenUrl`, make sure to include the domain of the target URL in the `validDomains` section of your app manifest. If the domain isn't listed, Teams displays the message **URL may lead to untrusted content**. # [C#](#tab/csharp) -The following code shows an example of `messageBack` action type in C#: +The following code shows an example of an `Action.OpenUrl` action in C#: ```csharp -var button = new CardAction() -{ - Type = ActionTypes.MessageBack, - Title = "My MessageBack button", - DisplayText = "I clicked this button", - Text = "User just clicked the MessageBack button", - Value = "{\"property\": \"propertyValue\" }" -}; -``` - -# [JavaScript/Node.js](#tab/javascript) +using Microsoft.Teams.Cards; -The following code shows an example of `messageBack` action type in JavaScript: - -```javascript -CardFactory.actions([ +var action = new OpenUrlAction("https://adaptivecards.microsoft.com") { - type: 'messageBack', - title: "My MessageBack button", - displayText: "I clicked this button", - text: "User just clicked the MessageBack button", - value: {property: "propertyValue" } -}]) + Title = "Learn More" +}; ``` ---- - -### Inbound message example - -`replyToId` contains the ID of the message that the card action came from. Use it if you want to update the message. +# [JSON](#tab/json) -The following code shows an example of inbound message: +The following code shows an example of an `Action.OpenUrl` action in JSON: ```json { - "text":"User just clicked the MessageBack button", - "value":{ - "property":"propertyValue" - }, - "type":"message", - "timestamp":"2017-06-22T22:38:47.407Z", - "id":"f:5261769396935243054", - "channelId":"msteams", - "serviceUrl":"https://smba.trafficmanager.net/amer-client-ss.msg/", - "from":{ - "id":"29:102jd210jd010icsoaeclaejcoa9ue09u", - "name":"John Smith" - }, - "conversation":{ - "id":"19:malejcou081i20ojmlcau0@thread.skype;messageid=1498171086622" - }, - "recipient":{ - "id":"28:76096e45-119f-4736-859c-6dfff54395f7", - "name":"MyBot" - }, - "entities":[ - { - "locale": "en-US", - "country": "US", - "platform": "Windows", - "timezone": "America/Los_Angeles", - "type": "clientInfo" - } - ], - "channelData":{ - "channel":{ - "id":"19:malejcou081i20ojmlcau0@thread.skype" - }, - "team":{ - "id":"19:12d021jdoijsaeoaue0u@thread.skype" - }, - "tenant":{ - "id":"bec8e231-67ad-484e-87f4-3e5438390a77" - } - }, - "replyToId": "1575667808184", + "type": "Action.OpenUrl", + "url": "https://adaptivecards.microsoft.com", + "title": "Learn More" } ``` -## Action type imBack - -The `imBack` action triggers a return message to your bot, as if the user typed it in a normal chat message. Your user and all other users in a channel can see the button response. - -With `imBack`, you can create an action with the following properties: - -| Property | Description | -| --- | --- | -| `title` | Appears as the button label. | -| `value` | This field must contain the text string used in the chat and therefore sent back to the bot. This is the message text you process in your bot to perform the desired logic. | - -> [!NOTE] -> The `value` field is a simple string. There is no support for formatting or hidden characters. +--- -# [JSON](#tab/json) +### Action sets -The following code shows an example of `imBack` action type in JSON: - -```json -{ - "type": "imBack", - "title": "More", - "value": "Show me more" -} -``` +You can group multiple actions together using `ActionSet` within an Adaptive Card: # [C#](#tab/csharp) -The following code shows an example of `imBack` action type in C#: +The following code shows an example of grouping actions in C#: ```csharp -var button = new CardAction() -{ - Type = ActionTypes.ImBack, - Title = "More", - Value = "Show me more" -}; -``` - -# [JavaScript/Node.js](#tab/javascript) +using Microsoft.Teams.Cards; -The following code shows an example of `imBack` action type in JavaScript: - -```javascript -CardFactory.actions([ +var card = new AdaptiveCard { - type: "imBack", - title: "More", - value: "Show me more" -}]) + Schema = "http://adaptivecards.io/schemas/adaptive-card.json", + Actions = new List + { + new ExecuteAction + { + Title = "Submit Feedback", + Data = new Union(new SubmitActionData + { + NonSchemaProperties = new Dictionary + { + { "action", "submit_feedback" } + } + }) + }, + new OpenUrlAction("https://adaptivecards.microsoft.com") + { + Title = "Learn More" + } + } +}; ``` ---- - -## Action type invoke - -The `invoke` action is used for invoking [dialogs (referred as task modules in TeamsJS v1.x)](~/task-modules-and-cards/task-modules/task-modules-bots.md). - -The `invoke` action contains three properties, `type`, `title`, and `value`. - -With `invoke`, you can create an action with the following properties: - -| Property | Description | -| --- | --- | -| `title` | Appears as the button label. | -| `value` | This property can contain a string, a stringified JSON object, or a JSON object. | - # [JSON](#tab/json) -The following code shows an example of `invoke` action type in JSON: +The following code shows an example of grouping actions in JSON: ```json { - "type": "invoke", - "title": "Option 1", - "value": { - "option": "opt1" + "type": "AdaptiveCard", + "version": "1.5", + "schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "actions": [ + { + "type": "Action.Execute", + "title": "Submit Feedback", + "data": { + "action": "submit_feedback" + } + }, + { + "type": "Action.OpenUrl", + "url": "https://adaptivecards.microsoft.com", + "title": "Learn More" } + ] } ``` -When a user selects the button, your bot receives the `value` object with some additional information. +--- -> [!NOTE] -> The activity type is `invoke` instead of `message` that is `activity.Type == "invoke"`. +### Raw JSON alternative -# [C#](#tab/csharp) - -The following code shows an example of `invoke` action type in C#: +If you prefer to work with raw JSON, you can deserialize it into the SDK types: ```csharp -var button = new CardAction() +var actionJson = """ { - Title = "Option 1", - Type = "invoke", - Value = "{\"option\": \"opt1\"}" -}; + "type": "Action.OpenUrl", + "url": "https://adaptivecards.microsoft.com", + "title": "Learn More" +} +"""; +var action = OpenUrlAction.Deserialize(actionJson); ``` -# [JavaScript/Node.js](#tab/javascript) - -The following code shows an example of `invoke` action type in Node.js: +## Work with input values -```javascript -CardFactory.actions([ -{ - type: "invoke", - title: "Option 1", - value: { - option: "opt1" - } -}]) -``` +### Associate data with cards ---- +You can send a card and have it be associated with specific data. Set the `data` value to be sent back to the client so you can associate it with a particular entity. -### Example of incoming invoke message +# [C#](#tab/csharp) -The top-level `replyToId` property contains the ID of the message that the card action came from. Use it if you want to update the message. +The following code shows an example of associating data with card actions in C#: -The following code shows an example of incoming invoke message: +```csharp +using Microsoft.Teams.Cards; -```json +private static AdaptiveCard CreateProfileCard() { - "type": "invoke", - "value": { - "option": "opt1" - }, - "timestamp": "2017-02-10T04:11:19.614Z", - "localTimestamp": "2017-02-09T21:11:19.614-07:00", - "id": "f:6894910862892785420", - "channelId": "msteams", - "serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/", - "from": { - "id": "29:1Eniglq0-uVL83xNB9GU6w_G5a4SZF0gcJLprZzhtEbel21G_5h- - NgoprRw45mP0AXUIZVeqrsIHSYV4ntgfVJQ", - "name": "John Doe" - }, - "conversation": { - "id": "19:97b1ec61-45bf-453c-9059-6e8984e0cef4_8d88f59b-ae61-4300-bec0-caace7d28446@unq.gbl.spaces" - }, - "recipient": { - "id": "28:8d88f59b-ae61-4300-bec0-caace7d28446", - "name": "MyBot" - }, - "entities": [ + return new AdaptiveCard + { + Schema = "http://adaptivecards.io/schemas/adaptive-card.json", + Body = new List { - "locale": "en-US", - "country": "US", - "platform": "Web", - "type": "clientInfo" - } - ], - "channelData": { - "channel": { - "id": "19:dc5ba12695be4eb7bf457cad6b4709eb@thread.skype" - }, - "team": { - "id": "19:712c61d0ef384e5fa681ba90ca943398@thread.skype" + new TextBlock("User Profile") + { + Weight = TextWeight.Bolder, + Size = TextSize.Large + }, + new TextInput + { + Id = "name", + Label = "Name", + Value = "John Doe" + }, + new TextInput + { + Id = "email", + Label = "Email", + Value = "john@contoso.com" + }, + new ToggleInput("Subscribe to newsletter") + { + Id = "subscribe", + Value = "false" + } }, - "tenant": { - "id": "72f988bf-86f1-41af-91ab-2d7cd011db47" + Actions = new List + { + new ExecuteAction + { + Title = "Save", + Data = new Union(new SubmitActionData + { + NonSchemaProperties = new Dictionary + { + { "action", "save_profile" }, + { "entity_id", "12345" } + } + }), + AssociatedInputs = AssociatedInputs.Auto + } } - }, - "replyToId": "1575667808184" + }; } ``` -## Action type sign-in +When the user submits the card, the handler receives the input values merged with the action data: -`signin` action type initiates an OAuth flow that permits bots to connect with secure services. For more information, see [authentication flow in bots](~/bots/how-to/authentication/auth-flow-bot.md). - -Teams also supports [Adaptive Cards actions](#adaptive-cards-actions) that are only used by Adaptive Cards. +```text +data["action"] → "save_profile" +data["entity_id"] → "12345" +data["name"] → "John Doe" +data["email"] → "john@contoso.com" +data["subscribe"] → "true" +``` # [JSON](#tab/json) -The following code shows an example of `signin` action type in JSON: +The following code shows an example of associating data with card actions in JSON: ```json { -"type": "signin", -"title": "Click me for signin", -"value": "https://signin.com" + "type": "AdaptiveCard", + "version": "1.5", + "schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "body": [ + { + "type": "TextBlock", + "text": "User Profile", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "Input.Text", + "id": "name", + "label": "Name", + "value": "John Doe" + }, + { + "type": "Input.Text", + "id": "email", + "label": "Email", + "value": "john@contoso.com" + }, + { + "type": "Input.Toggle", + "id": "subscribe", + "title": "Subscribe to newsletter", + "value": "false" + } + ], + "actions": [ + { + "type": "Action.Execute", + "title": "Save", + "data": { + "action": "save_profile", + "entity_id": "12345" + }, + "associatedInputs": "auto" + } + ] } ``` -# [C#](#tab/csharp) - -The following code shows an example of `signin` action type in C#: - -```csharp -var button = new CardAction() -{ - Type = ActionTypes.Signin, - Title = "Click me for signin", - Value = "https://signin.com" -}; -``` - -# [JavaScript/Node.js](#tab/javascript) - -The following code shows an example of `signin` action type in JavaScript: - -```javascript -CardFactory.actions([ -{ - type: "signin", - title: "Click me for signin", - value: "https://signin.com" -}]) -``` - --- -## Adaptive Cards actions - -> [!IMPORTANT] -> This documentation is considered legacy. For comprehensive information and resources related to Adaptive Cards, visit the [Adaptive Cards documentation hub](https://adaptivecards.microsoft.com/). - -Adaptive Cards support the following six action types: - -* [Action.OpenUrl](https://adaptivecards.microsoft.com/?topic=Action.OpenUrl): Opens the specified url. -* [Action.Submit](https://adaptivecards.microsoft.com/?topic=Action.Submit): Sends the result of the submit action to the bot. -* [Action.ShowCard](https://adaptivecards.microsoft.com/?topic=Action.ShowCard): Invokes a dialog and renders the sub-card into that dialog. You only need to handle this if `ShowCardActionMode` is set to popup. -* [Action.ToggleVisibility](https://adaptivecards.microsoft.com/?topic=Action.ToggleVisibility): Shows or hides one or more elements in the card. -* [Action.Execute](/adaptive-cards/authoring-cards/universal-action-model#actionexecute): Gathers the input fields, merges with optional data field, and sends an event to the client. -* [Action.ResetInputs](dynamic-search.md#actionresetinputs): Resets the values of the inputs in an Adaptive Card. - -### Action.Submit +### Input validation -`Action.Submit` type is used to gather the input, combine the `data` properties, and send an event to the bot. When a user selects the submit action, Teams sends a message activity to the bot, which includes the user's input in key-value pairs for all input fields and hidden data that is defined in the card payload. +Input controls provide built-in validation. For more information, see the Adaptive Cards [input validation documentation](https://adaptivecards.microsoft.com/?topic=input-validation). -In the Adaptive Card schema, the `data` property for Action.Submit is either a `string` or an `object`. A submit action behaves differently for each data property: - -* `string`: A string submit action automatically sends a message from the user to the bot and is visible in the conversation history. -* `object`: An object submit action automatically sends an invisible message from the user to the bot that contains hidden data. An object submit action populates the activity’s value property while the text property is empty. +# [C#](#tab/csharp) -Action.Submit is equivalent to the Bot Framework actions. You can also modify the Adaptive Card `Action.Submit` payload to support existing Bot Framework actions using a `msteams` property in the `data` object of `Action.Submit`. When you define the `msteams` property under `data`, the Teams client defines the behavior of `Action.Submit`. If the `msteams` property isn't defined in the schema, `Action.Submit` works like a regular Bot Framework invoke action, where; the submit action triggers an invoke call to the bot and the bot receives the payload with all the input values defined in the input fields. +The following code shows an example of input validation in C#: -> [!NOTE] -> ->* The bot doesn’t receive user input unless the user submits their actions in the Adaptive Card through a button, such as **Save** or **Submit**. For example, the bot doesn't consider user actions, such as selecting an option from multiple choices or filling out fields in a form, as inputs unless the user submits them. ->* Adding `msteams` to data with a Bot Framework action doesn't work with an Adaptive Card dialog. ->* Primary or destructive `ActionStyle` isn't supported in Teams. ->* Your app has five seconds to respond to the invoke message. +```csharp +using Microsoft.Teams.Cards; -#### Example +private static AdaptiveCard CreateProfileCardWithValidation() +{ + return new AdaptiveCard + { + Schema = "http://adaptivecards.io/schemas/adaptive-card.json", + Body = new List + { + new TextBlock("Profile with Validation") + { + Weight = TextWeight.Bolder, + Size = TextSize.Large + }, + new NumberInput + { + Id = "age", + Label = "Age", + IsRequired = true, + Min = 0, + Max = 120 + }, + new TextInput + { + Id = "name", + Label = "Name", + IsRequired = true, + ErrorMessage = "Name is required" + }, + new TextInput + { + Id = "location", + Label = "Location" + } + }, + Actions = new List + { + new ExecuteAction + { + Title = "Save", + Data = new Union(new SubmitActionData + { + NonSchemaProperties = new Dictionary + { + { "action", "save_profile" } + } + }), + AssociatedInputs = AssociatedInputs.Auto + } + } + }; +} +``` -The following is an example of an `Action.Submit` card payload: +# [JSON](#tab/json) -The payload consists of a text input field `"id": "text-1"` and hidden data payload `"hiddenKey": 123.45`. +The following code shows an example of input validation in JSON: ```json { - "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "type": "AdaptiveCard", "version": "1.5", - "fallbackText": "fallback text for sample 01", - "speak": "This is Adaptive Card sample 1", + "schema": "http://adaptivecards.io/schemas/adaptive-card.json", "body": [ { - "type": "Container", - "items": [ - { - "id": "text-1", - "type": "Input.Text" - } - ] + "type": "TextBlock", + "text": "Profile with Validation", + "weight": "Bolder", + "size": "Large" + }, + { + "type": "Input.Number", + "id": "age", + "label": "Age", + "isRequired": true, + "min": 0, + "max": 120 + }, + { + "type": "Input.Text", + "id": "name", + "label": "Name", + "isRequired": true, + "errorMessage": "Name is required" + }, + { + "type": "Input.Text", + "id": "location", + "label": "Location" } ], "actions": [ { - "type": "Action.Submit", + "type": "Action.Execute", + "title": "Save", "data": { - "hiddenKey": 123.45 - } + "action": "save_profile" + }, + "associatedInputs": "auto" } ] } ``` -:::image type="content" source="../../assets/images/adaptive-cards/adaptive-card-action-submit.png" alt-text="Screenshot shows an example of an Adaptive Card with the submit button."::: - -The following is an example of the incoming activity to a bot when user types something in the input field and selects **Submit**. The `value` attribute includes the user's input in the `text-1` property and a hidden data payload in the `hiddenKey` property: - - ```json - -{ - "type": "message", - "timestamp": "2023-07-18T23:45:41.699Z", - "localTimestamp": "2023-07-18T16:45:41.699-07:00", - "id": "f:9eb18f56-2259-8fa4-7dfc-111ffff58e67", - "channelId": "msteams", - "serviceUrl": "https://smba.trafficmanager.net/amer/", - "from": { - "id": "29:1E0NZYNZFQOCUI8zM9NY_EhlCsWgNbLGTHUNdBVX2ob8SLjhltEhQMPi07Gr6MLScFeS8SrKH1WGvJSiVKThnyw", - "name": "Megan Bowen", - "aadObjectId": "97b1ec61-45bf-453c-9059-6e8984e0cef4" - }, - "conversation": { - "conversationType": "personal", - "tenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47", - "id": "a:1H-RowZ3FrIheyjTupPnoCC6JvOLB5pCWms1xwqvAJG97j61D18EuSennYZE6tyfbQrnfIN3uIcwpOx73mg10hHp_uoTMMQlXhXosIu_q7QVCaYiW6Ch3bPWAitUw4aSX" - }, - "recipient": { - "id": "28:159e1c0f-15ef-4597-a8c6-44ba1fd89b78", - "name": "Mushroom" - }, - "entities": [ - { - "locale": "en-US", - "country": "US", - "platform": "Web", - "timezone": "America/Los_Angeles", - "type": "clientInfo" - } - ], - "channelData": { - "tenant": { - "id": "72f988bf-86f1-41af-91ab-2d7cd011db47" - }, - "source": { - "name": "message" - }, - "legacy": { - "replyToId": "1:1XFuAl7wF96vl6iAQk9tqus0uFrB89uujGpld-Qm-XEw" - } - }, - "replyToId": "1689723936016", - "value": { - "hiddenKey": 123.45, - "text-1": "HELLO" - }, - "locale": "en-US", - "localTimezone": "America/Los_Angeles" -} - ``` +--- ### Conditional enablement of action buttons @@ -548,8 +428,8 @@ You can use the `conditionallyEnabled` property to disable action buttons until Here's how the `conditionallyEnabled` property is defined: -| Property| Type | Required | Description | -|-----------|------|----------|-------------| +| Property | Type | Required | Description | +| --- | --- | --- | --- | | `conditionallyEnabled` | Boolean | ✔️ | Controls if the action is enabled only if at least one required input has been filled by the user. | The following card payload shows a conditionally enabled button: @@ -576,12 +456,12 @@ The following card payload shows a conditionally enabled button: ], "actions": [ { - "type": "Action.Submit", + "type": "Action.Execute", "title": "Submit", "conditionallyEnabled": true }, { - "type": "Action.Submit", + "type": "Action.Execute", "title": "Permanently disabled button", "isEnabled": false } @@ -608,210 +488,187 @@ The following card payload shows a conditionally enabled button: :::row-end::: -#### Form completion feedback - -You can build form completion feedback using an Adaptive Card. Form completion message appears in Adaptive Cards while sending a response to the bot. The message can be of two types, error or success: - -* **Error**: When a response sent to the bot is unsuccessful, **Something went wrong, Try again** message appears. The error occurs due to various reasons, such as: - * Too many requests - * Multiple concurrent operations on the same conversation - * Service dependency issue - * Gateway Timeout - - :::image type="content" source="../../assets/images/Cards/error-message.png" alt-text="Screenshot shows an Error message in an Adaptive Card." ::: - -* **Success**: When a response sent to the bot is successful, **Your response was sent to the app** message appears. - - :::image type="content" source="../../assets/images/Cards/success.PNG" alt-text="Screenshot shows a success message in an Adaptive Card."::: - - You can select **Close** or switch chat to dismiss the message. +## Server handlers - If you don't want to display the success message, set the attribute `hide` to `true` in the `msTeams` `feedback` property. Following is an example: +Card actions arrive as `card.action` activities in your app. These give you access to the validated input values plus any `data` values you had configured to be sent back to you. - ```json - "content": { - "type": "AdaptiveCard", - "title": "Card with hidden footer messages", - "version": "1.0", - "actions": [ - { - "type": "Action.Submit", - "title": "Submit", - "msTeams": { - "feedback": { - "hide": true - } - } - } - ] - } - ``` - -For more information on cards and cards in bots, see [cards documentation](~/task-modules-and-cards/what-are-cards.md). - -### Adaptive Cards with messageBack action - -To include a `messageBack` action with an Adaptive Card, include the following details in the `msteams` object: - -> [!NOTE] -> You can include additional hidden properties in the `data` object, if required. +Use the `OnAdaptiveCardAction` handler to process card actions: -| Property | Description | -| --- | --- | -| `type` | Set to `messageBack`. | -| `displayText` | Optional. Used by the user in the chat stream when the action is performed. This text isn't sent to your bot. | -| `value` | Sent to your bot when the action is performed. You can encode context for the action, such as unique identifiers or a JSON object. | -| `text` | Sent to your bot when the action is performed. Use this property to simplify bot development. Your code can check a single top-level property to dispatch bot logic. | +```csharp +using System.Text.Json; +using Microsoft.Teams.Api.Activities.Invokes.AdaptiveCards; +using Microsoft.Teams.Apps; +using Microsoft.Teams.Apps.Annotations; +using Microsoft.Teams.Common.Logging; -The following code shows an example of Adaptive Cards with `messageBack` action: +//... -```json +teams.OnAdaptiveCardAction(async context => { - "type": "Action.Submit", - "title": "Click me for messageBack", - "data": { - "msteams": { - "type": "messageBack", - "displayText": "I clicked this button", - "text": "text to bots", - "value": "{\"bfKey\": \"bfVal\", \"conflictKey\": \"from value\"}" - } - } -} -``` - -### Adaptive Cards with imBack action - -To include an `imBack` action with an Adaptive Card, include the following details in the `msteams` object: - -> [!NOTE] -> The `value` field is a simple string that doesn’t support formatting or hidden characters. + var activity = context.Activity; + context.Log.Info("[CARD_ACTION] Card action received"); -| Property | Description | -| --- | --- | -| `type` | Set to `imBack`. | -| `value` | String that needs to be echoed back in the chat. | + var data = activity.Value?.Action?.Data; -The following code shows an example of Adaptive Cards with `imBack` action: + context.Log.Info($"[CARD_ACTION] Raw data: {JsonSerializer.Serialize(data)}"); -```json -{ - "type": "Action.Submit", - "title": "Click me for imBack", - "data": { - "msteams": { - "type": "imBack", - "value": "Text to reply in chat" + if (data == null) + { + context.Log.Error("[CARD_ACTION] No data in card action"); + return new ActionResponse.Message("No data specified") { StatusCode = 400 }; } - } -} -``` - -### Adaptive Cards with sign-in action - -To include a `signin` action with an Adaptive Card, include the following details in the `msteams` object: -> [!NOTE] -> You can include additional hidden properties in the `data` object, if required. + string? action = data.TryGetValue("action", out var actionObj) ? actionObj?.ToString() : null; -| Property | Description | -| --- | --- | -| `type` | Set to `signin`. | -| `value` | Set to the URL where you want to redirect. | + if (string.IsNullOrEmpty(action)) + { + context.Log.Error("[CARD_ACTION] No action specified in card data"); + return new ActionResponse.Message("No action specified") { StatusCode = 400 }; + } + context.Log.Info($"[CARD_ACTION] Processing action: {action}"); -The following code shows an example of Adaptive Cards with `signin` action: + string? GetFormValue(string key) + { + if (data.TryGetValue(key, out var val)) + { + if (val is JsonElement element) + return element.GetString(); + return val?.ToString(); + } + return null; + } -```json -{ - "type": "Action.Submit", - "title": "Click me for signin", - "data": { - "msteams": { - "type": "signin", - "value": "https://signin.com" + switch (action) + { + case "submit_feedback": + var feedbackText = GetFormValue("feedback") ?? "No feedback provided"; + await context.Send($"Feedback received: {feedbackText}"); + break; + + case "create_task": + var title = GetFormValue("title") ?? "Untitled"; + var priority = GetFormValue("priority") ?? "medium"; + var dueDate = GetFormValue("due_date") ?? "No date"; + await context.Send($"Task created!\nTitle: {title}\nPriority: {priority}\nDue: {dueDate}"); + break; + + case "save_profile": + var name = GetFormValue("name") ?? "Unknown"; + var email = GetFormValue("email") ?? "No email"; + var subscribe = GetFormValue("subscribe") ?? "false"; + await context.Send($"Profile saved!\nName: {name}\nEmail: {email}\nSubscribed: {subscribe}"); + break; + + default: + context.Log.Error($"[CARD_ACTION] Unknown action: {action}"); + return new ActionResponse.Message("Unknown action") { StatusCode = 400 }; } - } -} + + return new ActionResponse.Message("Action processed successfully") { StatusCode = 200 }; +}); ``` -### Adaptive Cards with invoke action +> [!NOTE] +> The `data` values come from JSON and need to be extracted using the helper method shown above to handle different JSON element types. -To include an `invoke` action with an Adaptive Card, include the following details in the `msteams` object: +## End-to-end example: Task form card -> [!NOTE] -> You can include additional hidden properties in the `data` object, if required. +The following example shows a complete card with input fields and an action handler. -| Property | Description | -| --- | --- | -| `type` | Set to `task/fetch`. | -| `data` | Set the value. | +### Build the card -The following code shows an example of Adaptive Cards with `invoke` action: +```csharp +using Microsoft.Teams.Cards; -```json +private static AdaptiveCard CreateTaskFormCard() { - "type": "Action.Submit", - "title": "submit", - "data": { - "msteams": { - "type": "task/fetch" - } - } + return new AdaptiveCard + { + Schema = "http://adaptivecards.io/schemas/adaptive-card.json", + Body = new List + { + new TextBlock("Create New Task") + { + Weight = TextWeight.Bolder, + Size = TextSize.Large + }, + new TextInput + { + Id = "title", + Label = "Task Title", + Placeholder = "Enter task title" + }, + new TextInput + { + Id = "description", + Label = "Description", + Placeholder = "Enter task details", + IsMultiline = true + }, + new ChoiceSetInput + { + Id = "priority", + Label = "Priority", + Value = "medium", + Choices = new List + { + new() { Title = "High", Value = "high" }, + new() { Title = "Medium", Value = "medium" }, + new() { Title = "Low", Value = "low" } + } + }, + new DateInput + { + Id = "due_date", + Label = "Due Date", + Value = DateTime.Now.ToString("yyyy-MM-dd") + } + }, + Actions = new List + { + new ExecuteAction + { + Title = "Create Task", + Data = new Union(new SubmitActionData + { + NonSchemaProperties = new Dictionary + { + { "action", "create_task" } + } + }), + AssociatedInputs = AssociatedInputs.Auto, + Style = ActionStyle.Positive + } + } + }; } ``` -| Property | Description | -| --- | --- | -| `type` | Set to `invoke`. | -| `value` | Set the value to display. | +### Send the card -The following code shows an example of Adaptive Cards with `invoke` action with additional payload data: +```csharp +teams.OnMessage(async context => +{ + var text = context.Activity.Text?.ToLowerInvariant() ?? ""; -```json -[ - { - "type": "Action.Submit", - "title": "submit with object value", - "data": { - "ab": "xy", - "msteams": { - "type": "invoke", - "value": { "a": "b" } - } - } - }, - { - "type": "Action.Submit", - "title": "submit with stringified json value", - "data": { - "ab": "xy", - "msteams": { - "type": "invoke", - "value": "{ \"a\": \"b\"}" - } + if (text.Contains("form")) + { + await context.Typing(); + var card = CreateTaskFormCard(); + await context.Send(card); } - } -] +}); ``` -## Code samples - -|S.No.|Card| Description|.NET|Node.js|Python|Java|Manifest| -|:--|:--|:--------------------------------------------------------|-----|------------|-----|----------------------------|------| -|1|Adaptive Card actions|This sample shows how to send Adaptive Cards with multiple action types using a Teams bot.|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-adaptive-card-actions/csharp)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-adaptive-card-actions/nodejs)|NA|NA|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/blob/main/samples/bot-adaptive-card-actions/csharp/demo-manifest/bot-adaptivecard-actions.zip)| -|2|Using cards|Introduces all card types including thumbnail, audio, media etc. Builds on Welcoming user + multi-prompt bot by presenting a card with buttons in welcome message that route to appropriate dialog.|[View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/csharp_dotnetcore/06.using-cards)|[View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/javascript_nodejs/06.using-cards)|[View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/python/06.using-cards)|NA|NA| -|3|Adaptive Cards|Demonstrates how the multi-turn dialog can use a card to get user input for name and age.|[View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/csharp_dotnetcore/07.using-adaptive-cards)|[View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/javascript_nodejs/07.using-adaptive-cards)|[View](https://github.com/microsoft/BotBuilder-Samples/blob/main/samples/python/07.using-adaptive-cards)|NA|NA| -|4|Card Formatting|This sample demonstrates a conditionally enabled button.|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-formatting-cards/csharp)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/bot-formatting-cards/nodejs)|NA|NA|NA| - ## Next step > [!div class="nextstepaction"] -> [Universal Actions for Adaptive Cards](../cards/Universal-actions-for-adaptive-cards/Overview.md) +> [Building Adaptive Cards](/microsoftteams/platform/teams-sdk/in-depth-guides/adaptive-cards/building-adaptive-cards) ## See also -* [Cards reference](./cards-reference.md) -* [Types of cards](cards-reference.md) -* [Use dialogs from bots](~/task-modules-and-cards/task-modules/task-modules-bots.md) -* [Adaptive Cards in bots](../../bots/how-to/conversations/conversation-messages.md#adaptive-cards) -* [Adaptive Card-based Loop component](../../m365-apps/cards-loop-component.md) +* [Adaptive Cards overview](/microsoftteams/platform/teams-sdk/in-depth-guides/adaptive-cards/overview) +* [Executing Actions](/microsoftteams/platform/teams-sdk/in-depth-guides/adaptive-cards/executing-actions) +* [Listening to Activities](/microsoftteams/platform/teams-sdk/essentials/on-activity/overview) +* [Adaptive Cards documentation](https://adaptivecards.microsoft.com/) +* [Adaptive Cards Designer](https://adaptivecards.microsoft.com/designer.html) From 2c2dedf9b6ef95eb044b013239536b046b4a3bbf Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Wed, 1 Apr 2026 16:12:00 +0530 Subject: [PATCH 02/16] updated broken links --- .../messaging-extensions/how-to/link-unfurling.md | 2 +- .../Sequential-Workflows.md | 4 ++-- .../Up-To-Date-Views.md | 2 +- .../User-Specific-Views.md | 2 +- .../Work-with-Universal-Actions-for-Adaptive-Cards.md | 4 ++-- .../task-modules/task-modules-bots.md | 6 +++--- msteams-platform/whats-new.md | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/msteams-platform/messaging-extensions/how-to/link-unfurling.md b/msteams-platform/messaging-extensions/how-to/link-unfurling.md index 6f390d6352e..439e41fd470 100644 --- a/msteams-platform/messaging-extensions/how-to/link-unfurling.md +++ b/msteams-platform/messaging-extensions/how-to/link-unfurling.md @@ -123,7 +123,7 @@ The following card types are supported: * [Hero card](~/task-modules-and-cards/cards/cards-reference.md#hero-card) * [Connector card for Microsoft 365 Groups](../../task-modules-and-cards/cards/cards-reference.md#connector-card-for-microsoft-365-groups) -For more information, see [Action type invoke](~/task-modules-and-cards/cards/cards-actions.md#action-type-invoke). +For more information, see [Action.Execute](~/task-modules-and-cards/cards/cards-actions.md#actionexecute). The following code is an example of the `invoke` request: diff --git a/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Sequential-Workflows.md b/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Sequential-Workflows.md index 1f00000886b..5b9069a906e 100644 --- a/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Sequential-Workflows.md +++ b/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Sequential-Workflows.md @@ -146,7 +146,7 @@ adaptive_card_response = { ## See also * [Cards and dialogs](../../cards-and-task-modules.md) -* [Adaptive Card actions in Teams](~/task-modules-and-cards/cards/cards-actions.md#adaptive-cards-actions) +* [Adaptive Card actions in Teams](~/task-modules-and-cards/cards/cards-actions.md#card-actions) * [How bots work](/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0&preserve-view=true) * [Work with Universal Actions for Adaptive Cards](Work-with-universal-actions-for-adaptive-cards.md) -* [Form completion feedback](../cards-actions.md#form-completion-feedback) +* [Server handlers](../cards-actions.md#server-handlers) diff --git a/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Up-To-Date-Views.md b/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Up-To-Date-Views.md index 11e29a07724..45f089abe92 100644 --- a/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Up-To-Date-Views.md +++ b/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Up-To-Date-Views.md @@ -266,4 +266,4 @@ The following code provides an example of Adaptive Cards sent as response of `ad * [Cards and dialogs](../../cards-and-task-modules.md) * [Work with Universal Actions for Adaptive Cards](Work-with-universal-actions-for-adaptive-cards.md) * [User Specific Views](User-Specific-Views.md) -* [Form completion feedback](../cards-actions.md#form-completion-feedback) +* [Server handlers](../cards-actions.md#server-handlers) diff --git a/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/User-Specific-Views.md b/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/User-Specific-Views.md index 8ed191e00da..f8de13338c0 100644 --- a/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/User-Specific-Views.md +++ b/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/User-Specific-Views.md @@ -271,4 +271,4 @@ The following list provides card design guidelines for User Specific Views: * [Work with Universal Actions for Adaptive Cards](Work-with-Universal-Actions-for-Adaptive-Cards.md) * [Up to date cards](Up-To-Date-Views.md) * [Cards](../../what-are-cards.md) -* [Form completion feedback](../cards-actions.md#form-completion-feedback) +* [Server handlers](../cards-actions.md#server-handlers) diff --git a/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Work-with-Universal-Actions-for-Adaptive-Cards.md b/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Work-with-Universal-Actions-for-Adaptive-Cards.md index ea4ca749e23..2aa170970a4 100644 --- a/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Work-with-Universal-Actions-for-Adaptive-Cards.md +++ b/msteams-platform/task-modules-and-cards/cards/Universal-actions-for-adaptive-cards/Work-with-Universal-Actions-for-Adaptive-Cards.md @@ -117,7 +117,7 @@ For more information, see [backward compatibility on Teams](/adaptive-cards/auth ## See also * [Cards and dialogs](../../cards-and-task-modules.md) -* [Adaptive Card actions in Teams](~/task-modules-and-cards/cards/cards-actions.md#adaptive-cards-actions) +* [Adaptive Card actions in Teams](~/task-modules-and-cards/cards/cards-actions.md#card-actions) * [Sequential Workflows](~/task-modules-and-cards/cards/universal-actions-for-adaptive-cards/sequential-workflows.md) * [Up to date cards](~/task-modules-and-cards/cards/universal-actions-for-adaptive-cards/up-to-date-views.md) -* [Form completion feedback](../cards-actions.md#form-completion-feedback) +* [Server handlers](../cards-actions.md#server-handlers) diff --git a/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md b/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md index ff6161e724e..26a7aa17282 100644 --- a/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md +++ b/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md @@ -12,8 +12,8 @@ Invoke dialogs (referred as task modules in TeamsJS v1.x) from Microsoft Teams b There are two ways of invoking dialogs: -* A new invoke message `task/fetch`: Using the `invoke` [card action](~/task-modules-and-cards/cards/cards-actions.md#action-type-invoke) for Bot Framework cards, or the `Action.Submit` [card action](~/task-modules-and-cards/cards/cards-actions.md#adaptive-cards-actions) for Adaptive Cards, with `task/fetch`, either an HTML or Adaptive Card-based dialog is fetched dynamically from your bot. -* Deep link URLs: Using the [deep link syntax for dialogs](../../concepts/build-and-test/deep-link-application.md#deep-link-to-open-a-dialog), you can use the `openUrl` [card action](~/task-modules-and-cards/cards/cards-actions.md#action-type-openurl) for Bot Framework cards or the `Action.OpenUrl` [card action](~/task-modules-and-cards/cards/cards-actions.md#adaptive-cards-actions) for Adaptive Cards, respectively. With deep link URLs, the dialog URL or Adaptive Card body is already known to avoid a server round-trip relative to `task/fetch`. +* A new invoke message `task/fetch`: Using the `invoke` [card action](~/task-modules-and-cards/cards/cards-actions.md#actionexecute) for Bot Framework cards, or the `Action.Submit` [card action](~/task-modules-and-cards/cards/cards-actions.md#card-actions) for Adaptive Cards, with `task/fetch`, either an HTML or Adaptive Card-based dialog is fetched dynamically from your bot. +* Deep link URLs: Using the [deep link syntax for dialogs](../../concepts/build-and-test/deep-link-application.md#deep-link-to-open-a-dialog), you can use the `openUrl` [card action](~/task-modules-and-cards/cards/cards-actions.md#actionopenurl) for Bot Framework cards or the `Action.OpenUrl` [card action](~/task-modules-and-cards/cards/cards-actions.md#card-actions) for Adaptive Cards, respectively. With deep link URLs, the dialog URL or Adaptive Card body is already known to avoid a server round-trip relative to `task/fetch`. > [!IMPORTANT] > Each `url` and `fallbackUrl` must implement the HTTPS encryption protocol. @@ -28,7 +28,7 @@ When the `value` object of the `invoke` card action or `Action.Submit` is initia The following steps provide instructions on how to invoke a dialog (referred as task module in TeamsJS v1.x) using `task/fetch`: -1. This image shows a Bot Framework hero card with a **Buy** `invoke` [card action](~/task-modules-and-cards/cards/cards-actions.md#action-type-invoke). The value of the `type` property is `task/fetch` and the rest of the `value` object can be of your choice. +1. This image shows a Bot Framework hero card with a **Buy** `invoke` [card action](~/task-modules-and-cards/cards/cards-actions.md#actionexecute). The value of the `type` property is `task/fetch` and the rest of the `value` object can be of your choice. 1. The bot receives the `invoke` HTTP POST message. 1. The bot creates a response object and returns it in the body of the POST response with an HTTP 200 response code. For more information on schema for responses, see the [discussion on task/submit](#responds-to-the-tasksubmit-messages). The following code provides an example of body of the HTTP response that contains a [TaskInfo object](~/task-modules-and-cards/task-modules/invoking-task-modules.md#dialoginfo-object) embedded in a wrapper object: diff --git a/msteams-platform/whats-new.md b/msteams-platform/whats-new.md index ef3fd7f60fd..02df058c927 100644 --- a/msteams-platform/whats-new.md +++ b/msteams-platform/whats-new.md @@ -260,7 +260,7 @@ Teams platform features that are available to all app developers.
| 07/21/2022 | Introduced step by step guide to send activity feed notifications | Design your app > UI components> Activity feed notifications > [Send activity feed notification](sbs-graphactivity-feedbroadcast.yml) | | 07/08/2022| Updates to send channel ID selected by user during app installation to bots via conversation and installation update events | Build bots > Bot conversations > Conversation events in your Teams bot > [Conversation events in your Teams bot](bots/how-to/conversations/subscribe-to-conversation-events.md) | | 06/16/2022 | Updated media capabilities to support desktop and mobile| Integrate device capabilities > [Integrate media capabilities](concepts/device-capabilities/media-capabilities.md)| -| 06/08/2022 | Optional card feedback for success message| Build cards and task modules > Build cards > [Form completion feedback](task-modules-and-cards/cards/cards-actions.md#form-completion-feedback)| +| 06/08/2022 | Optional card feedback for success message| Build cards and task modules > Build cards > [Server handlers](task-modules-and-cards/cards/cards-actions.md#server-handlers)| | 06/03/2022 | Updated Add authentication module for enabling SSO for tab app with new structure and procedures | Add authentication > Tabs > [Enable single sign-on in a tab app](tabs/how-to/authentication/tab-sso-overview.md) | | 05/24/2022 | Additional tips for rapid approval to publish your app linked to a SaaS offer | Publish to the Teams Store > Overview > [Additional tips for rapid approval to publish your app linked to a SaaS offer](~/concepts/deploy-and-publish/appsource/publish.md#additional-tips-for-rapid-approval-to-publish-your-app-linked-to-a-saas-offer) | | 05/24/2022 | Submit your Outlook- and Office-enabled apps to the Teams Store | Extend your app across Microsoft 365 > [Overview](m365-apps/overview.md) | @@ -296,7 +296,7 @@ Teams platform features that are available to all app developers.
| 02/08/2022 | Introduced step-by-step guide to create Calling and Meeting bot| Build bots > Calls and meetings bots > Register calls and meetings bot > [Step-by-step guide to create Calling and Meeting bot](sbs-calling-and-meeting.yml) | | 02/02/2022 | Introduced app manifest version 1.12 | App manifest > [App manifest schema](/microsoft-365/extensibility/schema/#all-generally-available-versions) | | 01/25/2022 | Send real-time captions API | Build apps for Teams meetings > Meeting apps API references> [Advanced meeting APIs](apps-in-teams-meetings/meeting-apps-apis.md)| -| 01/19/2022 | Adaptive Cards form completion feedback | Build cards and task modules > Build cards > [Form completion feedback](task-modules-and-cards/cards/cards-actions.md#form-completion-feedback)| +| 01/19/2022 | Adaptive Cards form completion feedback | Build cards and task modules > Build cards > [Server handlers](task-modules-and-cards/cards/cards-actions.md#server-handlers)| | 01/17/2022 | People Picker in Adaptive Cards for desktop | Build cards and task modules > Build cards > [People Picker in Adaptive Cards](task-modules-and-cards/cards/people-picker.md)| From c7b069f8a9979961b4f9e5dfb420cd1d215ac1f9 Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Wed, 1 Apr 2026 16:20:09 +0530 Subject: [PATCH 03/16] Update link-unfurling.md --- .../messaging-extensions/how-to/link-unfurling.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/msteams-platform/messaging-extensions/how-to/link-unfurling.md b/msteams-platform/messaging-extensions/how-to/link-unfurling.md index 439e41fd470..e636fca1615 100644 --- a/msteams-platform/messaging-extensions/how-to/link-unfurling.md +++ b/msteams-platform/messaging-extensions/how-to/link-unfurling.md @@ -4,9 +4,9 @@ author: surbhigupta description: Learn to add link unfurling with Developer Portal and messaging extension in a Teams app with app manifest or manually. Update web service code to handle invoke. ms.localizationpriority: medium ms.topic: conceptual -ms.author: surbhigupta +ms.author: vikasalmal ms.owner: slamba -ms.date: 11/06/2024 +ms.date: 04/01/2026 --- # Link unfurling @@ -537,4 +537,4 @@ The following JSON payload example for `suggestedActions` property: * [Message extensions](../what-are-messaging-extensions.md) * [Adaptive Cards](../../task-modules-and-cards/what-are-cards.md#adaptive-cards) * [Tabs link unfurling and Stageview](../../tabs/tabs-link-unfurling.md) -* [Bot activity handlers](../../bots/bot-basics.md) \ No newline at end of file +* [Bot activity handlers](../../bots/bot-basics.md) From d154a8f7bc35d149c5197938ed1210708ca39826 Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Wed, 1 Apr 2026 16:49:36 +0530 Subject: [PATCH 04/16] Update link-unfurling.md --- msteams-platform/messaging-extensions/how-to/link-unfurling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msteams-platform/messaging-extensions/how-to/link-unfurling.md b/msteams-platform/messaging-extensions/how-to/link-unfurling.md index e636fca1615..0abf8efa482 100644 --- a/msteams-platform/messaging-extensions/how-to/link-unfurling.md +++ b/msteams-platform/messaging-extensions/how-to/link-unfurling.md @@ -1,6 +1,6 @@ --- title: Add Link Unfurling to App Manifest -author: surbhigupta +author: vikasalmal description: Learn to add link unfurling with Developer Portal and messaging extension in a Teams app with app manifest or manually. Update web service code to handle invoke. ms.localizationpriority: medium ms.topic: conceptual From 0c911a97178bf92b32fab9fd3de316378aab9f20 Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Fri, 3 Apr 2026 17:05:57 +0530 Subject: [PATCH 05/16] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- msteams-platform/whats-new.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msteams-platform/whats-new.md b/msteams-platform/whats-new.md index e07a9bc1126..8efcad5cda5 100644 --- a/msteams-platform/whats-new.md +++ b/msteams-platform/whats-new.md @@ -260,7 +260,7 @@ Teams platform features that are available to all app developers.
| 07/21/2022 | Introduced step by step guide to send activity feed notifications | Design your app > UI components> Activity feed notifications > [Send activity feed notification](sbs-graphactivity-feedbroadcast.yml) | | 07/08/2022| Updates to send channel ID selected by user during app installation to bots via conversation and installation update events | Build bots > Bot conversations > Conversation events in your Teams bot > [Conversation events in your Teams bot](bots/how-to/conversations/subscribe-to-conversation-events.md) | | 06/16/2022 | Updated media capabilities to support desktop and mobile| Integrate device capabilities > [Integrate media capabilities](concepts/device-capabilities/media-capabilities.md)| -| 06/08/2022 | Optional card feedback for success message| Build cards and task modules > Build cards > [Server handlers](task-modules-and-cards/cards/cards-actions.md#server-handlers)| +| 06/08/2022 | Server handlers for card actions| Build cards and task modules > Build cards > [Server handlers](task-modules-and-cards/cards/cards-actions.md#server-handlers)| | 06/03/2022 | Updated Add authentication module for enabling SSO for tab app with new structure and procedures | Add authentication > Tabs > [Enable single sign-on in a tab app](tabs/how-to/authentication/tab-sso-overview.md) | | 05/24/2022 | Additional tips for rapid approval to publish your app linked to a SaaS offer | Publish to the Teams Store > Overview > [Additional tips for rapid approval to publish your app linked to a SaaS offer](~/concepts/deploy-and-publish/appsource/publish.md#additional-tips-for-rapid-approval-to-publish-your-app-linked-to-a-saas-offer) | | 05/24/2022 | Submit your Outlook- and Office-enabled apps to the Teams Store | Extend your app across Microsoft 365 > [Overview](m365-apps/overview.md) | From 56f8aa345059e685efd91f811de3aa533c7817ce Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Fri, 3 Apr 2026 17:08:42 +0530 Subject: [PATCH 06/16] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- msteams-platform/whats-new.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msteams-platform/whats-new.md b/msteams-platform/whats-new.md index 8efcad5cda5..c3cbc6518bb 100644 --- a/msteams-platform/whats-new.md +++ b/msteams-platform/whats-new.md @@ -296,7 +296,7 @@ Teams platform features that are available to all app developers.
| 02/08/2022 | Introduced step-by-step guide to create Calling and Meeting bot| Build bots > Calls and meetings bots > Register calls and meetings bot > [Step-by-step guide to create Calling and Meeting bot](sbs-calling-and-meeting.yml) | | 02/02/2022 | Introduced app manifest version 1.12 | App manifest > [App manifest schema](/microsoft-365/extensibility/schema/#all-generally-available-versions) | | 01/25/2022 | Send real-time captions API | Build apps for Teams meetings > Meeting apps API references> [Advanced meeting APIs](apps-in-teams-meetings/meeting-apps-apis.md)| -| 01/19/2022 | Adaptive Cards form completion feedback | Build cards and task modules > Build cards > [Server handlers](task-modules-and-cards/cards/cards-actions.md#server-handlers)| +| 01/19/2022 | Server handlers for Adaptive Cards form completion | Build cards and task modules > Build cards > [Server handlers](task-modules-and-cards/cards/cards-actions.md#server-handlers)| | 01/17/2022 | People Picker in Adaptive Cards for desktop | Build cards and task modules > Build cards > [People Picker in Adaptive Cards](task-modules-and-cards/cards/people-picker.md)| From a805a7b4d39c9e6c49621fe7c0d1881e38dc340c Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Fri, 10 Apr 2026 14:24:49 +0530 Subject: [PATCH 07/16] made changes to three files --- .../messaging-extensions/how-to/link-unfurling.md | 2 +- .../task-modules-and-cards/cards/cards-actions.md | 10 +++++----- .../task-modules/task-modules-bots.md | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/msteams-platform/messaging-extensions/how-to/link-unfurling.md b/msteams-platform/messaging-extensions/how-to/link-unfurling.md index 0abf8efa482..1a31fdcbe1f 100644 --- a/msteams-platform/messaging-extensions/how-to/link-unfurling.md +++ b/msteams-platform/messaging-extensions/how-to/link-unfurling.md @@ -6,7 +6,7 @@ ms.localizationpriority: medium ms.topic: conceptual ms.author: vikasalmal ms.owner: slamba -ms.date: 04/01/2026 +ms.date: 04/10/2026 --- # Link unfurling diff --git a/msteams-platform/task-modules-and-cards/cards/cards-actions.md b/msteams-platform/task-modules-and-cards/cards/cards-actions.md index b853ecaab1b..e28edc1c4b3 100644 --- a/msteams-platform/task-modules-and-cards/cards/cards-actions.md +++ b/msteams-platform/task-modules-and-cards/cards/cards-actions.md @@ -3,7 +3,7 @@ title: Adaptive Card actions in Teams SDK description: Learn about Adaptive Card action types such as Action.Execute, Action.OpenUrl, Action.ShowCard, and Action.ToggleVisibility, and how to handle card actions using the Teams SDK. ms.localizationpriority: medium ms.topic: conceptual -ms.date: 03/31/2026 +ms.date: 04/10/2026 --- # Card actions @@ -148,7 +148,7 @@ The following code shows an example of grouping actions in JSON: { "type": "AdaptiveCard", "version": "1.5", - "schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "actions": [ { "type": "Action.Execute", @@ -264,7 +264,7 @@ The following code shows an example of associating data with card actions in JSO { "type": "AdaptiveCard", "version": "1.5", - "schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "body": [ { "type": "TextBlock", @@ -378,7 +378,7 @@ The following code shows an example of input validation in JSON: { "type": "AdaptiveCard", "version": "1.5", - "schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "body": [ { "type": "TextBlock", @@ -490,7 +490,7 @@ The following card payload shows a conditionally enabled button: ## Server handlers -Card actions arrive as `card.action` activities in your app. These give you access to the validated input values plus any `data` values you had configured to be sent back to you. +Universal Action submissions are delivered to your bot as `invoke` activities named `adaptiveCard/action`. In the Teams SDK, these are surfaced to your app as `card.action` activities, which give you access to the validated input values plus any `data` values you configured to be sent back to you. Use the `OnAdaptiveCardAction` handler to process card actions: diff --git a/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md b/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md index 26a7aa17282..fd5c62a93a2 100644 --- a/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md +++ b/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md @@ -3,7 +3,7 @@ title: Use dialogs in Microsoft Teams bots description: Learn how to use dialogs with Microsoft Teams bots and invoke dialogs, about Bot Framework card and Adaptive Card actions, deep links, and respond to messages. ms.localizationpriority: medium ms.topic: how-to -ms.date: 01/31/2023 +ms.date: 04/10/2026 --- # Use dialogs with bots @@ -12,8 +12,8 @@ Invoke dialogs (referred as task modules in TeamsJS v1.x) from Microsoft Teams b There are two ways of invoking dialogs: -* A new invoke message `task/fetch`: Using the `invoke` [card action](~/task-modules-and-cards/cards/cards-actions.md#actionexecute) for Bot Framework cards, or the `Action.Submit` [card action](~/task-modules-and-cards/cards/cards-actions.md#card-actions) for Adaptive Cards, with `task/fetch`, either an HTML or Adaptive Card-based dialog is fetched dynamically from your bot. -* Deep link URLs: Using the [deep link syntax for dialogs](../../concepts/build-and-test/deep-link-application.md#deep-link-to-open-a-dialog), you can use the `openUrl` [card action](~/task-modules-and-cards/cards/cards-actions.md#actionopenurl) for Bot Framework cards or the `Action.OpenUrl` [card action](~/task-modules-and-cards/cards/cards-actions.md#card-actions) for Adaptive Cards, respectively. With deep link URLs, the dialog URL or Adaptive Card body is already known to avoid a server round-trip relative to `task/fetch`. +* A new invoke message `task/fetch`: Using the [`Action.Execute`](~/task-modules-and-cards/cards/cards-actions.md#actionexecute) card action for Adaptive Cards with `task/fetch`, either an HTML or Adaptive Card-based dialog is fetched dynamically from your bot. +* Deep link URLs: Using the [deep link syntax for dialogs](../../concepts/build-and-test/deep-link-application.md#deep-link-to-open-a-dialog), you can use the [`Action.OpenUrl`](~/task-modules-and-cards/cards/cards-actions.md#actionopenurl) card action for Adaptive Cards. With deep link URLs, the dialog URL or Adaptive Card body is already known to avoid a server round-trip relative to `task/fetch`. > [!IMPORTANT] > Each `url` and `fallbackUrl` must implement the HTTPS encryption protocol. @@ -28,9 +28,9 @@ When the `value` object of the `invoke` card action or `Action.Submit` is initia The following steps provide instructions on how to invoke a dialog (referred as task module in TeamsJS v1.x) using `task/fetch`: -1. This image shows a Bot Framework hero card with a **Buy** `invoke` [card action](~/task-modules-and-cards/cards/cards-actions.md#actionexecute). The value of the `type` property is `task/fetch` and the rest of the `value` object can be of your choice. -1. The bot receives the `invoke` HTTP POST message. -1. The bot creates a response object and returns it in the body of the POST response with an HTTP 200 response code. For more information on schema for responses, see the [discussion on task/submit](#responds-to-the-tasksubmit-messages). The following code provides an example of body of the HTTP response that contains a [TaskInfo object](~/task-modules-and-cards/task-modules/invoking-task-modules.md#dialoginfo-object) embedded in a wrapper object: +1. This image shows an Adaptive Card with a **Buy** [`Action.Execute`](~/task-modules-and-cards/cards/cards-actions.md#actionexecute) card action. The value of the `type` property is `task/fetch` and the rest of the `data` object can be of your choice. +1. The bot receives a `card.action` activity. In the Teams SDK, you handle this using the `OnAdaptiveCardAction` handler. For more information, see [Executing Actions](https://learn.microsoft.com/en-us/microsoftteams/platform/teams-sdk/in-depth-guides/adaptive-cards/executing-actions). +1. The bot creates an `ActionResponse` object and returns it. For more information on schema for responses, see the [discussion on task/submit](#responds-to-the-tasksubmit-messages). The following code provides an example of the response body that contains a [TaskInfo object](~/task-modules-and-cards/task-modules/invoking-task-modules.md#dialoginfo-object) embedded in a wrapper object: ```json { From c871d1075e7554577192fbdd3a368393bb58c279 Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Fri, 10 Apr 2026 14:36:35 +0530 Subject: [PATCH 08/16] Update task-modules-bots.md --- .../task-modules-and-cards/task-modules/task-modules-bots.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md b/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md index fd5c62a93a2..4f521fd709b 100644 --- a/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md +++ b/msteams-platform/task-modules-and-cards/task-modules/task-modules-bots.md @@ -29,7 +29,7 @@ When the `value` object of the `invoke` card action or `Action.Submit` is initia The following steps provide instructions on how to invoke a dialog (referred as task module in TeamsJS v1.x) using `task/fetch`: 1. This image shows an Adaptive Card with a **Buy** [`Action.Execute`](~/task-modules-and-cards/cards/cards-actions.md#actionexecute) card action. The value of the `type` property is `task/fetch` and the rest of the `data` object can be of your choice. -1. The bot receives a `card.action` activity. In the Teams SDK, you handle this using the `OnAdaptiveCardAction` handler. For more information, see [Executing Actions](https://learn.microsoft.com/en-us/microsoftteams/platform/teams-sdk/in-depth-guides/adaptive-cards/executing-actions). +1. The bot receives a `card.action` activity. In the Teams SDK, you handle this using the `OnAdaptiveCardAction` handler. For more information, see [Executing Actions](/microsoftteams/platform/teams-sdk/in-depth-guides/adaptive-cards/executing-actions). 1. The bot creates an `ActionResponse` object and returns it. For more information on schema for responses, see the [discussion on task/submit](#responds-to-the-tasksubmit-messages). The following code provides an example of the response body that contains a [TaskInfo object](~/task-modules-and-cards/task-modules/invoking-task-modules.md#dialoginfo-object) embedded in a wrapper object: ```json From 72c87b5fbd21dff3c46b56d3ce4218cf844f5643 Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Thu, 23 Apr 2026 11:58:05 +0530 Subject: [PATCH 09/16] Update cards-actions.md --- .../cards/cards-actions.md | 456 +++++++++++++++++- 1 file changed, 455 insertions(+), 1 deletion(-) diff --git a/msteams-platform/task-modules-and-cards/cards/cards-actions.md b/msteams-platform/task-modules-and-cards/cards/cards-actions.md index e28edc1c4b3..5dce8645e31 100644 --- a/msteams-platform/task-modules-and-cards/cards/cards-actions.md +++ b/msteams-platform/task-modules-and-cards/cards/cards-actions.md @@ -3,7 +3,7 @@ title: Adaptive Card actions in Teams SDK description: Learn about Adaptive Card action types such as Action.Execute, Action.OpenUrl, Action.ShowCard, and Action.ToggleVisibility, and how to handle card actions using the Teams SDK. ms.localizationpriority: medium ms.topic: conceptual -ms.date: 04/10/2026 +ms.date: 04/22/2026 --- # Card actions @@ -54,6 +54,30 @@ var action = new ExecuteAction }; ``` +# [TypeScript](#tab/typescript) + +The following code shows an example of an `Action.Execute` action in TypeScript: + +```typescript +import { ExecuteAction } from '@microsoft/teams.cards'; + +const action = new ExecuteAction({ title: 'Submit Feedback' }) + .withData({ action: 'submit_feedback' }) + .withAssociatedInputs('auto'); +``` + +# [Python](#tab/python) + +The following code shows an example of an `Action.Execute` action in Python: + +```python +from microsoft_teams.cards.core import ExecuteAction + +action = ExecuteAction(title="Submit Feedback") \ + .with_data({"action": "submit_feedback"}) \ + .with_associated_inputs("auto") +``` + # [JSON](#tab/json) The following code shows an example of an `Action.Execute` action in JSON: @@ -91,6 +115,28 @@ var action = new OpenUrlAction("https://adaptivecards.microsoft.com") }; ``` +# [TypeScript](#tab/typescript) + +The following code shows an example of an `Action.OpenUrl` action in TypeScript: + +```typescript +import { OpenUrlAction } from '@microsoft/teams.cards'; + +const action = new OpenUrlAction('https://adaptivecards.microsoft.com') + .withTitle('Learn More'); +``` + +# [Python](#tab/python) + +The following code shows an example of an `Action.OpenUrl` action in Python: + +```python +from microsoft_teams.cards.core import OpenUrlAction + +action = OpenUrlAction(url="https://adaptivecards.microsoft.com") \ + .with_title("Learn More") +``` + # [JSON](#tab/json) The following code shows an example of an `Action.OpenUrl` action in JSON: @@ -140,6 +186,39 @@ var card = new AdaptiveCard }; ``` +# [TypeScript](#tab/typescript) + +The following code shows an example of grouping actions in TypeScript: + +```typescript +import { ActionSet, ExecuteAction, OpenUrlAction } from '@microsoft/teams.cards'; + +const actionSet = new ActionSet( + new ExecuteAction({ title: 'Submit Feedback' }) + .withData({ action: 'submit_feedback' }) + .withAssociatedInputs('auto'), + new OpenUrlAction('https://adaptivecards.microsoft.com') + .withTitle('Learn More') +); +``` + +# [Python](#tab/python) + +The following code shows an example of grouping actions in Python: + +```python +from microsoft_teams.cards.core import ActionSet, ExecuteAction, OpenUrlAction + +action_set = ActionSet( + actions=[ + ExecuteAction(title="Submit Feedback") + .with_data({"action": "submit_feedback"}), + OpenUrlAction(url="https://adaptivecards.microsoft.com") + .with_title("Learn More") + ] +) +``` + # [JSON](#tab/json) The following code shows an example of grouping actions in JSON: @@ -172,6 +251,8 @@ The following code shows an example of grouping actions in JSON: If you prefer to work with raw JSON, you can deserialize it into the SDK types: +# [C#](#tab/csharp) + ```csharp var actionJson = """ { @@ -183,6 +264,30 @@ var actionJson = """ var action = OpenUrlAction.Deserialize(actionJson); ``` +# [TypeScript](#tab/typescript) + +```typescript +import { IOpenUrlAction } from '@microsoft/teams.cards'; + +const actionJson = { + type: 'Action.OpenUrl', + url: 'https://adaptivecards.microsoft.com', + title: 'Learn More', +} as const satisfies IOpenUrlAction; +``` + +# [Python](#tab/python) + +```python +action_json = { + "type": "Action.OpenUrl", + "url": "https://adaptivecards.microsoft.com", + "title": "Learn More", +} +``` + +--- + ## Work with input values ### Associate data with cards @@ -370,6 +475,75 @@ private static AdaptiveCard CreateProfileCardWithValidation() } ``` +# [TypeScript](#tab/typescript) + +The following code shows an example of input validation in TypeScript: + +```typescript +import { + AdaptiveCard, + NumberInput, + TextInput, + ActionSet, + ExecuteAction, +} from '@microsoft/teams.cards'; + +function createProfileCardInputValidation() { + const ageInput = new NumberInput({ id: 'age' }) + .withLabel('Age') + .withIsRequired(true) + .withMin(0) + .withMax(120); + + const nameInput = new TextInput({ id: 'name' }) + .withLabel('Name') + .withIsRequired() + .withErrorMessage('Name is required'); + + const card = new AdaptiveCard( + ageInput, + nameInput, + new TextInput({ id: 'location' }).withLabel('Location'), + new ActionSet( + new ExecuteAction({ title: 'Save' }) + .withData({ action: 'save_profile' }) + .withAssociatedInputs('auto') + ) + ); + + return card; +} +``` + +# [Python](#tab/python) + +The following code shows an example of input validation in Python: + +```python +from microsoft_teams.cards import AdaptiveCard, ActionSet, ExecuteAction, NumberInput, TextInput + +def create_profile_card_input_validation(): + age_input = NumberInput(id="age").with_label("Age").with_is_required(True).with_min(0).with_max(120) + name_input = TextInput(id="name").with_label("Name").with_is_required(True).with_error_message("Name is required") + + card = AdaptiveCard( + schema="http://adaptivecards.io/schemas/adaptive-card.json", + body=[ + age_input, + name_input, + TextInput(id="location").with_label("Location"), + ActionSet( + actions=[ + ExecuteAction(title="Save") + .with_data({"action": "save_profile"}) + .with_associated_inputs("auto") + ] + ), + ], + ) + return card +``` + # [JSON](#tab/json) The following code shows an example of input validation in JSON: @@ -494,6 +668,8 @@ Universal Action submissions are delivered to your bot as `invoke` activities na Use the `OnAdaptiveCardAction` handler to process card actions: +# [C#](#tab/csharp) + ```csharp using System.Text.Json; using Microsoft.Teams.Api.Activities.Invokes.AdaptiveCards; @@ -568,6 +744,147 @@ teams.OnAdaptiveCardAction(async context => }); ``` +# [TypeScript](#tab/typescript) + +```typescript +import { + AdaptiveCardActionErrorResponse, + AdaptiveCardActionMessageResponse, +} from '@microsoft/teams.api'; +import { App } from '@microsoft/teams.apps'; + +// ... + +app.on('card.action', async ({ activity, send }) => { + const data = activity.value?.action?.data; + + if (!data?.action) { + return { + statusCode: 400, + type: 'application/vnd.microsoft.error', + value: { + code: 'BadRequest', + message: 'No action specified', + innerHttpError: { + statusCode: 400, + body: { error: 'No action specified' }, + }, + }, + } satisfies AdaptiveCardActionErrorResponse; + } + + console.debug('Received action data:', data); + + switch (data.action) { + case 'submit_feedback': + await send(`Feedback received: ${data.feedback}`); + break; + + case 'create_task': + await send( + `Task created!\nTitle: ${data.title}\nPriority: ${data.priority}\nDue: ${data.due_date}` + ); + break; + + case 'save_profile': + await send( + `Profile saved!\nName: ${data.name}\nEmail: ${data.email}\nSubscribed: ${data.subscribe}` + ); + break; + + default: + return { + statusCode: 400, + type: 'application/vnd.microsoft.error', + value: { + code: 'BadRequest', + message: 'Unknown action', + innerHttpError: { + statusCode: 400, + body: { error: 'Unknown action' }, + }, + }, + } satisfies AdaptiveCardActionErrorResponse; + } + + return { + statusCode: 200, + type: 'application/vnd.microsoft.activity.message', + value: 'Action processed successfully', + } satisfies AdaptiveCardActionMessageResponse; +}); +``` + +# [Python](#tab/python) + +```python +from microsoft_teams.api import ( + AdaptiveCardInvokeActivity, + AdaptiveCardActionErrorResponse, + AdaptiveCardActionMessageResponse, + HttpError, + InnerHttpError, + AdaptiveCardInvokeResponse, +) +from microsoft_teams.apps import ActivityContext + +# ... + +@app.on_card_action +async def handle_card_action( + ctx: ActivityContext[AdaptiveCardInvokeActivity], +) -> AdaptiveCardInvokeResponse: + data = ctx.activity.value.action.data + + if not data.get("action"): + return AdaptiveCardActionErrorResponse( + status_code=400, + type="application/vnd.microsoft.error", + value=HttpError( + code="BadRequest", + message="No action specified", + inner_http_error=InnerHttpError( + status_code=400, + body={"error": "No action specified"}, + ), + ), + ) + + print("Received action data:", data) + + if data["action"] == "submit_feedback": + await ctx.send(f"Feedback received: {data.get('feedback')}") + elif data["action"] == "create_task": + await ctx.send( + f"Task created!\nTitle: {data.get('title')}\nPriority: {data.get('priority')}\nDue: {data.get('due_date')}" + ) + elif data["action"] == "save_profile": + await ctx.send( + f"Profile saved!\nName: {data.get('name')}\nEmail: {data.get('email')}\nSubscribed: {data.get('subscribe')}" + ) + else: + return AdaptiveCardActionErrorResponse( + status_code=400, + type="application/vnd.microsoft.error", + value=HttpError( + code="BadRequest", + message="Unknown action", + inner_http_error=InnerHttpError( + status_code=400, + body={"error": "Unknown action"}, + ), + ), + ) + + return AdaptiveCardActionMessageResponse( + status_code=200, + type="application/vnd.microsoft.activity.message", + value="Action processed successfully", + ) +``` + +--- + > [!NOTE] > The `data` values come from JSON and need to be extracted using the helper method shown above to handle different JSON element types. @@ -577,6 +894,8 @@ The following example shows a complete card with input fields and an action hand ### Build the card +# [C#](#tab/csharp) + ```csharp using Microsoft.Teams.Cards; @@ -644,8 +963,100 @@ private static AdaptiveCard CreateTaskFormCard() } ``` +# [TypeScript](#tab/typescript) + +```typescript +import { + AdaptiveCard, + TextBlock, + TextInput, + ChoiceSetInput, + DateInput, + ActionSet, + ExecuteAction, +} from '@microsoft/teams.cards'; + +function createTaskFormCard() { + return new AdaptiveCard( + new TextBlock('Create New Task', { + size: 'Large', + weight: 'Bolder', + }), + new TextInput({ id: 'title' }) + .withLabel('Task Title') + .withPlaceholder('Enter task title'), + new TextInput({ id: 'description' }) + .withLabel('Description') + .withPlaceholder('Enter task details') + .withIsMultiline(true), + new ChoiceSetInput( + { title: 'High', value: 'high' }, + { title: 'Medium', value: 'medium' }, + { title: 'Low', value: 'low' } + ) + .withId('priority') + .withLabel('Priority') + .withValue('medium'), + new DateInput({ id: 'due_date' }) + .withLabel('Due Date') + .withValue(new Date().toISOString().split('T')[0]), + new ActionSet( + new ExecuteAction({ title: 'Create Task' }) + .withData({ action: 'create_task' }) + .withAssociatedInputs('auto') + .withStyle('positive') + ) + ); +} +``` + +# [Python](#tab/python) + +```python +from datetime import datetime +from microsoft_teams.cards import ( + AdaptiveCard, TextBlock, ActionSet, ExecuteAction, + Choice, ChoiceSetInput, DateInput, TextInput, +) + +def create_task_form_card(): + return AdaptiveCard( + schema="http://adaptivecards.io/schemas/adaptive-card.json", + body=[ + TextBlock(text="Create New Task", weight="Bolder", size="Large"), + TextInput(id="title") + .with_label("Task Title") + .with_placeholder("Enter task title"), + TextInput(id="description") + .with_label("Description") + .with_placeholder("Enter task details") + .with_is_multiline(True), + ChoiceSetInput(choices=[ + Choice(title="High", value="high"), + Choice(title="Medium", value="medium"), + Choice(title="Low", value="low"), + ]).with_id("priority").with_label("Priority").with_value("medium"), + DateInput(id="due_date") + .with_label("Due Date") + .with_value(datetime.now().strftime("%Y-%m-%d")), + ActionSet( + actions=[ + ExecuteAction(title="Create Task") + .with_data({"action": "create_task"}) + .with_associated_inputs("auto") + .with_style("positive") + ] + ), + ], + ) +``` + +--- + ### Send the card +# [C#](#tab/csharp1) + ```csharp teams.OnMessage(async context => { @@ -660,6 +1071,49 @@ teams.OnMessage(async context => }); ``` +# [TypeScript](#tab/typescript1) + +```typescript +import { App } from '@microsoft/teams.apps'; + +// ... + +app.on('message', async ({ send, activity }) => { + const text = activity.text?.toLowerCase() ?? ''; + + if (text.includes('form')) { + await send({ type: 'typing' }); + const card = createTaskFormCard(); + await send(card); + } +}); +``` + +# [Python](#tab/python1) + +```python +from microsoft_teams.api import MessageActivity, TypingActivityInput +from microsoft_teams.apps import ActivityContext + +@app.on_message +async def handle_message(ctx: ActivityContext[MessageActivity]): + text = (ctx.activity.text or "").lower() + + if "form" in text: + await ctx.reply(TypingActivityInput()) + card = create_task_form_card() + await ctx.send(card) +``` + +--- + +## Code samples + +|S.No.|Card| Description|.NET|Node.js|Python|Java|Manifest| +|:--|:--|:--------------------------------------------------------|-----|------------|-----|----------------------------|------| +|1|Bot Cards|This sample shows how to use the Teams SDK to send and handle various card types, including Adaptive Cards with interactive actions, in Microsoft Teams.|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/TeamsSDK/bot-cards/dotnet/bot-cards)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/TeamsSDK/bot-cards/nodejs/bot-cards)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/TeamsSDK/bot-cards/python/bot-cards)|NA|NA| +|2|Card Formatting|This sample demonstrates how to use the `conditionallyEnabled` property with `Action.Execute` to disable action buttons until required inputs are filled.|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/TeamsSDK/bot-cards/dotnet/bot-cards)|[View](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/TeamsSDK/bot-cards/nodejs/bot-cards)|NA|NA|NA| + ## Next step > [!div class="nextstepaction"] From 927f00d3b25509c20a458edea8578688f473b12b Mon Sep 17 00:00:00 2001 From: SirajShaik-MSFT Date: Thu, 23 Apr 2026 15:13:45 +0530 Subject: [PATCH 10/16] Update cards-actions.md --- msteams-platform/task-modules-and-cards/cards/cards-actions.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/msteams-platform/task-modules-and-cards/cards/cards-actions.md b/msteams-platform/task-modules-and-cards/cards/cards-actions.md index 5dce8645e31..cc8c4372299 100644 --- a/msteams-platform/task-modules-and-cards/cards/cards-actions.md +++ b/msteams-platform/task-modules-and-cards/cards/cards-actions.md @@ -6,6 +6,8 @@ ms.topic: conceptual ms.date: 04/22/2026 --- + + # Card actions [!INCLUDE [adaptive-card-redirect](../../includes/adaptive-card-redirect.md)] From 72b59ec7cacef4f8a5e2ae0c5ba4de88a9a2b920 Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Thu, 23 Apr 2026 15:28:23 +0530 Subject: [PATCH 11/16] Update cards-actions.md --- .../cards/cards-actions.md | 79 ++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/msteams-platform/task-modules-and-cards/cards/cards-actions.md b/msteams-platform/task-modules-and-cards/cards/cards-actions.md index 5dce8645e31..5c6fa33f3b3 100644 --- a/msteams-platform/task-modules-and-cards/cards/cards-actions.md +++ b/msteams-platform/task-modules-and-cards/cards/cards-actions.md @@ -3,7 +3,7 @@ title: Adaptive Card actions in Teams SDK description: Learn about Adaptive Card action types such as Action.Execute, Action.OpenUrl, Action.ShowCard, and Action.ToggleVisibility, and how to handle card actions using the Teams SDK. ms.localizationpriority: medium ms.topic: conceptual -ms.date: 04/22/2026 +ms.date: 04/23/2026 --- # Card actions @@ -361,6 +361,83 @@ data["email"] → "john@contoso.com" data["subscribe"] → "true" ``` +# [TypeScript](#tab/typescript) + +The following code shows an example of associating data with card actions in TypeScript: + +```typescript +import { + AdaptiveCard, + TextInput, + ToggleInput, + ActionSet, + ExecuteAction, +} from '@microsoft/teams.cards'; + +function editProfileCard() { + const card = new AdaptiveCard( + new TextInput({ id: 'name' }).withLabel('Name').withValue('John Doe'), + new TextInput({ id: 'email', label: 'Email', value: 'john@contoso.com' }), + new ToggleInput('Subscribe to newsletter').withId('subscribe').withValue('false'), + new ActionSet( + new ExecuteAction({ title: 'Save' }) + .withData({ + action: 'save_profile', + entity_id: '12345', + }) + .withAssociatedInputs('auto') + ) + ); + + return card; +} +``` + +When the user submits the card, the handler receives the input values merged with the action data: + +```text +data.action → "save_profile" +data.entity_id → "12345" +data.name → "John Doe" +data.email → "john@contoso.com" +data.subscribe → "true" +``` + +# [Python](#tab/python) + +The following code shows an example of associating data with card actions in Python: + +```python +from microsoft_teams.cards import AdaptiveCard, ActionSet, ExecuteAction +from microsoft_teams.cards.core import TextInput, ToggleInput + +profile_card = AdaptiveCard( + schema="http://adaptivecards.io/schemas/adaptive-card.json", + body=[ + TextInput(id="name").with_label("Name").with_value("John Doe"), + TextInput(id="email", label="Email", value="john@contoso.com"), + ToggleInput(title="Subscribe to newsletter").with_id("subscribe").with_value("false"), + ActionSet( + actions=[ + ExecuteAction(title="Save") + .with_data({"action": "save_profile", "entity_id": "12345"}) + .with_associated_inputs("auto"), + ] + ), + ], +) +``` + +When the user submits the card, the handler receives the input values merged with the action data: + +```text +data["action"] → "save_profile" +data["entity_id"] → "12345" +data["name"] → "John Doe" +data["email"] → "john@contoso.com" +data["subscribe"] → "true" +``` + # [JSON](#tab/json) The following code shows an example of associating data with card actions in JSON: From 09a4f9acdc22108f0b2b1ec96560f47fb507bb25 Mon Sep 17 00:00:00 2001 From: SirajShaik-MSFT Date: Thu, 23 Apr 2026 15:31:42 +0530 Subject: [PATCH 12/16] Update cards-actions.md --- .../cards/cards-actions.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/msteams-platform/task-modules-and-cards/cards/cards-actions.md b/msteams-platform/task-modules-and-cards/cards/cards-actions.md index cc8c4372299..1bcd51c8ff0 100644 --- a/msteams-platform/task-modules-and-cards/cards/cards-actions.md +++ b/msteams-platform/task-modules-and-cards/cards/cards-actions.md @@ -253,7 +253,7 @@ The following code shows an example of grouping actions in JSON: If you prefer to work with raw JSON, you can deserialize it into the SDK types: -# [C#](#tab/csharp) +# [C#](#tab/csharp2) ```csharp var actionJson = """ @@ -266,7 +266,7 @@ var actionJson = """ var action = OpenUrlAction.Deserialize(actionJson); ``` -# [TypeScript](#tab/typescript) +# [TypeScript](#tab/typescript2) ```typescript import { IOpenUrlAction } from '@microsoft/teams.cards'; @@ -278,7 +278,7 @@ const actionJson = { } as const satisfies IOpenUrlAction; ``` -# [Python](#tab/python) +# [Python](#tab/python2) ```python action_json = { @@ -296,7 +296,7 @@ action_json = { You can send a card and have it be associated with specific data. Set the `data` value to be sent back to the client so you can associate it with a particular entity. -# [C#](#tab/csharp) +# [C#](#tab/csharp3) The following code shows an example of associating data with card actions in C#: @@ -363,7 +363,7 @@ data["email"] → "john@contoso.com" data["subscribe"] → "true" ``` -# [JSON](#tab/json) +# [JSON](#tab/json2) The following code shows an example of associating data with card actions in JSON: @@ -670,7 +670,7 @@ Universal Action submissions are delivered to your bot as `invoke` activities na Use the `OnAdaptiveCardAction` handler to process card actions: -# [C#](#tab/csharp) +# [C#](#tab/csharp4) ```csharp using System.Text.Json; @@ -746,7 +746,7 @@ teams.OnAdaptiveCardAction(async context => }); ``` -# [TypeScript](#tab/typescript) +# [TypeScript](#tab/typescript3) ```typescript import { @@ -817,7 +817,7 @@ app.on('card.action', async ({ activity, send }) => { }); ``` -# [Python](#tab/python) +# [Python](#tab/python3) ```python from microsoft_teams.api import ( @@ -896,7 +896,7 @@ The following example shows a complete card with input fields and an action hand ### Build the card -# [C#](#tab/csharp) +# [C#](#tab/csharp5) ```csharp using Microsoft.Teams.Cards; @@ -965,7 +965,7 @@ private static AdaptiveCard CreateTaskFormCard() } ``` -# [TypeScript](#tab/typescript) +# [TypeScript](#tab/typescript4) ```typescript import { @@ -1012,7 +1012,7 @@ function createTaskFormCard() { } ``` -# [Python](#tab/python) +# [Python](#tab/python4) ```python from datetime import datetime From 4ae1240919bc667ab1c66c93e0537224c530954a Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Thu, 23 Apr 2026 16:54:04 +0530 Subject: [PATCH 13/16] Update cards-actions.md --- .../cards/cards-actions.md | 60 +++++++++---------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/msteams-platform/task-modules-and-cards/cards/cards-actions.md b/msteams-platform/task-modules-and-cards/cards/cards-actions.md index c0abc79b735..caba3713d99 100644 --- a/msteams-platform/task-modules-and-cards/cards/cards-actions.md +++ b/msteams-platform/task-modules-and-cards/cards/cards-actions.md @@ -35,7 +35,7 @@ The SDK provides builder helpers that abstract the underlying JSON. You can crea `Action.Execute` is the recommended action type for server-side processing. When a user selects an Execute action, the input values and any configured data are sent to your bot as a `card.action` activity. -# [C#](#tab/csharp) +# [C#](#tab/csharp1) The following code shows an example of an `Action.Execute` action in C#: @@ -56,7 +56,7 @@ var action = new ExecuteAction }; ``` -# [TypeScript](#tab/typescript) +# [TypeScript](#tab/typescript1) The following code shows an example of an `Action.Execute` action in TypeScript: @@ -68,7 +68,7 @@ const action = new ExecuteAction({ title: 'Submit Feedback' }) .withAssociatedInputs('auto'); ``` -# [Python](#tab/python) +# [Python](#tab/python1) The following code shows an example of an `Action.Execute` action in Python: @@ -80,7 +80,7 @@ action = ExecuteAction(title="Submit Feedback") \ .with_associated_inputs("auto") ``` -# [JSON](#tab/json) +# [JSON](#tab/json1) The following code shows an example of an `Action.Execute` action in JSON: @@ -104,7 +104,7 @@ The following code shows an example of an `Action.Execute` action in JSON: > [!NOTE] > When using `Action.OpenUrl`, make sure to include the domain of the target URL in the `validDomains` section of your app manifest. If the domain isn't listed, Teams displays the message **URL may lead to untrusted content**. -# [C#](#tab/csharp) +# [C#](#tab/csharp2) The following code shows an example of an `Action.OpenUrl` action in C#: @@ -117,7 +117,7 @@ var action = new OpenUrlAction("https://adaptivecards.microsoft.com") }; ``` -# [TypeScript](#tab/typescript) +# [TypeScript](#tab/typescript2) The following code shows an example of an `Action.OpenUrl` action in TypeScript: @@ -128,7 +128,7 @@ const action = new OpenUrlAction('https://adaptivecards.microsoft.com') .withTitle('Learn More'); ``` -# [Python](#tab/python) +# [Python](#tab/python2) The following code shows an example of an `Action.OpenUrl` action in Python: @@ -139,7 +139,7 @@ action = OpenUrlAction(url="https://adaptivecards.microsoft.com") \ .with_title("Learn More") ``` -# [JSON](#tab/json) +# [JSON](#tab/json2) The following code shows an example of an `Action.OpenUrl` action in JSON: @@ -157,7 +157,7 @@ The following code shows an example of an `Action.OpenUrl` action in JSON: You can group multiple actions together using `ActionSet` within an Adaptive Card: -# [C#](#tab/csharp) +# [C#](#tab/csharp3) The following code shows an example of grouping actions in C#: @@ -188,7 +188,7 @@ var card = new AdaptiveCard }; ``` -# [TypeScript](#tab/typescript) +# [TypeScript](#tab/typescript3) The following code shows an example of grouping actions in TypeScript: @@ -204,7 +204,7 @@ const actionSet = new ActionSet( ); ``` -# [Python](#tab/python) +# [Python](#tab/python3) The following code shows an example of grouping actions in Python: @@ -221,7 +221,7 @@ action_set = ActionSet( ) ``` -# [JSON](#tab/json) +# [JSON](#tab/json3) The following code shows an example of grouping actions in JSON: @@ -253,7 +253,7 @@ The following code shows an example of grouping actions in JSON: If you prefer to work with raw JSON, you can deserialize it into the SDK types: -# [C#](#tab/csharp) +# [C#](#tab/csharp4) ```csharp var actionJson = """ @@ -266,7 +266,7 @@ var actionJson = """ var action = OpenUrlAction.Deserialize(actionJson); ``` -# [TypeScript](#tab/typescript) +# [TypeScript](#tab/typescript4) ```typescript import { IOpenUrlAction } from '@microsoft/teams.cards'; @@ -278,7 +278,7 @@ const actionJson = { } as const satisfies IOpenUrlAction; ``` -# [Python](#tab/python) +# [Python](#tab/python4) ```python action_json = { @@ -296,7 +296,7 @@ action_json = { You can send a card and have it be associated with specific data. Set the `data` value to be sent back to the client so you can associate it with a particular entity. -# [C#](#tab/csharp) +# [C#](#tab/csharp5) The following code shows an example of associating data with card actions in C#: @@ -363,7 +363,7 @@ data["email"] → "john@contoso.com" data["subscribe"] → "true" ``` -# [TypeScript](#tab/typescript) +# [TypeScript](#tab/typescript5) The following code shows an example of associating data with card actions in TypeScript: @@ -405,7 +405,7 @@ data.email → "john@contoso.com" data.subscribe → "true" ``` -# [Python](#tab/python) +# [Python](#tab/python5) The following code shows an example of associating data with card actions in Python: @@ -440,7 +440,7 @@ data["email"] → "john@contoso.com" data["subscribe"] → "true" ``` -# [JSON](#tab/json) +# [JSON](#tab/json4) The following code shows an example of associating data with card actions in JSON: @@ -495,7 +495,7 @@ The following code shows an example of associating data with card actions in JSO Input controls provide built-in validation. For more information, see the Adaptive Cards [input validation documentation](https://adaptivecards.microsoft.com/?topic=input-validation). -# [C#](#tab/csharp) +# [C#](#tab/csharp6) The following code shows an example of input validation in C#: @@ -554,7 +554,7 @@ private static AdaptiveCard CreateProfileCardWithValidation() } ``` -# [TypeScript](#tab/typescript) +# [TypeScript](#tab/typescript6) The following code shows an example of input validation in TypeScript: @@ -594,7 +594,7 @@ function createProfileCardInputValidation() { } ``` -# [Python](#tab/python) +# [Python](#tab/python6) The following code shows an example of input validation in Python: @@ -623,7 +623,7 @@ def create_profile_card_input_validation(): return card ``` -# [JSON](#tab/json) +# [JSON](#tab/json5) The following code shows an example of input validation in JSON: @@ -747,7 +747,7 @@ Universal Action submissions are delivered to your bot as `invoke` activities na Use the `OnAdaptiveCardAction` handler to process card actions: -# [C#](#tab/csharp) +# [C#](#tab/csharp7) ```csharp using System.Text.Json; @@ -823,7 +823,7 @@ teams.OnAdaptiveCardAction(async context => }); ``` -# [TypeScript](#tab/typescript) +# [TypeScript](#tab/typescript7) ```typescript import { @@ -894,7 +894,7 @@ app.on('card.action', async ({ activity, send }) => { }); ``` -# [Python](#tab/python) +# [Python](#tab/python7) ```python from microsoft_teams.api import ( @@ -973,7 +973,7 @@ The following example shows a complete card with input fields and an action hand ### Build the card -# [C#](#tab/csharp) +# [C#](#tab/csharp8) ```csharp using Microsoft.Teams.Cards; @@ -1042,7 +1042,7 @@ private static AdaptiveCard CreateTaskFormCard() } ``` -# [TypeScript](#tab/typescript) +# [TypeScript](#tab/typescript8) ```typescript import { @@ -1089,7 +1089,7 @@ function createTaskFormCard() { } ``` -# [Python](#tab/python) +# [Python](#tab/python8) ```python from datetime import datetime @@ -1155,8 +1155,6 @@ teams.OnMessage(async context => ```typescript import { App } from '@microsoft/teams.apps'; -// ... - app.on('message', async ({ send, activity }) => { const text = activity.text?.toLowerCase() ?? ''; From ce443e6a11fb86c0db3e216a478d6be5bb0452d3 Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Thu, 23 Apr 2026 17:18:38 +0530 Subject: [PATCH 14/16] Update cards-actions.md --- .../task-modules-and-cards/cards/cards-actions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/msteams-platform/task-modules-and-cards/cards/cards-actions.md b/msteams-platform/task-modules-and-cards/cards/cards-actions.md index caba3713d99..ef946c29a8a 100644 --- a/msteams-platform/task-modules-and-cards/cards/cards-actions.md +++ b/msteams-platform/task-modules-and-cards/cards/cards-actions.md @@ -1134,7 +1134,7 @@ def create_task_form_card(): ### Send the card -# [C#](#tab/csharp1) +# [C#](#tab/csharp9) ```csharp teams.OnMessage(async context => @@ -1150,7 +1150,7 @@ teams.OnMessage(async context => }); ``` -# [TypeScript](#tab/typescript1) +# [TypeScript](#tab/typescript9) ```typescript import { App } from '@microsoft/teams.apps'; @@ -1166,7 +1166,7 @@ app.on('message', async ({ send, activity }) => { }); ``` -# [Python](#tab/python1) +# [Python](#tab/python9) ```python from microsoft_teams.api import MessageActivity, TypingActivityInput From 08914efd9a76ad04a4050d5a8fa69cca3e436e23 Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Thu, 23 Apr 2026 17:25:41 +0530 Subject: [PATCH 15/16] Update link-unfurling.md --- .../messaging-extensions/how-to/link-unfurling.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/msteams-platform/messaging-extensions/how-to/link-unfurling.md b/msteams-platform/messaging-extensions/how-to/link-unfurling.md index 1a31fdcbe1f..4f32925a2f6 100644 --- a/msteams-platform/messaging-extensions/how-to/link-unfurling.md +++ b/msteams-platform/messaging-extensions/how-to/link-unfurling.md @@ -6,7 +6,7 @@ ms.localizationpriority: medium ms.topic: conceptual ms.author: vikasalmal ms.owner: slamba -ms.date: 04/10/2026 +ms.date: 04/23/2026 --- # Link unfurling @@ -366,7 +366,7 @@ To get your app ready for zero install link unfurling, follow these steps: } }, "value":{ - "url":"https://test.test.com/test" + "url":"https://example.com/test" }, "locale":"en-US", "localTimezone":"America/Los_Angeles" From 81aa5986d2f382a37645c49433dc2a30848c8153 Mon Sep 17 00:00:00 2001 From: v-nikitach Date: Tue, 28 Apr 2026 14:56:35 +0530 Subject: [PATCH 16/16] Update cards-actions.md --- .../task-modules-and-cards/cards/cards-actions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/msteams-platform/task-modules-and-cards/cards/cards-actions.md b/msteams-platform/task-modules-and-cards/cards/cards-actions.md index ef946c29a8a..710f829b0a9 100644 --- a/msteams-platform/task-modules-and-cards/cards/cards-actions.md +++ b/msteams-platform/task-modules-and-cards/cards/cards-actions.md @@ -3,7 +3,7 @@ title: Adaptive Card actions in Teams SDK description: Learn about Adaptive Card action types such as Action.Execute, Action.OpenUrl, Action.ShowCard, and Action.ToggleVisibility, and how to handle card actions using the Teams SDK. ms.localizationpriority: medium ms.topic: conceptual -ms.date: 04/23/2026 +ms.date: 04/28/2026 --- @@ -12,7 +12,7 @@ ms.date: 04/23/2026 [!INCLUDE [adaptive-card-redirect](../../includes/adaptive-card-redirect.md)] -Adaptive Cards support interactive elements through actions—buttons, links, and input submission triggers that respond to user interaction. You can use these to collect form input, trigger workflows, open URLs, and more. +Adaptive Cards support interactive elements through actions buttons, links, and input submission triggers that respond to user interaction. You can use these to collect form input, trigger workflows, open URLs, and more. The Teams SDK provides builder helpers and server-side handlers that simplify working with card actions. The following action types are supported: