Microsoft Teams Bot Framework reference

Every Microsoft Teams bot limit, in one table

54documented limits
9groups
2026-08-20last verified

Last verified against Microsoft Learn - Rate limiting for Teams bots

Microsoft publishes the ceilings that govern a Teams bot across half a dozen pages: the rate-limit tables live in the bot documentation, message size in the formatting guide, manifest field lengths in the app manifest schema, member paging in the context APIs, and the org-level caps (team sizes, channel counts) in the Teams admin limits reference. This page pulls the documented numbers into one place, quoted exactly, with the source next to every row.

The limits interact more than the scattered docs suggest. A broadcast that respects the per-thread send window of 7 operations per second can still be throttled by the global ceiling of 50 requests per second per app per tenant. A message that is fine at 60 KB sails past the recommended 80 KB working ceiling once mentions and reactions are counted in UTF-16, and dies at the 100 KB cap with 413 MessageSizeTooBig. An invoke handler that answers in six seconds does not degrade gracefully - Teams retried it twice, told the user "Unable to reach the app", and threw your late answer away. Knowing the numbers before designing the send path is cheaper than discovering them from 429 Throttled responses in production.

Microsoft warns that "the exact values of rate limits are subject to change" and that the published figures "are for estimation only," so treat these tables as design targets rather than contractual guarantees, and implement backoff regardless of how much headroom you believe you have - the handling contract for each ceiling links to the matching entry in the Teams error reference. Each section intro links the error you receive when its ceiling is crossed, and every row cites the Microsoft Learn page it was read from. Everything below is quoted from Microsoft Learn as of the verification date; anything Microsoft does not document - including several numbers that circulate in forum answers - is deliberately not listed here.

Jump to: Per-bot, per-thread rate limits · All-bots-per-thread and global limits · Message size limits · Cards, formatting and incoming webhooks · Response-time windows · App manifest field limits · Conversation member retrieval · Proactive messaging constraints · Teams platform caps that affect bots

Per-bot, per-thread rate limits

The per-bot-per-thread limit "controls the traffic that a agent is allowed to generate in a single conversation," where a conversation is "1:1 between agent and user, a group chat, or a channel in a team." One message to each of a thousand users touches a thousand threads, so "if the application sends one agent message to each user, the thread limit doesn't throttle" - broadcasts are governed by the global ceiling in the next section instead. Exceeding any window returns 429 Throttled with a Retry-After header. Note the docs' caveat that service-level message splitting "results in higher than expected RPS": one long message can count as several operations.

WhatLimitNotesSource
Send to conversation (per bot, per thread)7 per 1s / 8 per 2s / 60 per 30s / 1,800 per 3,600sThe 3,600s/1,800-operation window "applies only if multiple agent messages are sent to a single user."docs ↗
Create conversation (per bot, per thread)7 per 1s / 8 per 2s / 60 per 30s / 1,800 per 3,600sSame windows as sending; relevant to proactive-messaging fan-outs that create 1:1 conversations.docs ↗
Get conversation members (per bot, per thread)14 per 1s / 16 per 2s / 120 per 30s / 3,600 per 3,600sRoster reads get double the send budget. Use paged retrieval; see the conversation members section.docs ↗
Get conversations (per bot, per thread)14 per 1s / 16 per 2s / 120 per 30s / 3,600 per 3,600sApplies to conversation/channel enumeration calls.docs ↗
Legacy TeamsInfo.getMembers / GetMembersAsync (deprecated)5 requests per minute, maximum 10K members per teamBeing deprecated; Microsoft directs bots to paginated member retrieval instead.docs ↗

All-bots-per-thread and global limits

Two more budgets sit above the per-bot table. The per-thread limit for all bots "controls the traffic that all agents are allowed to generate across a single conversation" - a busy channel with several installed bots shares one pool, so your bot can be throttled by a neighbor's chatter. Above that, "the global limit per app per tenant is 50 Requests Per Second (RPS)," the ceiling that actually governs broadcast jobs. The documentation also fixes the retry contract: alongside 429, "error codes 412, 502, and 504 must also be retried" - the handling recipes are in the 412 and 502 entries.

WhatLimitNotesSource
Send to conversation (all bots, per thread)14 per 1s / 16 per 2sShared across every bot installed in the conversation.docs ↗
Create conversation (all bots, per thread)14 per 1s / 16 per 2sShared across every bot installed in the conversation.docs ↗
Get conversation members (all bots, per thread)28 per 1s / 32 per 2sShared read budget for rosters.docs ↗
Get conversations (all bots, per thread)28 per 1s / 32 per 2sShared read budget for conversation enumeration.docs ↗
Global limit per app per tenant50 requests per second"The total number of agent messages per second must not cross the thread limit." Pace broadcasts below this.docs ↗
Status codes to retry429 (honor Retry-After), plus 412, 502, 504 with exponential backoff"Using an exponential backoff with a random jitter is the recommended way to handle 429s."docs ↗

Message size limits

The bot message ceiling is documented in the message-formatting guide, not the rate-limit page, and it is bigger than the old 28 KB folklore: 100 KB, with an explicit engineering margin. Because the measurement covers the serialized activity - "the message itself (text, image links, etc.), @-mentions, and reactions encoded as UTF-16" - the visible text underestimates the real payload. Overflow is rejected with 413 MessageSizeTooBig, which is documented as non-retryable: the payload must shrink. Machine-generated Adaptive Cards are the usual offender; cap list lengths at generation time.

WhatLimitNotesSource
Bot message size (activity payload)100 KB (approximate)"Includes the message itself (text, image links, etc.), @-mentions, and reactions encoded as UTF-16." Base64-encoded images are not counted.docs ↗
Recommended working ceiling80 KB"It's recommended to ensure that the size of the message itself is within 80 KB to guarantee successful message delivery."docs ↗
Over the limitHTTP 413 (RequestEntityTooLarge), error code MessageSizeTooBigNot retryable; reduce the payload.docs ↗
Channel conversation post size (platform-wide)Approximately 100 KB per postSame accounting rules; applies to posts in channels generally, bots included.docs ↗
Direct Line activity size (Web Chat / custom clients)256K characters serialized; keep under 150K recommended"The total size of the activity, when serialized to JSON and encrypted, must not exceed 256K characters."docs ↗

Cards, formatting and incoming webhooks

Bot-sent cards live inside the 100 KB activity budget above - there is no separate documented card cap for bots. Incoming webhooks are the surface with the famous 28 KB limit, and they carry their own rate limit that has nothing to do with the bot tables. Formatting support is uneven across surfaces and platforms (desktop, iOS, Android), so a card that renders on desktop can degrade on mobile; the cross-platform tables in the formatting guide are worth checking before shipping markdown-heavy messages. Payloads that violate schema expectations fail with 400 Bad Argument rather than a size error.

WhatLimitNotesSource
Incoming webhook message size28 KB"The message size limit is 28 KB. When the size exceeds 28 KB, you receive an error."docs ↗
Incoming webhook request rate4 requests per second"If more than four requests are made in a second, the client connection is throttled until the window refreshes."docs ↗
Adaptive Card actions via incoming webhookAction.OpenUrl, Action.ShowCard, Action.ToggleVisibility, Action.Execute"All native Adaptive Card schema elements, except Action.Submit, are fully supported."docs ↗
Bot message text formattingTextFormat: plain, markdown, or xmlTeams supports a subset of Markdown/XML; rich cards support formatting in the text property only, and support varies by desktop/iOS/Android.docs ↗

Response-time windows

Invoke-style interactions run on a hard clock. For message-extension action commands and dialog submits, "your app has five seconds to respond to the invoke message"; miss it and "the Teams client retries the request twice before it sends an error message Unable to reach the app," and "if the bot replies after the timeout, the response is ignored" - the failure anatomy is in the Unable to reach the app entry. Regular message activities are more forgiving, but a slow endpoint still produces redelivery, duplicate replies, and eventually the silent-bot behavior dissected in Teams bot not responding; endpoint-side failures surface as 502 bot returned an error.

WhatLimitNotesSource
Message extension / dialog invoke response (composeExtensions/submitAction)5 seconds"Your app has five seconds to respond to the invoke message."docs ↗
Invoke timeout behavior2 client retries, then "Unable to reach the app"Late responses are ignored - make invoke side effects idempotent, since a slow handler runs up to three times.docs ↗
Long-running invoke workMust be deferred until after the invoke reply"The app must defer any long-running actions after the bot replies to the invoke request. The long-running action results can be delivered as a message."docs ↗

App manifest field limits

The Teams app manifest JSON schema enforces hard maximum lengths, and the Developer Portal or upload validation rejects packages that exceed them - a common cause of "app cannot be uploaded" during deployment, distinct from the runtime 401 BotNotRegistered that follows a botId mismatch inside an accepted manifest. The values below are read from the published schema (v1.19); the manifest release notes record one change since: the bot command limit was "increased from 10 to 12" in schema v1.24. Manifest mechanics and the botId pitfall are cause 1 in Teams bot not responding.

WhatLimitNotesSource
App name, short (name.short)30 characters"A short display name for the app."docs ↗
App name, full (name.full)100 characters"Used if the full app name exceeds 30 characters."docs ↗
Description, short (description.short)80 characters"A short description of the app used when space is limited."docs ↗
Description, full (description.full)4,000 characters"The full description of the app."docs ↗
Bots per app (bots array)1The schema caps the bots array at one item per app.docs ↗
Command lists per bot (bots.commandLists)3One list per scope (personal, team, groupChat).docs ↗
Commands per command list10 (12 from manifest v1.24)Release notes: "Increased bot commands limit from 10 to 12 to accommodate Microsoft Copilot Studio agents."docs ↗
Bot command title32 characterscommandLists.commands[].title maxLength.docs ↗
Bot command description128 characterscommandLists.commands[].description maxLength.docs ↗
Compose (message) extensions per app1composeExtensions array maxItems.docs ↗
Commands per compose extension10composeExtensions.commands maxItems.docs ↗
Static tabs per app (staticTabs)16staticTabs array maxItems.docs ↗

Conversation member retrieval

Roster fetches are both paged and rate-limited, and the two interact: a team of 20,000 members at the maximum page size of 500 is 40 calls, comfortably inside the read windows above, but the same fetch at page size 50 makes 400 calls and needs pacing. Microsoft is blunt about the legacy path: "Don't use non-paginated member retrieval in teams and channels. For large rosters, non-paginated calls can be incomplete or throttled" - throttled meaning 429. Member queries in conversations the bot has been removed from fail with 403 BotNotInConversationRoster.

WhatLimitNotesSource
Paged member retrieval - minimum page size50Pass pageSize plus the continuation token between calls.docs ↗
Paged member retrieval - default page size200Applied when no pageSize is specified.docs ↗
Paged member retrieval - maximum page size500Larger values are not honored.docs ↗
Pagination availabilityTeam and channel conversations only"Pagination isn't supported in chat conversations. In chats, the full roster is returned by the service."docs ↗

Proactive messaging constraints

Proactive messages - anything sent outside a reply to a user - run under structural constraints rather than numeric ones. The app must already be installed where the message lands; targeting a user by Entra ID works only in personal scope, and without the personal installation the send fails with 403 ForbiddenOperationException. Users who block or uninstall the bot answer with 403 MessageWritesBlocked, and stale references produce 404 ConversationNotFound. The serviceUrl rules matter across clouds: hardcode the public host and GCC tenants fail with 403 InvalidBotApiHost.

WhatLimitNotesSource
Requirements to create a conversationaadObjectId or userId, plus tenantId and serviceUrl"Create the conversation only once, and store the resulting conversationId for future proactive messages."docs ↗
Targeting by Microsoft Entra ID (aadObjectId)Personal scope only"Sending proactive messages using aadObjectId is supported only in personal scope"; the app must be installed personally.docs ↗
What proactive messaging cannot createNo new group chats, no new channels"You can't create a new group chat or a new channel in a team with proactive messaging." New 1:1 chats and new channel threads are possible.docs ↗
Targeting by email or UPNNot supported"Teams doesn't support sending proactive messages using email or User Principal Name (UPN)."docs ↗
Global service URLs (fallback when no incoming serviceUrl)Public smba.trafficmanager.net/teams/; GCC smba.infra.gcc.teams.microsoft.com/teams; GCC High smba.infra.gov.teams.microsoft.us/teams; DoD smba.infra.dod.teams.microsoft.us/teams"Avoid hardcoding them. Instead, use serviceUrl from the incoming activity or conversation reference."docs ↗
Blocked or uninstalled user403 with subCode MessageWritesBlockedDocumented as the way to build a per-user blocked report; no event fires when a user blocks or uninstalls.docs ↗
userId scopeUnique per bot and user; not transferable"The userId is unique to your agent ID and a particular user. You can't reuse the userId between agents."docs ↗

Teams platform caps that affect bots

These are Teams-wide limits from the admin documentation rather than bot-API limits, but they bound what a bot can do: how many people a channel post can reach, how many members a roster fetch can return, how many channels an enumeration can yield. The mention restriction in very large teams is easy to miss - a bot that @mentions the team in a 12,000-member org fails where the same code worked in a smaller one, usually surfacing as 400 Bad Argument on the mention entity or as a silently absent notification.

WhatLimitNotesSource
Members in a group chat250"Only 200 members can be added to a group chat at the same time." Chats over 20 people lose typing indicators and some features.docs ↗
Members in a team25,000Includes shared-channel members from outside the team.docs ↗
Channels per team1,000 (includes deleted channels for 30 days)Any combination of standard, private, and shared channels.docs ↗
Members in a private channel5,000Private channels also each get their own SharePoint site.docs ↗
Members in an org-wide team10,000Maximum 5 org-wide teams per tenant.docs ↗
Team/channel @mentions in very large teamsBlocked above 10,000 members"Teams/channel mentions are blocked in teams with over 10,000 members."docs ↗
Chat file attachments10 per message, 100 MB per fileExceeding the count shows the sender an error message.docs ↗
File upload via SharePoint/OneDrive (Files tabs, channel files)250 GB per fileTeams file storage is SharePoint-backed, so SharePoint limits apply to channel and chat files.docs ↗

Teams guides and tools

Other platforms

Frequently asked questions

How many messages per second can a Teams bot send?

Into one conversation: 7 per second (8 per 2 seconds, 60 per 30 seconds, 1,800 per hour when repeatedly messaging a single user). Across a whole tenant: 50 requests per second for your app, all operations combined. All bots in one thread also share a 14-per-second send pool. Exceeding any window returns 429 Throttled with a Retry-After header, and Microsoft warns the values can change - implement backoff regardless.

What is the Teams bot message size limit - 28 KB or 100 KB?

For bots, 100 KB per activity, approximately measured: text, image links, mentions, and reactions counted as UTF-16, excluding base64 images, with an official recommendation to stay within 80 KB. The 28 KB figure belongs to incoming webhooks, a different surface. Oversized bot messages fail with 413 RequestEntityTooLarge carrying error code MessageSizeTooBig, which is not retryable.

How fast must a Teams bot respond to an invoke?

Five seconds for message-extension action commands and dialog submits: "Your app has five seconds to respond to the invoke message." On timeout the client retries twice, shows the user "Unable to reach the app", and ignores any late response. Microsoft's documented pattern is to reply within the window and defer long-running work, delivering results afterward as a normal or proactive message.

How many command list commands can a Teams bot declare in its manifest?

Ten commands per command list in schema versions through v1.23, raised to twelve in manifest v1.24. A bot may carry up to three command lists (one per scope), each command with a 32-character title and 128-character description. The manifest also caps the app at one bot, one compose extension with ten commands, and sixteen static tabs.

How do I fetch large team rosters without being throttled?

Use paged member retrieval with a continuation token: minimum page size 50, default 200, maximum 500. Pagination works in team and channel conversations; chats return the full roster in one response. Avoid the deprecated non-paginated getMembers APIs, which are throttled to five requests per minute, capped at 10K members, and documented as potentially incomplete for large rosters.

Can my bot proactively message any user in the tenant?

Only users who have the app: proactive 1:1 messages require the app installed in the user's personal scope (or install it for them via the Graph installedApps API). Targeting by Entra object ID works only in personal scope; email and UPN targeting are not supported; and you cannot create new group chats or channels proactively. Users without the installation return 403 ForbiddenOperationException.

Which failed requests should a Teams bot retry?

Microsoft documents four retryable codes: 429 (wait the Retry-After header value, or use exponential backoff with jitter scoped to the thread), plus 412, 502, and 504 with exponential backoff. Everything else - 400, 401, 403, 404, 405, 413, 500 - is documented as non-retryable: fix the payload, credentials, or policy condition instead of resending.

Do Adaptive Cards have their own size limit in Teams?

Not for bots: a bot-sent card is part of the activity and lives inside the documented 100 KB message limit (80 KB recommended). The separate 28 KB ceiling applies to incoming webhook payloads, including Adaptive Cards sent through webhooks. In practice generated cards hit the limit through unbounded lists and tables, so cap collection sizes when building card JSON.

Why does my broadcast throttle even though each user gets only one message?

One message per user keeps every per-thread window happy but still spends the global budget: 50 requests per second per app per tenant. A 10,000-user announcement fired as fast as possible exceeds that within the first second. Queue the fan-out with a token bucket below 50 RPS, honor any Retry-After on 429, and remember service-side message splitting can count one long message as multiple requests.

Does the 15-second response window for Teams bots appear in these tables?

No - Microsoft's tables document the five-second invoke window, but no equivalent number for plain message activities. In practice, endpoints that take tens of seconds see redelivered activities and duplicate replies, and the community guidance is to acknowledge quickly and defer slow work. Treat responsiveness as an architectural requirement even though only the invoke surface carries a documented figure.

Build on Teams without tracking every limit yourself

Conferbot paces sends, queues retries and surfaces limit errors as readable status.