No—calling the channel-messages delta endpoint every 5–60 seconds as a continuous production polling loop does not comply with the documented Microsoft Teams polling requirement, even if every call remains below the 1-request-per-second throttling limit.
Microsoft states that apps polling to determine whether a Teams resource changed may do so only once per day; apps needing more frequent updates should use change-notification subscriptions. Noncompliant polling can trigger additional throttling or suspension or termination of API access.^1^
Why the 1-rps limit does not make this acceptable
The published limits are throttling ceilings, not approved polling intervals. Teams evaluates requests across several independent dimensions, including:
- Per app across all tenants
- Per app per tenant
- Per channel or other resource
- Per user, when applicable
The documented default GET limits include 1 rps per chat or channel, 30 rps per app per tenant, and 1,500 rps per app. Specific channel-message GET limits include 1 rps per channel, 20 rps per app per tenant, and 200 rps per app.^2^
Therefore, a five-second interval might be below the per-channel throttling ceiling but still violate the separate once-per-day polling requirement. A multitenant deployment can also reach aggregate app or app-per-tenant limits before reaching the per-channel limit.
Supported design for the current RSC model
For private and shared channels where ChannelMessage.Read.Group cannot provide the required change notifications:
- Use the delta endpoint for initial synchronization.
- Follow every
@odata.nextLink until Graph returns @odata.deltaLink.
- Persist the complete
@odata.deltaLink unchanged; its state token is opaque.
- Use that URL for the next periodic synchronization.
- Do not run it as a 5–60-second activity detector. Under the documented Teams polling policy, schedule the check no more frequently than once per day.
Delta query is a pull-based synchronization mechanism. It reduces transferred data by returning changes since the saved state, but it does not convert polling into a supported real-time event stream.^3^
A scheduler should therefore resemble:
async Task SynchronizeChannelAsync(ChannelState state)
{
var url = state.DeltaLink ?? state.InitialDeltaUrl;
do
{
var page = await graph.GetAsync<DeltaPage>(url);
await store.ApplyAsync(page.Messages);
url = page.NextLink;
if (page.DeltaLink is not null)
await store.SaveDeltaLinkAsync(state.ChannelId, page.DeltaLink);
}
while (url is not null);
}
Also treat 429 Too Many Requests independently from the schedule: honor Retry-After, back off, and avoid immediately retrying rejected requests.
If low-latency synchronization is mandatory
The accepted Microsoft Q&A resolution for this exact private/shared-channel RSC scenario states that no additional RSC scope or configuration enables message change notifications there. Its alternative is tenant-wide ChannelMessage.Read.All, which requires tenant-admin consent and the applicable Microsoft Graph protected-API approval process.^4^
If customers can grant that permission, replace polling with a channel-level subscription to:
/teams/{team-id}/channels/{channel-id}/messages
Channel subscriptions deliver created and updated messages and replies, can include resource data, and support application-only ChannelMessage.Read.All.^5^
If tenant-wide permission and admin consent are not acceptable, there is no documented production-supported path in these sources for 5–60-second synchronization of private/shared-channel messages using only ChannelMessage.Read.Group. The practical choices are daily delta synchronization or reduced functionality for those channel types.
References
- Use the Microsoft Graph API to work with Microsoft Teams
- Microsoft Graph service-specific throttling limits
- Use delta query to track changes in Microsoft Graph data
- Teams Bot: Receiving all messages from Private Channels using RSC permissions - Microsoft Q&A
- Get change notifications for messages in Teams channels and chats using Microsoft Graph