Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Important
The code samples in this section are based on v4.6 and later versions of the Bot Framework SDK. If you're looking for documentation for earlier versions, see the Message Extensions - v3 SDK section in the Resources folder of the documentation.
After the user submits the search command, your web service receives a composeExtension/query invoke message that contains a value object with the search parameters. The invoke is triggered by the following conditions:
- As characters are entered into the search box.
initialRunis set to true in your app manifest. For more information, see default query.
This document guides you on how to respond to user requests in the form of cards and previews and the conditions under which Microsoft Teams issues a default query.
The request parameters are found in the value object in the request, which includes the following properties:
| Property name | Purpose |
|---|---|
commandId |
The name of the command invoked by the user, matching one of the commands declared in the app manifest. |
parameters |
Array of parameters. Each parameter object contains the parameter name along with the parameter value provided by the user. |
queryOptions |
Pagination parameters: skip: Skip count for this query count: Number of elements to return. |
protected override async Task<MessagingExtensionResponse> OnTeamsMessagingExtensionQueryAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken)
{
// Code to handle the query.
}
Respond to user requests
When the user performs a query, Microsoft Teams issues a synchronous HTTP request to your service. At that point, your code has five seconds to provide an HTTP response to the request. During this time, your service can perform more lookups, or any other business logic needed to serve the request.
Your service must respond with the results matching the user query. The response must indicate an HTTP status code of 200 OK and a valid application or JSON object with the following properties:
| Property name | Purpose |
|---|---|
composeExtension |
Top-level response envelope. |
composeExtension.type |
Type of response. The following types are supported: result: Displays a list of search results auth: Prompts the user to authenticate config: Prompts the user to set up the message extension message: Displays a plain text message |
composeExtension.attachmentLayout |
Specifies the layout of the attachments. Used for responses of type result. The following types are supported: list: A list of card objects containing thumbnail, title, and text fields grid: A grid of thumbnail images |
composeExtension.attachments |
Array of valid attachment objects. Used for responses of type result. The following types are supported: application/vnd.microsoft.card.thumbnail application/vnd.microsoft.card.hero application/vnd.microsoft.teams.card.o365connector application/vnd.microsoft.card.adaptive |
composeExtension.suggestedActions |
Suggested actions. Used for responses of type auth or config. |
composeExtension.text |
Message to display. Used for responses of type message. |
config response
The config response is the data returned by the server or the app to configure and enable the message extension within the messaging platform. When a user configures the message extension for the first time, a config response is used to prompt the user to set up the message extension and provide any necessary configuration.
The following code snippet shows the config response that appears when the user interacts with the message extension:
{
"composeExtension": {
"suggestedActions": {
"actions": [
{
"type": "openUrl",
"title": "Open url",
"value": "https://<your-tunnel-url>/searchSettings.html?settings="
}
]
},
"type": "config"
},
"responseType": "composeExtension"
}
The config response includes:
- The
valueproperty that contains a URL to open a configuration page in a Teams dialog, which allows users to input necessary details and submit the configuration. Few examples of thevalueproperty are:https://<your-subdomain>.ngrok-free.app/searchSettings.htmlhttps://<your-subdomain>.devtunnels.ms/searchSettings.html.
- The
typefield withincomposeExtensionset toconfig, indicating the nature of this response as a configuration. - The
responseTypethat identifies this response is for thecomposeExtensionof the app.
Initialize the Teams SDK on the configuration page and use authentication.notifySuccess() to send the collected configuration data back to Teams. submitConfig() function demonstrates how to structure and return configuration values after the user completes the setup process.
To complete the message extension configuration flow:
The URL provided in the
valueproperty must host a webpage that opens the URL as a Teams dialog when the message extension configuration is triggered.If authentication is required, the page must use Teams authentication and call
authentication.notifySuccess()upon successful sign-in.After collecting user input, the page must notify Teams of the successful setup by calling
notifySuccess(configData)that sends the configuration values back to Teams:microsoftTeams.app.initialize(); function submitConfig() { const configData = { setting1: "User-selected value", setting2: "Another value" }; microsoftTeams.authentication.notifySuccess(configData); }Once
notifySuccess()is executed, the configuration window automatically closes and the message extension is set up successfully.
auth response type
If your service requires user authentication, the users must sign in before they use the message extension. For more information, see authentication.
message response type
A message response is used when your extension needs to display a plain text message. The message response type doesn't support formatting.
The following code snippet is an example of a message response returned by the app:
return new MessagingExtensionResponse
{
ComposeExtension = new MessagingExtensionResult
{
Type = "message",
Text = "Here is the message you want to show!"
}
};
result response type
The result list is displayed in the Microsoft Teams UI with a preview of each item. The preview is generated in one of the two ways:
- Using the
previewproperty within theattachmentobject. Thepreviewattachment can only be a Hero or a Thumbnail card. - Extracting from the basic
title,text, andimageproperties of theattachmentobject. The basic properties are used only if thepreviewproperty isn't specified.
Note
Message extension search results don't support padding.
Teams supports the following card types:
For the hero or thumbnail card, except for the invoke action, other actions such as button and tap aren't supported in the preview card. For hero and thumbnail cards, you don't need to specify a preview property, a preview is generated by default. To know about cards and learn how to use the thumbnail and hero card types, see what are cards and add cards and card actions.
To send an Adaptive Card or connector card for Microsoft 365 Groups, you must include a preview. The preview property must be a hero or thumbnail card and the respective card is generated as preview. If a preview property isn't specified in the attachment object, a preview isn't generated. For more information, see using connector cards for Microsoft 365 Groups.
Response example
protected override async Task<MessagingExtensionResponse> OnTeamsMessagingExtensionQueryAsync(ITurnContext<IInvokeActivity> turnContext, MessagingExtensionQuery query, CancellationToken cancellationToken)
{
var text = query?.Parameters?[0]?.Value as string ?? string.Empty;
// Searches NuGet for a package.
var obj = JObject.Parse(await (new HttpClient()).GetStringAsync($"https://azuresearch-usnc.nuget.org/query?q=id:{text}&prerelease=true"));
var packages = obj["data"].Select(item => (item["id"].ToString(), item["version"].ToString(), item["description"].ToString()));
// We take every row of the results and wrap them in cards wrapped in in MessagingExtensionAttachment objects.
// The Preview is optional, if it includes a Tap, that will trigger the OnTeamsMessagingExtensionSelectItemAsync event back on this bot.
var attachments = packages.Select(package => new MessagingExtensionAttachment
{
ContentType = HeroCard.ContentType,
Content = new HeroCard { Title = package.Item1 },
Preview = new HeroCard { Title = package.Item1, Tap = new CardAction { Type = "invoke", Value = package } }.ToAttachment()
})
.ToList();
// The list of MessagingExtensionAttachments must we wrapped in a MessagingExtensionResult wrapped in a MessagingExtensionResponse.
return new MessagingExtensionResponse
{
ComposeExtension = new MessagingExtensionResult
{
Type = "result",
AttachmentLayout = "list",
Attachments = attachments
}
};
}
Enable and handle tap actions
When a user selects a result from the message extension search query, the preview card displays the description and the Tap actions that were defined. The Tap action must have the required value property assigned that displays as a Tap button in the card sent.
protected override Task<MessagingExtensionResponse> OnTeamsMessagingExtensionSelectItemAsync(ITurnContext<IInvokeActivity> turnContext, JObject query, CancellationToken cancellationToken)
{
// The Preview card's Tap should have a Value property assigned, this will be returned to the bot in this event.
var (packageId, version, description, projectUrl, iconUrl) = query.ToObject<(string, string, string, string, string)>();
var card = new ThumbnailCard
{
Title = "Card Select Item",
Subtitle = description
};
var attachment = new MessagingExtensionAttachment
{
ContentType = ThumbnailCard.ContentType,
Content = card,
};
return Task.FromResult(new MessagingExtensionResponse
{
ComposeExtension = new MessagingExtensionResult
{
Type = "result",
AttachmentLayout = "list",
Attachments = new List<MessagingExtensionAttachment> { attachment }
}
});
}
Default query
If you set initialRun to true in the manifest, Microsoft Teams issues a default query when the user first opens the message extension. Your service can respond to this query with a set of prepopulated results. This is useful when your search command requires authentication or configuration, displaying recently viewed items, favorites, or any other information that isn't dependent on user input.
The default query has the same structure as any regular user query, except it has a parameter named initialRun that's set to a string value of true, as shown in the following object:
{
"type": "invoke",
"name": "composeExtension/query",
"value": {
"commandId": "searchCmd",
"parameters": [
{
"name": "initialRun",
"value": "true"
}
],
"queryOptions": {
"skip": 0,
"count": 25
}
},
⋮
}
Code sample
| Sample name | Description | .NET | Node.js | Manifest |
|---|---|---|---|---|
| Teams message extension search | This sample demonstrates how to create a message extension in Teams that allows users searches for NuGet packages and retrieve the results as a card. | View | View | View |
| Teams message extension auth and config | This sample demonstrates how to implement authentication in a message extension for Teams, enabling secure access and user-specific interactions. | View | View | View |
Next step
See also
Platform Docs