Subscribing to Copilot Activity: The AI Interactions Change Notifications API, Dual Subscription Scopes, and What Best-Effort Delivery Means for Your Audit Pipeline

A developer follows the standard Microsoft Graph webhook pattern to subscribe to Copilot activity: they POST a subscription with a three-day expiry, a valid notification URL, and the correct resource path — and Graph returns 400 Bad Request. The missing field is lifecycleNotificationUrl, and its absence is not a warning the request can proceed past. A week later, with the subscription running, their receiving endpoint goes offline for five hours during a deployment — and when it comes back, five hours of Copilot interaction events are gone, and they cannot be recovered. Before you build the receiving endpoint, there are three things about this API’s subscription model that generic Graph change notification guides do not put in front of you: the dual scope model and its permission boundary, the lifecycleNotificationUrl requirement, and a best-effort delivery model that determines whether this API is sufficient on its own.

After reading this post, you will be able to:

✅ Configure a per-user or tenant-wide subscription with the correct permission model, licensing, and every required field

✅ Implement a receiving endpoint that passes the validation handshake and handles both basic and rich notification payloads

✅ Design a compensating reconciliation strategy that accounts for the best-effort delivery model

✅ Identify the categories of Copilot interactions this API does not cover — including Copilot Studio agents — before you build against it


What Triggers a Notification — and What This API Does Not Capture

Before subscription mechanics, be clear about what a notification represents and where the events come from. The resource is aiInteraction, and each aiInteraction object represents one message exchanged between a user and Copilot. Its interactionType is either userPrompt — the message the user sent — or aiResponse, the message Copilot returned. Both types trigger notifications. The change types you subscribe to are created, deleted, and updated, supplied as a single comma-separated string: "created,deleted,updated".

The container resource is aiInteractionHistory. It returns interactions from Microsoft 365 Copilot experiences that write to the interaction history service — Copilot in Teams, Copilot Chat (BizChat), and Copilot in the productivity apps. The appClass property on each interaction identifies the source experience: you will see values such as IPM.SkypeTeams.Message.Copilot.Teams for Copilot in Teams and IPM.SkypeTeams.Message.Copilot.BizChat for Copilot Chat.

What this API does not capture matters as much as what it does. Three categories are excluded. Interactions from Copilot Studio agents are not returned — the documentation states plainly that getAllEnterpriseInteractions does not retrieve interactions in agents created by Copilot Studio. Consumer and personal Microsoft accounts are out of scope. And any AI experience that does not write to the interaction history service produces no interactions here, and therefore no notifications.

Note: Interactions from Copilot Studio agents are excluded. This is a documented boundary, not a temporary gap — change notifications on this resource do not fire for Studio agent interactions. If you are planning to audit Copilot Studio agent usage, do not build against this API for that purpose. See Post 12 (Copilot Studio Agents) for the agent authoring model; the audit path for Studio agents, if one exists, is separate from the AI Interactions Change Notifications API.

What this means for you: confirm your audit scope maps to Copilot experiences that write to the interaction history service — and if Copilot Studio agents are in scope, plan a separate path for them now, not after your pipeline is live.


Per-User or Tenant-Wide — and Why the Scope Choice Determines Your Permissions

The first architectural decision is not a field in the request body — it is which of two resource scopes you subscribe to, because the scope decides your permission model, your licensing requirements, and whether a delegated flow is even possible.

Per-user scope subscribes to the Copilot interactions that one specific user is part of. The resource path is copilot/users/{user-id}/interactionHistory/getAllEnterpriseInteractions. It supports both delegated and application permissions, so it fits user-scoped workflows and delegated app scenarios.

Tenant-wide scope subscribes to all Copilot interactions across the entire tenant. The resource path is copilot/interactionHistory/getAllEnterpriseInteractions. It supports application permissions only — there is no delegated path. This is the scope you want for a background audit pipeline or a SIEM integration that monitors the whole tenant, and it is a fundamentally different authentication architecture from per-user, not a larger version of the same thing.

The permission tables differ by scope. For a per-user subscription:

Permission typeLeast privilegedHigher privileged
Delegated (work or school account)AiEnterpriseInteraction.Read
Delegated (personal Microsoft account)Not supported
ApplicationAiEnterpriseInteraction.Read.User (via resource-specific consent)AiEnterpriseInteraction.Read.All

For a tenant-wide subscription:

Permission typeLeast privilegedHigher privileged
Delegated (work or school account)Not supported
Delegated (personal Microsoft account)Not supported
ApplicationAiEnterpriseInteraction.Read.All

Licensing is a hard gate in both directions, and it is not the same for the two scopes. A per-user subscription requires the target user in the resource path to have the Microsoft 365 Copilot Chat service plan enabled (service plan ID 3f30311c-6b1e-48a4-ab79-725b469da960). A tenant-wide subscription requires all six of the following service plan IDs to be provisioned and active on the tenant — this is not a soft requirement, and a missing plan will block the subscription.

Service planService plan ID
Microsoft 365 Copilot connectors in Microsoft 365 Copilot82d30987-df9b-4486-b146-198b21d164c7
Intelligent search931e4a88-a67f-48b5-814f-16a5f1e6028d
Microsoft 365 Copilot in Microsoft Teamsb95945de-b3bd-46db-8437-f2beb6ea2347
Microsoft 365 Copilot in productivity appsa62f8878-de10-42f3-b68f-6149a25ceb97
Microsoft 365 Copilot Chat3f30311c-6b1e-48a4-ab79-725b469da960
Power Platform connectors in Microsoft 365 Copilot89f1c4c8-0878-40f7-804d-869c9128ab5d

The consent flow for these AiEnterpriseInteraction scopes — delegated versus application, and the admin consent patterns — is covered in Post 02 (Auth, Permissions, and App Registration). Refer to that post for the registration mechanics rather than reproducing them here.

What this means for you: decide per-user versus tenant-wide before you touch the request body — that one choice fixes whether you can use a delegated flow at all, which permission you register, and how many service plans your tenant must carry.


Five Fields You Must Get Right Before Subscription Creation Succeeds

Subscriptions are created by posting to the standard Graph subscriptions endpoint — POST https://graph.microsoft.com/v1.0/subscriptions — the same endpoint you would use to subscribe to chatMessage or callTranscript. Five fields in the request body decide whether creation succeeds.

A flow diagram showing subscription creation with required fields, Microsoft Graph notification delivery forking into basic and rich paths, a retry arc showing the 4-hour exponential backoff window, and a separate lifecycle notification channel for subscription renewal

1. resource — the per-user or tenant-wide path from the previous section. This is where your scope decision becomes concrete in the request.

2. changeType — must be the string "created,deleted,updated" to receive the full set of interaction events.

3. expirationDateTime — the subscription’s expiry, which cannot exceed 4,320 minutes (three days) from creation. A request for a longer lifetime is rejected.

4. lifecycleNotificationUrl — required for any subscription whose expirationDateTime is more than one hour in the future. Without it, creation fails with the error "lifecycleNotificationUrl is a required property for subscription creation on this resource when the expirationDateTime value is set to greater than 1 hour". Because every realistic subscription outlasts one hour, treat this field as mandatory, not optional. The URL is validated independently during the creation handshake, exactly like the notification URL.

5. clientState — an opaque secret you set and Graph echoes back in every notification, so your endpoint can confirm a notification originated from your subscription rather than a spoofed source.

If you want the full interaction content delivered inside the notification rather than fetched afterward, set includeResourceData to true and supply encryptionCertificate and encryptionCertificateId. The full encryption setup — generating a certificate, encoding it to base64, and managing the private key in your application — is documented in the Microsoft Graph change notifications with resource data guide [Ref 8]. Reference that guide before implementing the rich notification path; this post does not reproduce the certificate procedure.

The following examples are adapted from the official documentation’s sample request bodies. Both add lifecycleNotificationUrl, which the original samples omit despite using multi-day expiry values that would cause subscription creation to fail without it per the rule above. A per-user subscription with resource data:

POST https://graph.microsoft.com/v1.0/subscriptions HTTP/1.1
Host: graph.microsoft.com
Authorization: Bearer {token}
Content-Type: application/json
{
"changeType": "created,deleted,updated",
"notificationUrl": "https://webhook.azurewebsites.net/api/resourceNotifications",
"lifecycleNotificationUrl": "https://webhook.azurewebsites.net/api/lifecycleNotifications",
"resource": "/copilot/users/{user-id}/interactionHistory/getAllEnterpriseInteractions",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2024-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}

A tenant-wide subscription is the same shape with the tenant-wide resource path:

POST https://graph.microsoft.com/v1.0/subscriptions HTTP/1.1
Host: graph.microsoft.com
Authorization: Bearer {token}
Content-Type: application/json
{
"changeType": "created,deleted,updated",
"notificationUrl": "https://webhook.azurewebsites.net/api/resourceNotifications",
"lifecycleNotificationUrl": "https://webhook.azurewebsites.net/api/lifecycleNotifications",
"resource": "/copilot/interactionHistory/getAllEnterpriseInteractions",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2024-08-10T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}

Two operational rules bound how many of these you can hold. A duplicate subscription — the same resource and changeType — returns HTTP 409 Conflict. And each subscription category has a quota:

Quota scopeActive subscription limit
Per app + tenant (tenant-wide subscriptions)1
Per app + user (per-user application subscriptions)1
Per user, delegated (per-user subscriptions)10
Per organization (shared with all Graph subscriptions)10,000

💡 Insight: The lifecycleNotificationUrl requirement is the single most common source of subscription creation failures for this resource. It is not a configuration option that unlocks extra features — it is a hard API enforcement at creation time for any subscription intended to outlast the default one-hour window. If your creation call returns 400 and you are certain the resource path and permissions are right, this field is the first thing to check.

What this means for you: build your creation request with all five fields present from the start — omitting lifecycleNotificationUrl fails the call outright, and a duplicate resource-and-changeType pair costs you a 409 instead of a working subscription.


The Endpoint Validation Handshake — What Graph Tests Before Creating the Subscription

Before Graph creates a subscription, it proves your endpoint is reachable and yours. This handshake runs before any interaction notification ever arrives, and if it fails, the subscription is never created.

Step 1 — Graph posts a validation token. When you submit the creation request, Graph sends a POST to your notificationUrl with a validationToken query parameter: POST https://{notificationUrl}?validationToken={opaqueToken}. If you supplied a lifecycleNotificationUrl, Graph validates that URL separately with the same mechanism.

Step 2 — Your endpoint echoes the token. The endpoint must respond within 10 seconds with HTTP 200, a Content-Type of text/plain, and a body containing the URL-decoded plain text validation token — not JSON, not an HTML-encoded string. Any deviation fails validation.

Step 3 — Graph creates or rejects the subscription. If the echo is correct, Graph creates the subscription and returns the subscription object. If validation fails, Graph returns 400 Bad Request and no subscription exists.

Quick win: Test the validation handshake in isolation before anything else. Submit a one-hour subscription with no lifecycleNotificationUrl and no includeResourceData — the simplest valid subscription there is — and confirm your endpoint returns the plain text token correctly. If that handshake succeeds, the harder configuration (resource data, encryption, long expiry) has one fewer variable to debug when you add it.

What this means for you: get the validation handler returning a plain text 200 first — until that works, no amount of correct subscription-body configuration will produce a live subscription.


Two Notification Payload Shapes — IDs Only or Encrypted Full Content

Once the subscription is live, notifications arrive in one of two shapes depending on whether you set includeResourceData.

Basic notifications carry identifiers, not content. Each notification includes subscriptionId, changeType, clientState, the resource string with the interaction ID embedded, and a resourceData block holding id, @odata.type, and @odata.id:

{
"subscriptionId": "10493aa0-4d29-4df5-bc0c-ef742cc6cd7f",
"changeType": "created",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2025-02-02T10:30:34.9097561-08:00",
"resource": "copilot/interactionHistory/interactions('1731701801008')",
"resourceData": {
"id": "1731701801008",
"@odata.type": "#Microsoft.Graph.aiInteraction",
"@odata.id": "copilot/interactionHistory/interactions('1731701801008')"
}
}

The interaction ID in resourceData.id is enough to make a follow-up GET call for the full interaction content. Basic notifications trade a second round trip for not having to manage encryption.

Rich notifications carry the full interaction content, encrypted. When includeResourceData is true, each notification adds an encryptedContent block — with data, dataKey, encryptionCertificateId, and encryptionCertificateThumbprint — alongside a tenantId and the validationTokens array. Once decrypted with your private key, encryptedContent.data conforms to the aiInteraction schema. A decrypted Copilot in Teams aiResponse looks like this (trimmed):

{
"id": "1731701801008",
"sessionId": "19:icg2t_AWPYJyJ2oDLB_CZyh29QXpZvbdpljKf7qKotk1@thread.v2",
"requestId": "7336770c-fb25-48ac-8303-4493ad11ed71",
"appClass": "IPM.SkypeTeams.Message.Copilot.Teams",
"interactionType": "aiResponse",
"conversationType": "appchat",
"createdDateTime": "2024-11-15T20:16:41.008Z",
"from": {
"device": null,
"user": null,
"application": {
"@odata.type": "#microsoft.graph.teamworkApplicationIdentity",
"id": "fb8d773d-7ef8-4ec0-a117-179f88add510",
"displayName": "Copilot in Teams",
"applicationIdentityType": "bot"
}
},
"body": {
"contentType": "text",
"content": "I use the transcript to generate insights..."
}
}

Look closely at the from block, because it holds a gotcha that breaks per-user attribution if you miss it.

Note: When interactionType is aiResponse, from.user is null — the Copilot response does not carry the user’s identity in the from field; from.application carries the Copilot bot identity instead. Only userPrompt interactions carry the user’s Entra ID in from.user. To attribute a Copilot response to the user who prompted it, correlate the aiResponse to its userPrompt by matching the requestId, which groups a prompt with its response. Do not attempt per-user attribution by reading from.user on the response side.

If you do not need every interaction, you can narrow the stream at the source. The $filter OData query parameter can be appended to the resource string in the subscription request — for example, ?$filter=appClass eq 'IPM.SkypeTeams.Message.Copilot.Teams' to receive only Teams Copilot interactions, or ?$filter=conversationType ne 'bizchat' to exclude Copilot Chat. One limitation is verified and worth knowing before you design the filter: $filter works on top-level properties of aiInteraction only. Nested property filters — for instance ?$filter=from/user/id eq '...' — are not supported and will not work.

What this means for you: pick basic notifications when a follow-up GET is acceptable and you want to avoid certificate management; pick rich notifications when you need content in-band — and either way, wire your user attribution to requestId, not to from.user.


Best-Effort Delivery: The Numbers Behind Average 10-Second Latency and 60-Minute Maximum

This is the section to read twice if you are building an audit log. Microsoft Graph change notifications follow a best-effort delivery model. There is no exactly-once guarantee, and notifications that are dropped cannot be recovered. For a compliance or SIEM pipeline, that fact is not a footnote — it is the constraint that decides whether this API is sufficient on its own.

The latency numbers are favorable in the common case. Average delivery latency is less than 10 seconds; maximum latency is 60 minutes. Most notifications arrive within seconds, which is the entire reason to prefer this over polling.

The retry behavior is where the operational risk lives. Your endpoint must return a 2xx response within 3 seconds. If it does not, Graph retries with exponential backoff for up to 4 hours, extending the timeout window to 10 seconds during those retries. After 4 hours of endpoint unavailability, the missed notifications are dropped — permanently, with no recovery path.

Slowness alone can cost you notifications even when the endpoint never goes fully down. If more than 10% of your responses take longer than 3 seconds in a 10-minute window, Graph marks the endpoint “slow” and delays notifications. If more than 15% exceed 10 seconds, notifications are dropped for that window.

Delivery metricValue
Average latencyLess than 10 seconds
Maximum latency60 minutes
Required response2xx within 3 seconds (10 seconds during retries)
Retry windowUp to 4 hours of exponential backoff
After the retry windowNotifications dropped, unrecoverable
“Slow” threshold>10% of responses over 3 seconds in 10 minutes → delayed
“Drop” threshold>15% of responses over 10 seconds → dropped for the window

💡 Insight: The 4-hour retry window is a ceiling, not a guarantee of delivery. An endpoint that is slow but not fully down can still drop notifications under the throttling thresholds long before four hours pass. Design for the worst case — a window of lost events — not the average case of sub-10-second delivery.

The endpoint pattern that survives this model is asynchronous. Validate the notification (check clientState), enqueue it, and return 202 Accepted within 3 seconds — then process it downstream from the queue. Return a 5xx only when you want Graph to retry; return 2xx only after the notification is safely queued. The endpoint must never do slow, synchronous processing on the request thread, because that is exactly what trips the throttling thresholds.

Because delivery is best-effort, an audit pipeline needs a compensating reconciliation strategy. Periodically poll the getAllEnterpriseInteractions GET API and reconcile the results against the events your webhook actually received, backfilling anything missing. A daily poll with a lookback window that extends beyond the 4-hour maximum retry window catches events lost during endpoint downtime or throttling. This is where this API meets Post 04 (Usage Reports): Post 04 gives you aggregated adoption trends on a 24-to-48-hour lag; this API gives you per-interaction events within seconds on average. They are different tools for different timing models, and a complete Copilot observability strategy uses both — the change notifications for real-time reaction, the reconciliation poll as the safety net that best-effort delivery requires.

What this means for you: treat webhook delivery as your fast path, never your only path — build the reconciliation poll before you promise anyone that your audit log is complete.


Keeping the Subscription Alive: Renewal, the Lifecycle Notification URL, and the 3-Day Ceiling

A subscription that hits its expirationDateTime stops delivering, and there is no grace period — an expired subscription must be re-created, not renewed. Keeping one alive is an active job.

Renew before expiry with PATCH. Renew a running subscription by sending PATCH https://graph.microsoft.com/v1.0/subscriptions/{id} with a new expirationDateTime up to three days from the PATCH time. Renewing also refreshes the endpoint’s access token.

PATCH https://graph.microsoft.com/v1.0/subscriptions/{subscriptionId} HTTP/1.1
Host: graph.microsoft.com
Authorization: Bearer {token}
Content-Type: application/json
{
"expirationDateTime": "2024-09-22T11:00:00.0000000Z"
}

Let the lifecycle channel drive renewal. The lifecycleNotificationUrl you supplied at creation is not only a validation target — it is where Graph sends lifecycle notifications when subscription health events occur: reauthorization needed, the subscription nearing expiry, or the subscription expiring. This is the mechanism that lets a long-lived subscription renew itself. Your lifecycle endpoint receives the event and triggers the PATCH, rather than depending solely on an external scheduler guessing the timing.

Renew early, not at the edge. Whether driven by the lifecycle channel or a scheduler, target renewal at the two-day mark — a full day before the three-day ceiling — so a transient failure has room for a retry before the subscription lapses. Renewing at the last moment leaves no margin, and a lapse means re-creation and a gap in your event stream.

What this means for you: schedule renewal at the two-day mark and wire your lifecycle endpoint to act on Graph’s own expiry warnings — an expired subscription is a re-creation and a data gap, not a quick fix.


The API Version Question the Official Docs Don’t Fully Resolve

If you are making a production-readiness decision, you need an honest read on this API’s version status, because the official documentation sends mixed signals and this post will not paper over them.

The evidence pointing toward v1.0 availability is concrete. Subscription creation uses POST https://graph.microsoft.com/v1.0/subscriptions, not a /beta path. The underlying getAllEnterpriseInteractions GET method has a documented v1.0 path. And the supported-resources table in the Graph change notifications overview does not mark aiInteraction with the asterisk that flags beta-only resources — nor does the change notifications how-to page carry a “preview only” or “subject to change” banner.

The evidence pointing the other way is equally real. The aiInteraction resource type page carries a beta-zone warning in its graph-preview section, and the resource documentation lives in the Microsoft 365 Copilot extensibility docs rather than the standard Graph API reference. Both signals cannot be simultaneously authoritative.

Note: This API’s version status is a mixed signal, not a clean GA announcement. The subscription endpoint path and the supported-resources table point to v1.0 availability; the resource type page carries a beta-zone warning. No official source states a preview-to-GA timeline. If you are building a production system on this API, verify the current state of both the aiInteraction resource page and the change notifications supported-resources table at the time you begin implementation — do not treat either this post or any earlier classification as the final word on its stability.

What this means for you: verify the resource page and the supported-resources table yourself before you commit this API as production-stable, and record the date you checked — the signals may have converged by the time you read this.


Nine Checks Before Your Pipeline Receives Real Copilot Events

Consolidate every gate from this post into one pre-go-live pass. Most failures here surface as a rejected subscription or a silent gap in events, not a helpful runtime error — so the checklist, not the exception log, is what catches them.

  • [ ] Licensing: Per-user subscriptions have the Microsoft 365 Copilot Chat service plan on each target user; tenant-wide subscriptions have all six service plan IDs provisioned and active on the tenant.
  • [ ] Permission registered: The app holds the right scope — AiEnterpriseInteraction.Read (delegated, per-user), AiEnterpriseInteraction.Read.User (RSC, per-user application), or AiEnterpriseInteraction.Read.All (per-user application, and the only option for tenant-wide).
  • [ ] Tenant-wide is application-only: For a tenant-wide subscription, confirm no delegated flow exists anywhere in the architecture — delegated is not supported for this scope.
  • [ ] Validation handshake: The notification endpoint returns HTTP 200 with a plain text token within 10 seconds; the lifecycle endpoint passes the same handshake.
  • [ ] lifecycleNotificationUrl present: The field is supplied for any subscription longer than one hour — creation fails without it.
  • [ ] Expiry within ceiling: expirationDateTime does not exceed three days (4,320 minutes) from creation.
  • [ ] Renewal scheduled: Renewal logic runs before expiry — target the two-day mark — driven by the lifecycle channel or a scheduler.
  • [ ] 202 endpoint pattern: The endpoint validates clientState, queues the notification, and returns 202 Accepted within 3 seconds, processing asynchronously rather than blocking on downstream work.
  • [ ] Reconciliation strategy: A periodic getAllEnterpriseInteractions GET poll reconciles against webhook-received events to backfill anything dropped by the best-effort model.

One caveat belongs in the checklist rather than buried elsewhere: national cloud availability for the change notification subscription specifically is not stated in the change notifications how-to. The Global, GCC, and DOD “supported” and China “not supported” availability documented for the getAllEnterpriseInteractions GET endpoint does not automatically extend to the webhook subscription for the same resource. If your deployment targets a US government cloud, verify subscription availability with Microsoft before assuming it.

What this means for you: walk all nine checks end to end before your first production run — a subscription that creates cleanly can still drop events silently, and only this checklist confirms every gate is closed.


Now What? Your Next Three Steps

  • Create a test subscription with a one-hour expiry — validate the handshake response and confirm your endpoint returns the plain text token correctly before you add lifecycleNotificationUrl or includeResourceData to the request.
  • Run a Copilot interaction in Teams or Copilot Chat and watch for the notification — verify it arrives at your endpoint within the expected latency window, and use clientState to confirm it came from your subscription.
  • Design your reconciliation strategy — decide the polling interval for the getAllEnterpriseInteractions GET call that will catch events missed during endpoint downtime, and cross-reference Post 04 (Usage Reports) if you need the aggregate picture alongside per-event detail.

How to Navigate This Series

This series runs 13 posts across 3 phases, moving from API landscape and governance foundations through the core Copilot API surfaces into agent architecture and extensibility.

  • Phase 1 — Foundations and Governance (Posts 01–04):
    • API landscape orientation (Post 01)
    • Authentication and permissions deep-dive (Post 02)
    • Rate limits and national cloud readiness (Post 03)
    • Usage reporting (Post 04).
  • Phase 2 — Building with Core APIs (Posts 05–09):
    • Package Management API for admins (Post 05)
    • Retrieval API (Post 06), Chat API (Post 07)
    • Meeting AI Insights (Post 08)
    • AI Interactions Change Notifications (Post 09).
  • Phase 3 — Agents and Extensibility (Posts 10–13): Copilot Connectors, declarative versus custom engine agents, Copilot Studio, and integration patterns including SPFx.

By role:

  • New to the series: → Post 01 → Post 02 → Post 04 → Post 09
  • Building real-time audit or SIEM pipelines: → Post 02 → Post 04 → Post 08 → Post 09
  • Evaluating architecture and governance: → Post 01 → Post 04 → Post 09

Post 08 (Meeting AI Insights) covered a polling-style, GET-based retrieval of structured meeting intelligence — and a meeting-end event is a natural trigger for a Copilot interactions subscription, so the two posts together give you both meeting-scoped and general Copilot coverage. For the delegated-versus-application flows and admin consent patterns behind the AiEnterpriseInteraction scopes referenced here, see Post 02. For the aggregated, batch-polling counterpart to this event-driven API, see Post 04.

The immediate next post is Post 10 — Copilot Connectors, which turns the direction around: instead of observing Copilot’s output as this post does, Connectors make external data available to Copilot as an input.


References

All claims in this post trace to the following official Microsoft documentation:

Leave a Reply