Declarative agents can read documents, cite policies, and generate images, but ask one “What’s left on my onboarding checklist?” and it has no idea. API Plugins fix that by giving your agent the ability to call live backend APIs and return real user data in real time, crossing from knowledge into action.
What Are API Plugins?
In the declarative agent world, actions are how agents do things: call APIs, retrieve live data, trigger workflows. API Plugins are one of the primary ways to add actions to your agent.
The concept is straightforward: you describe a REST API with a standard OpenAPI specification, wrap it in a plugin manifest, and register it with your agent. Copilot reads the descriptions in your manifest and decides when to call each endpoint. You don’t write routing logic; the model figures it out based on what the user is asking.
That last part is worth repeating: the model decides when to call your API based on natural language descriptions you provide. No intent matching. No dialog trees. Just well-written descriptions and a language model that understands context.
The Three Parts of an API Plugin
Every API plugin consists of three pieces:
-
An OpenAPI Spec: A standard YAML or JSON file describing your endpoints, parameters, and response shapes. This is the contract your API exposes to the world.
-
A Plugin Manifest: A JSON file that tells Copilot how to use the API. It maps operations to functions, describes when to use each function in natural language, and defines response semantics.
-
The Actual API: Your backend service, whether that is Azure Functions, Express, ASP.NET, or a third-party SaaS. Copilot doesn’t care about the implementation. It only cares about the OpenAPI contract.
If you work with APIs, you should always document them with an OpenAPI specification. It is the industry standard for describing HTTP APIs, and it is exactly what the declarative agent platform uses to understand your endpoints. If your API already has an OpenAPI spec, you are halfway to a working plugin.
Writing the OpenAPI Spec
For our Zava Insurance scenario, the backend exposes two endpoints:
GET /api/onboarding/status: Returns the authenticated user’s onboarding progress (a percentage and a list of tasks with their completion status).GET /api/onboarding/tasks/{taskId}: Returns detailed info about a specific task (instructions, due date, and a help link).
Here is the OpenAPI spec for this API:
openapi: 3.0.3
info:
title: Zava Insurance Onboarding API
description: API for tracking employee onboarding progress at Zava Insurance.
version: 1.0.0
servers:
- url: https://api.zavainsurance.com
description: Production server
paths:
/api/onboarding/status:
get:
operationId: getOnboardingStatus
summary: Get onboarding status
description: >-
Returns the overall onboarding progress percentage and a list of
tasks with their completion status for the authenticated user.
responses:
'200':
description: Onboarding progress for the authenticated user
content:
application/json:
schema:
type: object
properties:
progress:
type: integer
description: Overall onboarding completion percentage
tasks:
type: array
items:
type: object
properties:
taskId:
type: string
name:
type: string
status:
type: string
enum: [completed, in_progress, not_started]
/api/onboarding/tasks/{taskId}:
get:
operationId: getTaskDetails
summary: Get task details
description: >-
Returns detailed instructions, due date, and a help link
for a specific onboarding task.
parameters:
- name: taskId
in: path
required: true
description: The unique identifier of the onboarding task
schema:
type: string
responses:
'200':
description: Detailed information about the onboarding task
content:
application/json:
schema:
type: object
properties:
taskId:
type: string
name:
type: string
instructions:
type: string
dueDate:
type: string
format: date
helpUrl:
type: string
format: uri
security:
- OAuth2:
- openid
securitySchemes:
OAuth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://login.microsoftonline.com/common/oauth2/v2.0/authorize
tokenUrl: https://login.microsoftonline.com/common/oauth2/v2.0/token
scopes:
openid: Sign in
The critical thing in your OpenAPI spec is the description fields. These are not just documentation for human developers; they are what the model reads to understand your API. For example, the operation description for getOnboardingStatus says:
“Returns the overall onboarding progress percentage and a list of tasks with their completion status for the authenticated user.”
That is what Copilot uses to decide: “The user asked about their checklist, this endpoint sounds right.”
Write your OpenAPI descriptions as if you are explaining the endpoint to a smart colleague who has never seen your codebase. Be specific about what the endpoint returns and when it should be used. Vague descriptions lead to vague behavior.
The Plugin Manifest: Where description_for_model Lives
Now for the new piece: apiPlugin.json. This is where you tell Copilot everything it needs to know about your plugin. Here is what a minimal example looks like:
{
"schema_version": "v2.4",
"name_for_human": "Onboarding Status",
"namespace": "OnboardingStatus",
"description_for_human": "Check your onboarding progress and task details.",
"description_for_model": "Use this plugin when the user asks about their onboarding progress, task checklist, completed items, or pending onboarding steps. Do not use this plugin for general HR policy questions.",
"functions": [
{
"name": "getOnboardingStatus",
"description": "Returns the overall onboarding progress percentage and a list of tasks with their completion status."
},
{
"name": "getTaskDetails",
"description": "Returns detailed instructions, due date, and help link for a specific onboarding task."
}
],
"runtimes": [
{
"type": "OpenApi",
"auth": {
"type": "OAuthPluginVault",
"reference_id": "${{OAUTH2AUTHCODE_CONFIGURATION_ID}}"
},
"spec": {
"url": "apiSpecificationFiles/openapi.yaml"
},
"run_for_functions": [
"getOnboardingStatus",
"getTaskDetails"
]
}
]
}
A few things to note about this manifest:
description_for_modelis the most important field. It tells the language model when to reach for this plugin. A good description is specific, includes positive triggers (“when the user asks about onboarding progress”), and negative boundaries (“do not use for general HR policy questions”).functionsmaps directly to your OpenAPI operations by name. Each function only needs anameand adescription. Parameters and return types are inferred from the OpenAPI spec, so you do not need to redeclare them here.run_for_functionsin the runtime object binds specific functions to the runtime. This tells Copilot which functions are served by this OpenAPI endpoint. You can also use["*"]as a wildcard to match all functions, which avoids maintaining the list manually as you add new operations.
A poorly written description_for_model is the number one reason API plugins behave unpredictably. If the model calls your API at the wrong time, or never calls it, the description is almost always the culprit. Invest time here.
Authentication: OAuth and API Keys
Real APIs need authentication. The plugin manifest supports several auth patterns. For a complete guide to all supported schemes (OAuth 2.0, Entra ID SSO, API key, and anonymous), see the authentication documentation on Microsoft Learn.
OAuth 2.0 (recommended for user-specific data):
{
"auth": {
"type": "OAuthPluginVault",
"reference_id": "${{OAUTH2AUTHCODE_CONFIGURATION_ID}}"
}
}
This is what the onboarding API uses. The OAuth client registration happens in the Teams Developer Portal under Tools > OAuth client registration. You provide your authorization URL, token URL, scopes, client ID, and client secret. The portal generates a registration ID that you reference in your manifest. Once registered, the platform handles all user-facing consent flows and token refreshes for you; your API just receives a valid bearer token on every request.
If you use the M365 Agents Toolkit, this registration can be automated through the m365agents.yml configuration file. The relevant section looks like this:
provision:
- uses: oauth/register
with:
name: oAuth2AuthCode
flow: authorizationCode
appId: ${{TEAMS_APP_ID}}
clientId: ${{AAD_APP_CLIENT_ID}}
clientSecret: ${{SECRET_AAD_APP_CLIENT_SECRET}}
apiSpecPath: ./appPackage/apiSpecificationFiles/openapi.yaml
writeToEnvironmentFile:
configurationId: OAUTH2AUTHCODE_CONFIGURATION_ID
During provisioning, the toolkit registers the OAuth client in the Developer Portal and writes the resulting configuration ID back as OAUTH2AUTHCODE_CONFIGURATION_ID so the ${{OAUTH2AUTHCODE_CONFIGURATION_ID}} placeholder in your plugin manifest resolves automatically.
API Key (for shared or service-level access):
{
"auth": {
"type": "ApiKeyPluginVault",
"reference_id": "${{APIKEY_REGISTRATION_ID}}"
}
}
Use this when the API does not need user-specific auth: think weather data, public datasets, or internal services with a shared key. You register the API key in the Teams Developer Portal under Tools > API key registration, where you provide the secret, base URL, and tenant restrictions. The portal generates a registration ID that you reference in your manifest.
The same automation is available in m365agents.yml for API keys:
provision:
- uses: apiKey/register
with:
name: apiKey
primaryClientSecret: ${{SECRET_API_KEY}}
appId: ${{TEAMS_APP_ID}}
apiSpecPath: ./appPackage/apiSpecificationFiles/openapi.yaml
writeToEnvironmentFile:
registrationId: APIKEY_REGISTRATION_ID
For most enterprise scenarios involving user data, OAuth is the right choice. API keys are great for prototyping or when you are integrating with third-party APIs that only support key-based auth.
Registering the Plugin in Your Agent
With the manifest ready, registration is a one-liner in declarativeAgent.json:
{
"actions": [
{
"id": "onboardingStatusPlugin",
"file": "apiPlugin.json"
}
]
}
That is it. Save. Redeploy. Your agent now has access to live onboarding data.
Add one or two scenarios from your API plugin to the agent’s conversation starters. For example, a starter like “What’s left on my onboarding checklist?” or “Show me details for a specific onboarding task” helps users immediately understand what the agent can do with live data.
Seeing It in Action
Asking the agent: “What’s left on my onboarding checklist?”
It recognizes this as an onboarding status question (thanks, description_for_model!), calls the API, and responds:
“You’re 65% through your onboarding! Here’s what’s still pending:”
- Laptop setup: Completed
- Entra ID account: Completed
- Compliance training: In progress, due March 5
- Benefits enrollment: Not started, due March 10
- Meet your buddy: Not started
“Would you like details on any of these tasks?”
That is live data from the API, rendered conversationally. Following up with “Tell me more about the compliance training”, it calls getTaskDetails and returns specific instructions with a link to the training portal.
What API Plugins Give Your Agent
A plugin manifest, an OpenAPI spec, and a few lines of agent configuration gave us:
- Live, user-specific data: The agent can answer “what is my status” questions with real-time data from your backend, not just static documents
- Natural language routing: Copilot decides when to call your API based on descriptions you write. No intent matching, no dialog trees, no routing code
- Seamless orchestration: The agent automatically switches between knowledge sources and API calls within the same conversation, without any custom logic
- Standard API contracts: If your API already has an OpenAPI spec, the integration effort is minimal. The plugin manifest is the only new artifact
- Enterprise-grade auth: OAuth 2.0 and API key support means your existing authentication infrastructure works out of the box
- Zero orchestrator code: You did not build a state machine or write routing logic. You described your API, registered it, and let the platform handle the rest
The shift from “the agent knows about policies” to “the agent knows my onboarding status” is what turns a helpful assistant into a genuinely useful workplace tool.
Resources
- Plugins for Declarative Agents: Microsoft Learn: Official documentation for API plugin development
- What Is OpenAPI: The industry standard for describing HTTP APIs
- OpenAPI Specification: The full OpenAPI specification reference
- Build Declarative Agents: Microsoft Learn: Your starting point for building declarative agents
- Authentication in API Plugins: Microsoft Learn: OAuth, API key, and other auth patterns
- Plugin Manifest v2.4 Schema: Microsoft Learn: Latest API plugin manifest schema reference
Have questions or want to share what you're building? Connect with me on LinkedIn or check out more on The Manifest.