A reference guide for building AI agents: every method, how to authenticate, and the permissions each one needs.
The Microsoft Teams API is how an app or AI agent works with Microsoft Teams: listing teams and channels, reading and posting channel messages, reading chats and their messages, and managing team members. Access is granted through a Microsoft Entra app and a set of Microsoft Graph permissions, either acting as a signed-in user or acting as the app itself, and an agent reaches only the teams, channels, and chats those permissions allow. Microsoft Graph can also push a change to a notification URL when a message is created, updated, or deleted.
How an app or AI agent connects to Microsoft Teams determines what it can reach. Teams is part of Microsoft Graph, so an agent connects through a Microsoft Entra app registration and the Graph permissions it is granted.
Teams is part of Microsoft Graph, which answers at https://graph.microsoft.com. The generally available surface is the v1.0 endpoint; a separate beta endpoint carries newer, unstable features.
Microsoft's first-party MCP server translates natural-language requests into read-only Microsoft Graph calls, honoring the caller's roles, granted permissions, and throttling limits. It is in public preview and currently focuses on Microsoft Entra identity and directory read scenarios rather than full Teams messaging.
An app creates a subscription for a channel, a chat, or a whole tenant, and Microsoft Graph posts each create, update, or delete to a notification URL. Notifications can carry the encrypted message payload when an encryption certificate is supplied.
A delegated token acts on behalf of a signed-in user, so the app can do only what that user can do. Posting channel and chat messages is supported only this way, through ChannelMessage.Send and ChatMessage.Send.
An application token acts as the app with no user present, granted by an administrator. It suits background automation that reads across a tenant, but it cannot post new channel or chat messages, since live sending is delegated only.
Resource-specific consent grants an application permission scoped to a single team or chat rather than the whole tenant, through permissions whose names end in .Group or .Chat, such as ChannelMessage.Read.Group. A team owner consents when the app is installed.
The Teams part of Microsoft Graph is split into areas an agent can act on, such as teams, channels, channel messages, chats, and members. Each area has its own methods and its own permissions, and some grant access to far more than others.
List all teams in an organization, list the teams a user has joined, read a single team, and create a team from a Microsoft 365 group.
List the channels in a team, read a single channel, and create a new channel.
List the messages in a channel, read a single message, post a new message, and reply to a message.
List a user's chats, read a single chat, list the messages in a chat, and send a chat message.
List the members of a team, add a member, update a member's role, and remove a member.
Filter by method, access, or permission, or search any path. Select a row for version detail, rate limits, the related webhook event, and the source.
| Method | Endpoint | What it does | Access | Permission | Version | |
|---|---|---|---|---|---|---|
TeamsList all teams in an organization, list the teams a user has joined, read a single team, and create a team from a Microsoft 365 group.4 | ||||||
| GET | /teams | List all teams in an organization. | read | Team.ReadBasic.All | Current | |
Returns only id, displayName, description, and visibility; other properties come back null. Use Get team for the rest. Same permission for delegated and application. Acts onteam Permission (capability) Team.ReadBasic.AllVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /me/joinedTeams | List the teams that the signed-in user has joined. | read | Team.ReadBasic.All | Current | |
This route applies only to Microsoft Teams, not Microsoft 365 groups in general. Delegated only. Acts onteam Permission (capability) Team.ReadBasic.AllVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /teams/{team-id} | Get a single team's properties and settings. | read | Team.ReadBasic.All | Current | |
Reading full settings needs TeamSettings.Read.All. The application form TeamSettings.Read.Group uses resource-specific consent, where an app is granted access to one team at a time rather than all of them. Acts onteam Permission (capability) Team.ReadBasic.AllVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /groups/{group-id}/team | Create a team from an existing Microsoft 365 group. | write | Group.ReadWrite.All | Current | |
Every team is backed by a Microsoft 365 group, so a team is created by adding a team to a group that has at least one owner. A newly made group can return 404 until it replicates, so a retry is expected. Acts onteam Permission (capability) Group.ReadWrite.AllVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
ChannelsList the channels in a team, read a single channel, and create a new channel.3 | ||||||
| GET | /teams/{team-id}/channels | List the channels in a team. | read | Channel.ReadBasic.All | Current | |
Private and shared channels appear only to members. The application form ChannelSettings.Read.Group uses resource-specific consent, scoped to one team. Acts onchannel Permission (capability) Channel.ReadBasic.AllVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /teams/{team-id}/channels/{channel-id} | Get a single channel. | read | Channel.ReadBasic.All | Current | |
Reading channel settings beyond the basic fields needs ChannelSettings.Read.All. The application form ChannelSettings.Read.Group uses resource-specific consent. Acts onchannel Permission (capability) Channel.ReadBasic.AllVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /teams/{team-id}/channels | Create a channel in a team. | write | Channel.Create | Current | |
The application form Channel.Create.Group uses resource-specific consent, scoped to one team rather than the whole tenant. Acts onchannel Permission (capability) Channel.CreateVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Channel messagesList the messages in a channel, read a single message, post a new message, and reply to a message.4 | ||||||
| GET | /teams/{team-id}/channels/{channel-id}/messages | List the messages in a channel, without their replies. | read | ChannelMessage.Read.All | Current | |
Returns up to 20 messages per page, extendable to 50; use $expand=replies for replies. The application form ChannelMessage.Read.Group uses resource-specific consent, scoped to one team. Acts onchatMessage Permission (capability) ChannelMessage.Read.AllVersionAvailable since the API’s base version Webhook event channel-messageRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /teams/{team-id}/channels/{channel-id}/messages/{message-id} | Get a single message in a channel. | read | ChannelMessage.Read.All | Current | |
The application form ChannelMessage.Read.Group uses resource-specific consent, scoped to one team. Acts onchatMessage Permission (capability) ChannelMessage.Read.AllVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /teams/{team-id}/channels/{channel-id}/messages | Post a new message to a channel. | write | ChannelMessage.Send | Current | |
Sending a message is supported only as a signed-in user with the delegated ChannelMessage.Send permission. The only application permission here is Teamwork.Migrate.All, which is for importing past messages, not posting new ones. Acts onchatMessage Permission (capability) ChannelMessage.SendVersionAvailable since the API’s base version Webhook event channel-messageRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /teams/{team-id}/channels/{channel-id}/messages/{message-id}/replies | Reply to a message in a channel. | write | ChannelMessage.Send | Current | |
As with posting a new message, replying is delegated only. The application permission Teamwork.Migrate.All is for migration, not live replies. Acts onchatMessage Permission (capability) ChannelMessage.SendVersionAvailable since the API’s base version Webhook event channel-messageRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Chats & chat messagesList a user's chats, read a single chat, list the messages in a chat, and send a chat message.4 | ||||||
| GET | /me/chats | List the chats the signed-in user is part of. | read | Chat.ReadBasic | Current | |
Chat.ReadBasic returns the chat list without message content; Chat.Read adds messages. The /chats route lists the signed-in user's chats; the application form uses Chat.ReadBasic.All on /users/{id}/chats. Acts onchat Permission (capability) Chat.ReadBasicVersionAvailable since the API’s base version Webhook event chat-messageRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /chats/{chat-id} | Get a single chat. | read | Chat.ReadBasic | Current | |
The application form Chat.ReadBasic.All can read any chat in the tenant, so it reaches far more than the delegated form, which sees only the signed-in user's chats. Acts onchat Permission (capability) Chat.ReadBasicVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /chats/{chat-id}/messages | List the messages in a chat. | read | Chat.Read | Current | |
Reading message content needs Chat.Read, not the lighter Chat.ReadBasic. The application form is Chat.Read.All across the tenant. Acts onchatMessage Permission (capability) Chat.ReadVersionAvailable since the API’s base version Webhook event chat-messageRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /chats/{chat-id}/messages | Send a message in an existing chat. | write | ChatMessage.Send | Current | |
Sending is delegated only with ChatMessage.Send; this method cannot create a new chat, only post to an existing one. The application permission Teamwork.Migrate.All is for migration, not live sending. Acts onchatMessage Permission (capability) ChatMessage.SendVersionAvailable since the API’s base version Webhook event chat-messageRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
MembersList the members of a team, add a member, update a member's role, and remove a member.4 | ||||||
| GET | /teams/{team-id}/members | List the members of a team. | read | TeamMember.Read.All | Current | |
The application form TeamMember.Read.Group uses resource-specific consent, scoped to one team. Acts onconversationMember Permission (capability) TeamMember.Read.AllVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /teams/{team-id}/members | Add a member to a team. | write | TeamMember.ReadWrite.All | Current | |
The application form TeamMember.ReadWrite.Group uses resource-specific consent, scoped to one team. Acts onconversationMember Permission (capability) TeamMember.ReadWrite.AllVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /teams/{team-id}/members/{membership-id} | Update a member's role in a team, such as making a member an owner. | write | TeamMember.ReadWrite.All | Current | |
Changing a member to owner grants them control over the team. The application form TeamMember.ReadWrite.Group uses resource-specific consent. Acts onconversationMember Permission (capability) TeamMember.ReadWrite.AllVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /teams/{team-id}/members/{membership-id} | Remove a member from a team. | write | TeamMember.ReadWrite.All | Current | |
The application form TeamMember.ReadWrite.Group uses resource-specific consent, scoped to one team. Acts onconversationMember Permission (capability) TeamMember.ReadWrite.AllVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Microsoft Graph can notify an app or AI agent when a message is created, updated, or deleted in a channel or chat, instead of the app repeatedly asking. The agent creates a subscription for the chosen resource, and Graph posts each change to a notification URL.
| Event | What it signals | Triggered by |
|---|---|---|
chatMessage (channel) | Fires when a message or reply is created, updated, or deleted in a channel. An app subscribes to /teams/{team-id}/channels/{channel-id}/messages, or to /teams/getAllMessages for every channel in the tenant. | /teams/{team-id}/channels/{channel-id}/messages/teams/{team-id}/channels/{channel-id}/messages/teams/{team-id}/channels/{channel-id}/messages/{message-id}/replies |
chatMessage (chat) | Fires when a message is created, updated, or deleted in a chat. An app subscribes to /chats/{chat-id}/messages, to /users/{user-id}/chats/getAllMessages, or to /chats/getAllMessages for every chat in the tenant. | /me/chats/chats/{chat-id}/messages/chats/{chat-id}/messages |
Microsoft Graph limits how fast an app or AI agent can call, through a request ceiling measured over a short window that applies across the whole service, with extra service limits for Teams on top.
Microsoft Graph applies a service-wide ceiling of 130,000 requests within any 10-second window for a single app across all tenants, and Teams adds its own service limits on top. Going over returns 429 Too Many Requests with a Retry-After header that gives the number of seconds to wait, and the x-ms-throttle-scope and x-ms-throttle-limit-percentage headers report what was throttled and how close the app is to the limit. Polling a resource for changes is allowed only once per day; for anything more frequent, a change-notification subscription should be used instead.
List endpoints page with an @odata.nextLink URL in the response, which should be followed until it is absent rather than built by hand. Channel messages return up to 20 per page, extendable to 50 with $top, and replies can be pulled in with $expand=replies.
Requests and responses are JSON. Message bodies can be plain text or HTML, and a channel message can carry inline images and other hosted content. Listing a single channel message with $expand=replies can return up to 1,000 replies per page.
The status codes an agent should handle, and what to do about each.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 401 | Unauthorized | The access token is missing, invalid, or expired. | Acquire a fresh token from Microsoft Entra and send it in the Authorization header. |
| 403 | Forbidden | The token is valid but lacks the permission the call needs, or an administrator has not consented to it. Trying to post a channel or chat message with an application token also lands here, since live sending is delegated only. | Grant the required Graph permission, get admin consent, or switch to a delegated token for sending messages. |
| 404 | Not Found | The team, channel, chat, or message does not exist, or the token cannot see it. A team created less than 15 minutes ago can also return 404 while the underlying group replicates. | Confirm the id and the token's access, and for a brand-new team, retry after a short delay. |
| 409 | Conflict | The request conflicts with the current state. When importing a message, a createdDateTime that already exists in the target channel down to the millisecond returns this. | Adjust the conflicting value, such as the createdDateTime, and retry. |
| 429 | Too Many Requests | A throttling limit was exceeded, either the service-wide Microsoft Graph ceiling or a Teams service limit. | Wait for the number of seconds in the Retry-After header before sending the request again. |
| 503 | Service Unavailable | The service is temporarily unavailable or overloaded. | Back off and retry, honoring the Retry-After header when it is present. |
Microsoft Graph serves Teams under the named endpoint v1.0, the generally available surface. It does not use dated version strings; changes ship continuously and are recorded in the Graph changelog.
Microsoft Graph made channel-level Teams app management generally available on v1.0, letting an app list, get, enable, and disable apps within a single channel. The same update added @odata.nextLink pagination to the channel-listing methods to support larger channel counts, and removed the payment-model parameters and guidance from the Teams export APIs.
The replyWithQuote method on the chatMessage resource became generally available on v1.0, letting an app reply to one or more existing chat messages while quoting them.
The v1.0 endpoint is the generally available, production surface of Microsoft Graph, including the Teams resources for teams, channels, channel messages, chats, chat messages, and members. Microsoft Graph does not use dated version strings; new and changing features are tracked in the Microsoft Graph changelog, and unstable features live on the separate beta endpoint until they graduate to v1.0.
A separate beta endpoint carries newer, unstable features and should not be used in production.
Microsoft Graph changelog ↗Bollard AI sits between a team's AI agents and Microsoft Teams. Grant each agent exactly the access it needs, read or write, channel by channel, and every call is checked and logged.