Inquiry on Scalability, Throttling, and Delivery Guarantees for Microsoft Teams Activity Feed Notifications

Ahmad Nabil Bin Yusoff 0 Reputation points
2026-10-19T07:29:50.6966667+00:00

Hello Microsoft Developer Support Team,

We are developing a crisis alert management application that is embedded within Microsoft Teams. One of our core requirements is the ability to send urgent notifications to approximately 4,000 users as quickly as possible when an administrator triggers an emergency event.

The notifications are sent using Microsoft Graph Activity Feed Notifications, and users can respond directly through the notification experience in Teams.

We are evaluating two approaches:

Approach 1: Individual Notifications :
POST https://graph.microsoft.com/v1.0/users/{user-id}/teamwork/sendActivityNotification

**Approach 2: Bulk Notifications :
**POST https://graph.microsoft.com/v1.0/teamwork/sendActivityNotificationToRecipients

Our Use Case

  • Microsoft Teams embedded application
  • Crisis / emergency alert management
  • Approximately 4,000 users per alert event
  • Notifications should arrive as quickly as possible
  • Users receive the notification in the Teams Activity Feed and can respond
  • Fast and reliable distribution is critical

Questions

1. Rate Limits and Throttling

For both APIs:

  1. What are the documented or recommended throughput limits?
  2. Are there per-app, per-tenant, or per-user throttling limits?
  3. Is it acceptable to send thousands of requests concurrently?
  4. For example, can we send 4,000 notifications (40 bulk requests (100 users each) for bulk) simultaneously using asynchronous requests?
  5. If not, what level of concurrency is recommended?

2. Delivery Guarantees

For both APIs:

  • Does a successful API response guarantee delivery to the user's Teams client?
  • What does HTTP 202/204 actually indicate?
    • Accepted by Graph?
    • Accepted by Teams service?
    • Displayed to end user?
  • Are there scenarios where the API succeeds but the notification is ultimately not delivered?
  • Is there any mechanism to verify successful delivery?

Thank you for your assistance.

Microsoft Security | Microsoft Graph
0 comments No comments

1 answer

Sort by: Most helpful
  1. AI answer

    2026-10-19T07:30:50.12+00:00

    Use POST /teamwork/sendActivityNotificationToRecipients in batches of up to 100 recipients, but pace those batches below the 2 requests/second per-app-per-tenant limit rather than launching all 40 simultaneously.

    1. Throughput and throttling

    The documented Teams limits are ^1^:

    Endpoint Per app Per app per tenant Other endpoint-specific limit
    /users/{user-id}/teamwork/sendActivityNotification 50 rps 5 rps No dedicated per-user limit listed
    /teamwork/sendActivityNotificationToRecipients 20 rps 2 rps Up to 100 recipients/request

    Graph evaluates all applicable limits; whichever is reached first causes throttling. For one app sending into one tenant, the per-app-per-tenant value is therefore the practical governing limit.

    For 4,000 users:

    • Individual endpoint: 4,000 requests at no more than 5 rps, giving a theoretical request-submission floor of about 800 seconds.
    • Bulk endpoint: 40 requests of 100 recipients at no more than 2 rps, giving a theoretical request-submission floor of about 20 seconds.
    • Actual processing and client presentation can take longer.

    The bulk endpoint is purpose-built for multiple recipients, permits at most 100 recipients in each request, and returns 202 Accepted. Its token must also have at least 45 minutes remaining; otherwise, the call returns 412 Precondition Failed ^2^.

    Do not dispatch all 40 bulk requests simultaneously. Concurrency is not itself the published control; request rate is. Use:

    1. Batches of 100 users.
    2. A rate limiter below 2 rps for that tenant—starting around 1 request/second provides headroom.
    3. A small bounded concurrency, such as 1–2 in-flight calls, only to absorb network latency.
    4. Per-batch durable state and an idempotency strategy. If updating the same logical notification, chainId can override an earlier notification; do not assume it is a general request-deduplication receipt.
    5. Retry 429 only after the Retry-After interval. If that header is absent, use exponential backoff with jitter ^3^.

    Conceptually:

    foreach (var batch in recipients.Chunk(100))
    {
        await rateLimiter.WaitAsync(); // Configure below 2 requests/second/tenant
        var response = await SendBulkNotificationAsync(batch);
    
        if (response.StatusCode == HttpStatusCode.TooManyRequests)
        {
            await DelayFromRetryAfterOrExponentialBackoff(response);
            // Retry this batch; don't advance its durable status yet.
        }
    }
    

    If the same user can receive multiple alerts in a short period, Teams automatically throttles an app above 20 notifications per minute per user ^4^.

    2. Meaning of 202 and 204

    • Bulk endpoint — 202 Accepted: the request was accepted for asynchronous processing; it does not mean processing is complete ^2^.
    • Individual endpoint — 204 No Content: the endpoint successfully fulfilled the request and has no response body ^5^.

    Neither endpoint’s documentation defines these responses as proof that:

    • the notification was rendered in a particular Teams client;
    • a toast was shown;
    • the user saw or opened it; or
    • the user responded.

    Treat both as API-operation success, not end-user delivery/read confirmation.

    3. Delivery limitations

    Successful submission can still differ from visible presentation because:

    • The target user must have the sending Teams app installed ^6^.
    • Users control notification settings; the app cannot control how notifications are shown.
    • Priority notifications are not supported.
    • Toast notifications lead to the activity feed, while activity-feed entries can deep-link into the app.
    • Activity-feed notifications are stored for 30 days ^4^.

    The supplied API contracts do not document a delivery-status endpoint, callback, recipient-level receipt, read receipt, or guarantee that a successful request was displayed. In particular, the bulk 202 response does not provide a documented polling location for later recipient-level status.

    For operational tracking, record:

    • alert/event ID;
    • batch and recipient IDs;
    • submission time;
    • HTTP status;
    • Graph request/correlation headers;
    • retry count and final submission outcome;
    • the user’s acknowledgement in your application.

    That acknowledgement is the reliable business-level signal available to your crisis workflow—not the Graph submission response.

    4. Crisis-alert architecture implication

    Activity-feed notifications support alerts and user actions, but priority notifications are not supported ^6^. Therefore, do not treat this API alone as a guaranteed emergency-broadcast channel.

    Use the bulk API for fast Teams distribution, then implement application-level escalation:

    1. Submit 100-recipient batches through a durable queue.
    2. Retry only throttled/transient failures.
    3. Track acknowledgements through the Teams app.
    4. After a defined timeout, escalate unacknowledged alerts through an independently approved emergency channel.
    5. Load-test in a nonproduction tenant, including simulated 429 and partial-batch operational failures.

    References

    1. Microsoft Graph service-specific throttling limits
    2. teamwork: sendActivityNotificationToRecipients
    3. Microsoft Graph throttling guidance
    4. Best practices for using Microsoft Teams activity feed notifications
    5. userTeamwork: sendActivityNotification
    6. Send activity feed notifications to users in Microsoft Teams
    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.