iTranslated by AI
Turning Existing APIs into Copilot for Microsoft 365 Plugins
Introduction
As of April 15, 2024, it is now possible to create API-based Microsoft Teams message extensions.
Previously, Teams message extensions could only be created using the Microsoft Bot Framework. With this new feature, you can turn existing APIs into Teams apps without additional development. Furthermore, Teams message extensions can also serve as plugins for Copilot for Microsoft 365. This means your existing APIs can be utilized directly from Copilot for Microsoft 365, which is a very powerful update.
In this article, I will introduce the steps to make an existing API callable from Copilot for Microsoft 365.
Implementation Steps
I will use the following API as a sample.
To create a Teams app, you need the following three files, which can be generated via the Developer Portal:
- App manifest file
- Transparent icon file (PNG format)
- Full-color icon file (PNG format)
For API-based Teams message extensions, the following additional files are required:
- OpenAPI specification for the API (JSON or YAML format)
- Response rendering template
Preparing Additional Files
OpenAPI specifications can be enabled by adding the following libraries:
| Framework | Available Library |
|---|---|
| ASP.NET Core Web API | Swashbuckle.AspNetCore |
| Azure Functions | Microsoft.Azure.WebJobs.Extensions.OpenApi |
Although Microsoft documentation states that versions 2.0 and 3.0.x are supported, I will use 3.0.x as I encountered issues reading the 2.0 specification.
public static IServiceCollection AddOpenAPI(this IServiceCollection services)
{
_ = services.AddSingleton<IOpenApiConfigurationOptions>(provider => new OpenApiConfigurationOptions()
{
Info = new OpenApiInfo()
{
Version = "1.0.0",
Title = "Zenn Search API"
},
Servers = DefaultOpenApiConfigurationOptions.GetHostNames(),
OpenApiVersion = OpenApiVersionType.V3,
IncludeRequestingHostName = true,
ForceHttps = false,
ForceHttp = false,
});
return services;
}
If you cannot modify the code, you must create the OpenAPI specification manually.
The response rendering template is a JSON file containing two types of Adaptive Cards. You can paste the Adaptive Cards created using the designer.
Setting Up in the Developer Portal
Sign in to the Developer Portal (https://dev.teams.microsoft.com) for Microsoft Teams.
Click Apps - New app, enter the app name, and click Add.

Enter the app information under Basic information. Since this is used for calls from Copilot for Microsoft 365, ensure the description is detailed. After entering the information, click Save.

Click Message extensions under App Feature. Select API for the Message extension type, upload the OpenAPI specification, and click Save.

A dialog will appear indicating success; click Got it.

Click Add, select the API, and click Next.

Upload the response rendering template, but note that an error will occur at this stage.

You can upload it by temporarily changing the version in the response rendering template to devPreview.
{
- "version": "1.0",
+ "version": "devPreview",
Enter the command information. Please provide detailed descriptions here as well. Click Add.

Click Save.

App configuration is now complete, but you will encounter an error when previewing.

Looking at the error details, it states that the version is incorrect. This is because we changed it earlier.
version | Value "devPreview" does not match constant "1.0".
You cannot change files directly in the Developer Portal. Download the app package, revert the version to 1.0, and re-upload it.
{
- "version": "devPreview",
+ "version": "1.0",
...
Once you preview again, you will be able to add the app.

Configuring Authentication
If your API is accessible anonymously, your setup is complete. If the API requires authentication, additional settings are necessary. API-based Teams message extensions support authentication via secrets and Microsoft Entra ID. Note that secrets only support Bearer tokens. In this case, I am assuming access via an Azure Functions API key, but it cannot be used as-is. To handle this, I will create an Azure API Management instance and use a policy to convert the Bearer token into an X-Functions-Key header.
<policies>
<inbound>
<base />
<set-backend-service id="apim-generated-policy" backend-id="{{backend-id}}" />
<set-header name="X-Functions-Key" exists-action="override">
<value>@(Regex.Match(context.Request.Headers.GetValueOrDefault("Authorization",""), "^Bearer (?<key>.+)$").Groups["key"]?.Value)</value>
</set-header>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Secrets are not recorded in the app manifest file; instead, they are configured in the Developer Portal and referenced from the app manifest file. In the Developer Portal, click Tools - API key registration - Create an API Key.

Click Add secret, enter the secret (in this case, the Azure Functions key), and click Save.

Enter the API information and click Save. For the Target Teams app, while Any Teams app is fine during development, it is recommended to set this to Existing Teams app in production.

Copy the Registration ID of the created API key.

Set the Registration ID in the app manifest file. Since this also cannot be set from the Developer Portal, download the app package, modify it, and upload it again.
{
...
"composeExtensions": [
{
"composeExtensionType": "apiBased",
"authorization": {
"authType": "apiSecretServiceAuth",
"apiSecretServiceAuthConfiguration": {
"apiSecretRegistrationId": "{{registration-id}}"
}
},
...
}
]
...
}
Execution Results
First, confirm that it works with just the message extension. Open the extension in a chat, perform a search, and verify that the search results appear.

Next, verify the functionality in Copilot. Enable the extension in the Copilot chat.

Ask a question to Copilot, and verify that it can answer based on the search results.

Conclusion
I have demonstrated that you can integrate existing APIs into Copilot for Microsoft 365 without additional programming. There are some difficult configuration steps and issues with the Developer Portal that I hope will be improved in the future. Please give it a try!
Discussion