Graph
Graph
OVERVIEW REFERENCE
What is Microsoft Graph? Microsoft Graph REST API
OVERVIEW OVERVIEW
Microsoft Graph Data Connect Microsoft Graph connectors
Users Groups
e Access and manipulate user resources directly. e Enable user collaboration and integration
across services.
Resources
Microsoft Graph is the gateway to data and intelligence in Microsoft 365. It provides a
unified programmability model that you can use to access the tremendous amount of
data in Microsoft 365, Windows, and Enterprise Mobility + Security. Use the wealth of
data in Microsoft Graph to build apps for organizations and consumers that interact
with millions of users.
Together, the Microsoft Graph API, connectors, and Data Connect power the Microsoft
365 platform. With the ability to access Microsoft Graph data and other datasets, you
can derive insights and analytics, extend Microsoft 365 experiences, and build unique,
intelligent applications.
Microsoft 365 core services: Bookings, Calendar, Delve, Excel, Microsoft 365
compliance eDiscovery, Microsoft Search, OneDrive, OneNote, Outlook/Exchange,
People (Outlook contacts), Planner, SharePoint, Teams, To Do, Viva Insights
Enterprise Mobility + Security services: Advanced Threat Analytics, Advanced
Threat Protection, Azure Active Directory, Identity Manager, and Intune
Windows services: activities, devices, notifications, Universal Print
Dynamics 365 Business Central services
To find out more, see Major services and features in Microsoft Graph.
Use Microsoft Graph to build experiences around the user's unique context to help them
be more productive. Imagine an app that...
Looks at your next meeting and helps you prepare for it by providing profile
information for attendees, including their job titles and managers, as well as
information about the latest documents they're working on, and people they're
collaborating with.
Scans your calendar, and suggests the best times for the next team meeting.
Fetches the latest sales projection chart from an Excel file in your OneDrive and lets
you update the forecast in real time, all from your phone.
Subscribes to changes in your calendar, sends you an alert when you're spending
too much time in meetings, and provides recommendations for the ones you can
miss or delegate based on how relevant the attendees are to you.
Helps you sort out personal and work information on your phone; for example, by
categorizing pictures that should go to your personal OneDrive and business
receipts that should go to your OneDrive for Business.
Analyzes at-scale Microsoft 365 data so that decision makers can unlock valuable
insights into time allocation and collaboration patterns that improve business
productivity.
Brings custom business data into Microsoft Graph, indexing it to make it
searchable along with data from Microsoft 365 services.
Pick the first scenario about researching meeting attendees as an example. With the
Microsoft Graph API, you can:
Microsoft Graph continues to open up the Microsoft 365 platform for developers, and
always only with the appropriate permissions.
7 Note
When you use the Microsoft Graph API, you agree to the Microsoft APIs Terms of
Use and the Microsoft Privacy Statement .
Operation URL
GET my https://graph.microsoft.com/v1.0/me
profile
GET my https://graph.microsoft.com/v1.0/me/photo/$value
photo
GET my https://graph.microsoft.com/v1.0/me/events
calendar
events
GET my https://graph.microsoft.com/v1.0/me/manager
manager
GET https://graph.microsoft.com/v1.0/me/memberOf/$/microsoft.graph.group?
Microsoft $filter=groupTypes/any(a:a%20eq%20'unified')
365 groups
I'm a
member of
GET my https://graph.microsoft.com/v1.0/me/onenote/notebooks
notes
Microsoft Graph connectors create connections to external data sources, index the data,
and store it as external custom items and files. Once indexed, those items can show up
in Microsoft Search and for apps that use the Microsoft Search API.
Using Azure tools, you can then build intelligent apps that:
Data Data is protected while in Data protection is extended to the cache of data in
protection Microsoft 365 your Azure subscription
Next steps
Check out some partner solutions.
Try a sample request in the Graph Explorer.
Use the quick start to set up a ready-to-run sample app.
Look under Learn in the table of contents to read about services and features that
you can use in your scenarios.
Learn about metered APIs and services in Microsoft Graph.
Find out how to get an auth token in your app.
Start using the API.
Major services and features in Microsoft
Graph
Article • 03/14/2023
Microsoft Graph enables you to integrate with the best of Microsoft 365, Windows, and
Enterprise Mobility + Security services in Microsoft 365, using REST APIs and client
libraries. Additionally, it offers security and intelligence that can boost user productivity,
creativity, and team collaboration, and protect business resources and users' data.
A user in Microsoft Graph is one among the millions who use Microsoft 365 cloud
services. It is the focal point whose identity is protected and access is well-managed. The
user's data is what drives businesses. Microsoft Graph services make this data available
to businesses in rich contexts, real-time updates, and deep insights, and always only
with the appropriate permissions.
A Microsoft 365 group is the fundamental entity that lets users collaborate. It integrates
with other services, enabling richer scenarios in task planning, teamwork, education, and
more.
Users Azure Active Directory (Azure The user is a core focus of Microsoft Overview of
AD) and most productivity, Graph, around which many Microsoft users in
collaboration, intelligence, Graph services build user-centric Microsoft
and education services functionality. Graph
Groups Azure AD, OneDrive, A Microsoft 365 group provides the Overview of
OneNote, Outlook, Planner fundamental collaborative unit for Microsoft 365
users to share conversations, files, groups in
notes, calendar, plans, and more. Microsoft
Graph
by category.
Identity and Azure AD Creates and manages directory resources such as Azure AD
access users, groups, and applications. Manages access to identity and
management resources and data. Gives customers access to sign- access
in and account risk data in Azure AD. management
overview
Productivity
Feature Supporting Description More
services information
Calendar Outlook Lets users set up appointments and meetings on the Outlook
web and on mobile and desktop devices. It is part of calendar
the Outlook messaging communication hub in overview
Microsoft 365 that also lets users manage emails and
contacts.
Files OneDrive Manages and shares user files on OneDrive and OneDrive
and SharePoint. files storage
SharePoint overview
Notes OneNote Lets users plan and organize ideas and information. OneNote
notes
overview
Personal Outlook Contacts manager on the web and on mobile and Outlook
contacts desktop devices. It is part of the Outlook messaging personal
communication hub in Microsoft 365 that also lets contacts
users manage emails and schedule meetings. overview
To-do tasks To Do Lets users manage their personal tasks across work To Do tasks
and life. It is also integrated with Outlook, Teams, overview
Planner, and Cortana, which makes it the single
destination for user's personal tasks in Microsoft 365.
Calls and Microsoft Lets apps and services interact with users through Overview for
online Teams, various communications-related features; for using
meetings Skype example, enabling bots to handle calls, integrating Microsoft
online meetings in line of business scenarios, Teams,
showing users' presence status (preview), and Shifts, and
looking up records for calls and online meetings Viva
(preview). Learning to
foster
teamwork
Shift Microsoft Lets managers and frontline workers manage staff Overview for
management Shifts scheduling or capture data from workforce using
management systems to create optimized Microsoft
schedules for a business. Teams,
Shifts, and
Viva
Learning to
foster
teamwork
Sites and SharePoint Web-based platform for users and Microsoft 365 SharePoint
lists groups to share, organize, manage, and discover sites and
content (including lists, files, and notes). content
overview
Tasks and Planner Enables users in Microsoft 365 groups to create Planner
plans plans, assign tasks, and track progress. plans and
tasks
overview
Feature Supporting Description More
services information
Teamwork Microsoft Ultimate digital hub and chat-based workspace for Overview for
platform and Teams teams to share files, notes, calendar, and plans. using
messaging Microsoft
Teams,
Shifts, and
Viva
Learning to
foster
teamwork
People Azure AD, Gets information about persons as ordered by their People and
Outlook, relevance to a user, determined by the user's workplace
SharePoint, communication and collaboration patterns and intelligence
and more business relationships. in Microsoft
Graph
Profile Profile Provides a lightweight mechanism for storing and People and
(preview) retrieving information about people within a workplace
tenant. intelligence
in Microsoft
Graph
Profile card Profile card Provides a lightweight mechanism for an People and
customization administrator to customize the content that workplace
(preview) surfaces on the Microsoft 365 profile card within intelligence
an organization. in Microsoft
Graph
Document Delve, Uses advanced analytics and machine learning People and
insights OneDrive, techniques to get documents trending around, workplace
Outlook, viewed, modified, or shared by a user. intelligence
SharePoint in Microsoft
Graph
Browser Microsoft Microsoft Edge is one of the applications Using the Edge
management Edge that administrators manage through the API in Microsoft
Microsoft 365 admin center. As an Graph to
alternative to using the Microsoft 365 admin manage
center, apps can use the Microsoft Graph API browsers
to manage the same Edge settings
configured through the Microsoft 365 admin
center.
Cloud printing Universal Universal Print is a Microsoft 365 cloud- Cloud printing
Print based print infrastructure that enables a using Universal
simple, rich, and secure print experience for Print API
users and reduces administrative and
management effort for IT.
Corp Intune Enrolls and configures devices and manages Intune devices
management of mobile applications in your organization. and apps
devices and overview
apps
Service health Microsoft Provides access to the health status and Accessing
and 365 and message center posts about Microsoft cloud service health
communications Dynamics services. A notable example that uses the and
365 services service communications API is the Microsoft communications
365 admin center. in Microsoft
Graph
Security
Feature Supporting services Description More
information
Cross-device experiences
Feature Supporting Description More
services information
Cross- Activity Enables app experiences that transcend a single Overview for
device feed, device device, and instead move with the user from device cross-device
experiences relay to device regardless of its type and platform. experiences
) Important
The Microsoft Graph notifications API is deprecated and stopped returning data in
January 2022. For an alternative notification experience, see Microsoft Azure
Notification Hubs. For more information, see this blog post .
Usage reports
Feature Supporting services Description More
information
Reports Microsoft Teams, OneDrive, Outlook, Gets activity and usage Usage
SharePoint, Skype for Business, information of a supporting reports
Yammer service. overview
Education
Feature Supporting Description More
services information
Education Azure AD, Provides information relevant for education scenarios, Education
Education including schools, classes, students, teachers, and overview
assignment info. Enables ISVs to build applications for
the classroom that save teachers time and promote
teamwork and collaboration.
Business applications
Feature Supporting Description More
services information
Next steps
Look under Learn in the table of contents to read about services and features that
you can use in your scenarios.
Try a sample request in the Graph Explorer.
Use this quick start to set up a ready-to-run sample app.
What's new in Microsoft Graph
Article • 05/23/2023
See highlights of what's new in the recent two months in Microsoft Graph, what's added
earlier, and how you can share your ideas. For a detailed list of API-level updates, see
the API changelog.
) Important
Features, including APIs and tools, in preview status may change without notice,
and some may never be promoted to generally available (GA) status. Do not use
preview features in production apps.
Search | Index
Specify settings for the search experience of content in an external connection. For
example, a display template for search results, and a rule to select the display
template.
Collect configurable settings related to activities of connector content in an
external connection. These settings set rules to resolve the URL of an external item
to its ID , thereby identifying the external item.
Add instances of external activity on an external item. You can track the type of
external activity (such as viewed, modified, created, commented), the identity of
the user, group, or external group who performed the activity, and the result of
adding the activity.
Education
Get or update from class level assignment settings any grading category to weight
assignments differently when computing a class average grade.
The number of days that an attack simulation user is out of office during an attack
simulation and training campaign.
The last activity in a user's detailed online actions in an attack simulation and
training campaign.
Search | Query
Qualify a search query string with a query template, which supports KQL and query
variables.
Education
Teachers can activate an inactive assignment to signal that the assignment has
further action items for teachers or students.
Teachers can deactivate and mark an assignment as inactive to signal that the
assignment has no further action items for teachers and students.
Search | Index
Get or set the relative ranking importance of a property in a schema, to allow Microsoft
Search to determine the search relevance of the content.
Are there scenarios you'd like Microsoft Graph to support? Suggest and vote for
new features at Microsoft Feedback Portal . Some new features originate as
popular requests from the developer community. The Microsoft Graph team
regularly evaluates customer needs and releases new features in the following
order:
1. Debut in preview status. Any related REST API updates are in the beta
endpoint ( https://graph.microsoft.com/beta ).
Sign up for the Microsoft 365 developer program, get a free Microsoft 365
subscription, and start developing!
See also
Check out the Microsoft Graph developer blog periodically for release
announcements and helpful resources.
Browse details of Microsoft Graph API additions, and API behavior updates in the
changelog.
Find highlights of earlier releases.
Learn more about versioning, support, and breaking change policies for Microsoft
Graph.
Use Graph Explorer to try Microsoft
Graph APIs
Article • 11/03/2022
Graph Explorer is a developer tool that lets you learn about Microsoft Graph APIs. Use
Graph Explorer to try the APIs on the default sample tenant to explore capabilities, or
sign in to your own tenant and use it as a prototyping tool to fulfill your app scenarios.
This tool includes helpful features such as code snippets (C#, Java, JavaScript, Go and
PowerShell), Microsoft Graph Toolkit and adaptive cards integration, and more.
Graph Explorer handles the authentication process for you. Customize the experience by
collapsing the sidebar or changing the theme.
Get started
Graph Explorer is a web application hosted on the Microsoft Graph developer center. It's
an open-source project, and we welcome your contributions and feedback on GitHub .
Make requests
With Graph Explorer, you can make requests to the Microsoft Graph APIs to retrieve,
add, delete and update data. Your requests can send parameters, authorization details,
and any body data you require.
To create the request, you can either select a sample query from the menu at the left,
which fills in the query field, or you can choose to manually type your request in the
field. Once you run the request, you will get the HTTP response code and the response
will be displayed in the response preview area.
When you sign in to Graph Explorer and run the same query, the response is returned
with real data from the tenant that you signed in to.
) Important
For example, to run a POST request, select POST in the drop-down list for the HTTP
verb, and add a request body and request headers as appropriate.
Next steps
Try Graph Explorer.
Explore the different Graph Explorer features.
Contribute or provide feedback on GitHub .
Microsoft Graph tutorials
Article • 12/10/2022
Microsoft Graph tutorials are step-by-step training exercises that guide you through
creating a basic application that accesses data via Microsoft Graph. They are designed to
be completed within 30 minutes.
If you prefer to download a completed project, you can do so from one of the following
locations:
.NET microsoftgraph/msgraph-training-dotnet-core
Go microsoftgraph/msgraph-training-go
Java microsoftgraph/msgraph-training-java
JavaScript microsoftgraph/msgraph-training-javascript
PHP microsoftgraph/msgraph-training-php
PowerShell microsoftgraph/msgraph-training-powershell
Python microsoftgraph/msgraph-training-python
TypeScript microsoftgraph/msgraph-training-typescript
App-only authentication
In the app-only authentication tutorials, you create a basic command-line application
that has the following features:
If you prefer to download a completed project, you can do so from the project's
corresponding GitHub repository. Instructions for registering an application and
configuring the sample are located in each repository.
.NET microsoftgraph/msgraph-training-dotnet-core
Go microsoftgraph/msgraph-training-go
Java microsoftgraph/msgraph-training-java
JavaScript microsoftgraph/msgraph-training-javascript
PHP microsoftgraph/msgraph-training-php
PowerShell microsoftgraph/msgraph-training-powershell
Python microsoftgraph/msgraph-training-python
TypeScript microsoftgraph/msgraph-training-typescript
Next steps
After you complete a tutorial, you can learn more on Microsoft Learn or explore our
samples.
Microsoft Learn
For a deeper dive into Microsoft Graph, explore our Microsoft Graph learning paths:
Samples
If the tutorials aren't quite what you need, our Microsoft Graph samples cover more
scenarios and platforms, such as web apps and mobile apps.
Users you can reach with Microsoft
Graph
Article • 01/27/2023
Microsoft offers services and solutions that expand modern work and modern life.
As a developer, you can use the Microsoft Graph API to build applications that connect
to the millions of users that use Microsoft 365 products for work, school, and personal
productivity.
Microsoft 365
Enterprise Mobility + Security
Windows
With their consent, you can use Microsoft Graph to get access to users and
organizational data according to the services they are licensed to and the services and
features available in Microsoft Graph. To learn more, see Major services and features in
Microsoft Graph.
Next steps
Check out some partner solutions.
Try a sample request in the Graph Explorer.
Use the quick start to set up a ready-to-run sample app.
Look under Learn in the table of contents to read about services and features that
you can use in your scenarios.
Find out how to get an auth token in your app.
Start using the API.
National cloud deployments
Article • 03/08/2023
In addition to our global network of datacenters, Microsoft cloud services are available in
two separate national clouds. These national cloud versions are physical and logical
network-isolated instances of Microsoft enterprise cloud services that are confined
within the geographic borders of specific countries and operated by local personnel.
Each national cloud environment is unique and different than the Microsoft global
environment. It's important to be aware of some of these key differences when you
develop applications for national cloud environments; for example, registering
applications, acquiring tokens, and calling the Microsoft Graph API can be different.
This article provides information about the different Microsoft Graph national cloud
deployments and the capabilities that are available to developers within each.
7 Note
Microsoft Graph Data Connect does not support any of the national cloud
deployments.
https://www.youtube-nocookie.com/embed/R_3E0IVypRM
To learn more about access tokens and Microsoft Graph, see authentication basics. For
Azure AD authentication scenarios, see Azure AD authentication basics.
) Important
7 Note
Apps can only access organizational data through the national cloud endpoints.
This means that apps can only access data in tenants that are registered in the
specific national cloud. Apps that are trying to access consumer data associated
with Microsoft personal accounts through Microsoft Graph should use the global
service https://graph.microsoft.com . Access tokens acquired for a national cloud
deployment are not interchangeable with those acquired for the global service or
any other national cloud.
Supported features
The following Microsoft Graph features are generally available on the /v1.0 endpoint
across all national cloud deployments, except where noted.
Microsoft Graph features Microsoft Cloud for US Microsoft Cloud China operated
Government by 21Vianet
Access reviews ✔ ✔
Change notifications ✔ ✔
(subscriptions)
Directory extensions ✔ ✔
Excel ✔ ➖
Groups ✔ ✔
Microsoft Graph features Microsoft Cloud for US Microsoft Cloud China operated
Government by 21Vianet
OneDrive ✔ ✔*
Organizational contacts ✔ ✔
Outlook Calendar ✔ ✔
Outlook Mail ✔ ✔
Personal Contacts ✔ ✔
Privileged identity ✔ ✔
management
Planner ✔ ✔
Security ✔ ✔
SharePoint ✔ ✔
Teams ✔ ➖
To Do ✔ ➖
Users ✔ ✔
For more information about the availability of Microsoft 365 usage reports in national
clouds, see Working with Microsoft 365 usage reports in Microsoft Graph.
(*) Limited support for Exchange and OneDrive services only. Azure AD services aren't
supported.
) Important
Certain services and features that are in specific regions of the global service might
not be available in all of the national clouds. To find out what services are available,
see products available by region .
Explore samples for authenticating and working with Azure and Microsoft 365 in
National cloud deployments:
Microsoft Graph has always provided access to customer mailboxes in the cloud on
Exchange Online as part of Microsoft 365. Exchange 2016 Cumulative Update 3 (CU3),
released in September 2016 for Exchange on-premises servers, added support for REST
API integration with Microsoft 365.
Effective March 2023, the ability to use these REST APIs in hybrid deployments will no
longer be available.
API requests are not currently blocked, but Microsoft will block these requests
beginning in March 2023.
For more information, see The End of REST API Integration for Exchange on-premises -
Preview .
Overview of metered APIs and services
in Microsoft Graph
Article • 03/16/2023
Microsoft Graph includes APIs that are available at no additional cost with user
subscription licenses and APIs and services that are metered. Metered APIs and services
in Microsoft Graph incur costs based on usage. The costs might be incurred per API call
made, per object returned in an API call, or through other measures.
Whether metered or not, APIs in Microsoft Graph follow these two principles:
Customer data ownership: Customer data belongs to the customer. Learn more
about how Microsoft categorizes customer data .
Reasonable access: The service provides access to customer content, within
defined limits.
Metering some APIs helps to ensure the health of the current and future Microsoft
Graph ecosystem by balancing platform access and cost. In the event that a Microsoft
Graph API that is included with user subscription licenses becomes metered, that would
be a non-backward compatible change and the versioning, support, and breaking
change policies for Microsoft Graph would apply.
For the list of metered APIs and services, see Metered APIs and services.
Standard APIs
Most Microsoft Graph APIs are standard APIs. These APIs perform standard operations
(create, read, update, delete) on customer content and administrative endpoints.
Reasonable access limits for these APIs are defined based on documented usage
thresholds. This helps to ensure a positive customer experience and encourages efficient
API usage patterns. Access to standard APIs within the defined usage thresholds is
available as part of the user license without additional costs.
High-capacity APIs
High-capacity APIs ensure that customers and developers have access to data at scale.
This category includes purpose-built, bulk export or import endpoints and Microsoft
Graph services. These APIs may be metered and incur additional costs beyond user
subscription licenses.
Advanced APIs
Advanced APIs provide access to enriched or aggregated data, or advanced functionality
that extends from Microsoft 365. The assignSensitivityLabel API is an example of an
advanced API. These APIs may be metered and incur additional costs beyond user
subscription licenses.
Metered APIs can return errors related to your subscription status in addition to
other common errors. For details about Microsoft Graph errors, see Microsoft
Graph errors and resource types.
Metered APIs are billed according to API usage. Be sure to understand the
metering unit so that you can estimate the costs associated with a particular API.
Known limitations
The following limitations apply to metered APIs:
Metered APIs and services in Microsoft Graph are currently available only in the
Microsoft global environment and not in national cloud deployments, including
Microsoft 365 GCC deployments accessed through the worldwide Microsoft Graph
endpoint. For details about national clouds, see National cloud deployments.
The target application must be a confidential client application (for example, web
application, web API, or daemon/service). Public client applications (desktop and
mobile applications) are not supported.
See also
Metered APIs and services in Microsoft Graph
Enable metered APIs and services in Microsoft Graph
Payment models and licensing requirements for Microsoft Teams APIs
Metered APIs and services in Microsoft
Graph
Article • 03/16/2023
This article provides a list of metered APIs and services in Microsoft Graph. To call these
APIs and services, you must associate an active Azure subscription with the calling
application. For details, see Overview of metered APIs and services in Microsoft Graph.
Some metered APIs and services in Microsoft Graph are protected and require
additional validation beyond permissions and admin consent. Before you can use these
protected APIs, you must submit a request.
Teams chat export Teams API payment models and Microsoft Teams
licensing requirements request
Teams channel export Teams API payment models and Microsoft Teams
licensing requirements request
Teams chat / channel change Teams API payment models and Microsoft Teams
notifications licensing requirements request
Teams conversationMember change Teams API payment models and Microsoft Teams
notifications licensing requirements request
Teams chat / channel message Teams API payment models and Microsoft Teams
PATCH operations licensing requirements request
SharePoint and OneDrive for No charge while API is in preview SharePoint preview
Business assignSensitivityLabel enrollment form
See also
Overview of metered APIs and services in Microsoft Graph
Enable metered APIs and services in Microsoft Graph
Protected APIs in Microsoft Teams
Versioning, support, and breaking
change policies for Microsoft Graph
Article • 06/15/2022
This article describes the support and breaking change policies for Microsoft Graph and
the versions of the Microsoft Graph API that are currently available.
As new versions of the Microsoft Graph REST APIs and Microsoft Graph SDKs are
released, earlier versions will be retired. Microsoft declares a version as deprecated at
least 24 months in advance of retiring it. Similarly, for individual APIs that are generally
available (GA), Microsoft declares an API as deprecated at least 24 months in advance of
removing it from the GA version.
When we increment the major version of the API (for example, from v1.0 to v2.0), we are
announcing that the current version (in this example, v1.0) is immediately deprecated
and we will no longer support it 24 months after the announcement. We might make
exceptions to this policy for service security or health reliability issues.
When an API is marked as deprecated, we strongly recommend that you migrate to the
latest version as soon as possible. In some cases, we will announce that new applications
will have to start using the new APIs a short time after the original APIs are deprecated.
In those cases, only active applications that currently use the deprecated APIs can
continue to use them.
Note: Over time, we will update the list of backward compatible changes. If you
generate your own client proxies (like WCF clients), our guidance is that your client
applications should be prepared to receive properties and derived types not
previously defined by the Microsoft Graph API service. Microsoft Graph API follows
the guidance described in the Model Versioning section in the Microsoft REST API
guidelines .
Versions
The following versions of the Microsoft Graph API are currently available.
Beta version
In general, APIs debut in the beta version and are accessible in the
https://graph.microsoft.com/beta endpoint. For beta API documentation, see Microsoft
Graph beta endpoint reference. Expect breaking changes and deprecation of APIs in the
beta version from time to time. Do not take a production dependency on beta APIs.
We make no guarantees that a beta feature will be promoted to the current version.
When the Microsoft Graph API team believes that a beta feature is ready for general
availability, we will add that feature to the latest current version. If the promotion of the
feature would result in a breaking change to the current version, the version number will
be incremented, with the new version becoming the current version. Our developer
community can post feature requests on the Microsoft 365 Developer Platform ideas
forum , including requests for new features as well as requests to promote existing
beta APIs to the current version.
Current version
The current version of Microsoft Graph is v1.0. Exposed under
https://graph.microsoft.com/v1.0 , the Microsoft Graph API v1.0 version contains
features that are generally available and ready for production use. Browse the
documentation for the v1.0 APIs.
Preview status
An API or feature in Microsoft Graph is labelled as "(preview)" to indicate its behavior is
unique in the beta endpoint.
The behavior of most APIs and features in the v1.0 version is in parity with the beta
version. "preview" qualifies a minority of APIs and features in one of the following two
cases:
Like any other API in the beta endpoint, APIs marked in the documentation as "
(preview)" may experience breaking changes without notice. Do not access APIs from
the beta endpoint in production apps.
As an example, attack simulation training is a feature that has been generally available
for administrators in the Microsoft 365 Defender portal . When the REST API for attack
simulation training becomes available in Microsoft Graph in only the beta endpoint, the
REST API documentation is labelled as "(preview)". The "(preview)" label applies to the
REST API and its documentation in Microsoft Graph, even though the service itself is
generally available.
Terms of use
By using the Microsoft Graph APIs, you agree to the Microsoft APIs Terms of Use.
Your feedback is important to us. Connect with us on Microsoft Q&A. Tag your
questions with [microsoft-graph-*].
Microsoft APIs Terms of Use
Article • 09/26/2022
1. Defined Terms
a) "Customer(s)" means the licensee of a Microsoft online service ("Microsoft Offering")
and if the licensee is an organization, includes their administrators and end users.
b) "Microsoft APIs" means (i) any form of machine accessible application programming
interface that Microsoft makes available which provides access to a Microsoft Offering,
including all associated tools, elements, components and executables therein, (ii) any
Microsoft sample code that enables interactions with a Microsoft Offering, and (iii)
documentation that Microsoft makes available to help enable your access to the
Microsoft APIs.
c) "Microsoft email protocols and APIs" may include and means IMAP, POP, MAPI, RPC
over HTTP, Outlook REST API, Outlook APIs in Microsoft Graph API, Exchange Web
Services ("EWS"), Exchange Active Sync ("EAS"), Exchange Management Shell and any
Exchange online APIs in the Microsoft APIs, individually or in any combination, when
used to provide access to a Microsoft Offering.
1. if you have entered into another agreement with Microsoft that expressly
supersedes these API Terms and governs your use of specific Microsoft APIs, or
2. for any APIs other than the APIs listed in section 1.d) of these terms, if you access
APIs that present accompanying terms ("Accompanying Terms") and you have
accepted those Accompanying Terms, then those Accompanying Terms will apply
to your access of those APIs.
1. Use the Microsoft APIs in a way that could impair, harm or damage Microsoft, the
Microsoft APIs, any Microsoft Offering, or anyone's use of the Microsoft APIs or
any Microsoft Offerings;
2. Use the Microsoft APIs to disrupt, interfere with, or attempt to gain unauthorized
access to services, servers, devices, or networks connected to or which can be
accessed via the Microsoft APIs;
3. Use the Microsoft APIs, or any information accessed or obtained using the
Microsoft APIs, for the purpose of migrating Customers away from a Microsoft
Offering, except in connection with use of the Microsoft APIs by your Application
or unless expressly permitted by Microsoft pursuant to a duly executed written
agreement;
4. Scrape, build databases or otherwise create copies of any data accessed or
obtained using the Microsoft APIs, except as necessary to enable an intended
usage scenario for your Application;
5. Request from the Microsoft APIs more than the minimum amount of data, or more
than the minimum permissions to the types of data, that your Application needs
for Customers to use the intended functionality of your Application;
6. Use an unreasonable amount of bandwidth, or adversely impact the stability of the
Microsoft APIs or the behavior of other apps using the Microsoft APIs;
7. Attempt to circumvent the limitations Microsoft sets on your use of the Microsoft
APIs. Microsoft sets and enforces limits on your use of the Microsoft APIs (e.g.,
limiting the number of API requests that you may make or the number of users
you may serve), in its sole discretion;
8. Use Microsoft APIs in any manner that works around any technical limitations of
the Microsoft APIs or of the accessed Microsoft Offering, or reverse engineer,
decompile or disassemble the Microsoft APIs, except and only to the extent that
applicable law expressly permits, despite this limitation;
9. Use the Microsoft APIs, or any data obtained using the Microsoft APIs, to conduct
performance testing of a Microsoft Offering unless expressly permitted by
Microsoft pursuant to a duly executed written agreement;
10. Use the Microsoft APIs, or any data obtained using the Microsoft APIs, to identify,
exploit or publicly disclose any potential security vulnerabilities;
11. Request, use or make available any data obtained using the Microsoft APIs outside
any permissions expressly granted by Customers in connection with using your
Application;
12. Use or transfer any data accessed or obtained using the Microsoft APIs, including
any data aggregated, anonymized or derived from that data (collectively the
"Microsoft APIs Data") for advertising or marketing purposes including (i) targeting
ads, or (ii) serving ads. For purposes of clarity, this prohibition on using Microsoft
APIs Data for advertising or marketing purposes does not extend to using other
data, such as (i) the number of users of your Application, (ii) a user identifier you
independently receive from a user (e.g., an email address you receive when a user
enrolls to use your Application, a device identifier, or an advertising identifier), or
(iii) a product or service identifier that identifies a Microsoft Offering;
13. Make your Application available for use in a manner that circumvents the need for
users to obtain a valid license to the Microsoft application or service that is
accessed through the Microsoft APIs;
14. Redistribute or resell, or sublicense access to, the Microsoft APIs, any data
obtained using the Microsoft APIs, or any other Microsoft Offering accessed
through the Microsoft APIs; or
15. Misrepresent expressly, by omission, or implication, the need for users to obtain a
valid license to the Microsoft application or service that is accessed through the
Microsoft APIs;
16. Falsify or alter any unique referral identifier in, or assigned to an Application, or
otherwise obscure or alter the source of queries coming from an Application to
hide a violation of this agreement; or
17. Use the Microsoft APIs or allow any user to use the Application in a way that
violates applicable law, including:
a. Illegal activities, such as child pornography, gambling, piracy, violating
copyright, trademark or other intellectual property laws.
b. Intending to exploit minors in any way.
c. Accessing or authorizing anyone to access the Microsoft APIs from an
embargoed country as prohibited by the U.S. government.
d. Threatening, stalking, defaming, defrauding, degrading, victimizing or
intimidating anyone for any reason.
e. Violating applicable privacy laws and regulations.
18. Use the Microsoft APIs in a way that could create, in Microsoft's sole discretion and
judgment, an unreasonable risk to Customers from a security or privacy
perspective.
c) Accessing the Exchange and Outlook Services through Microsoft email protocols
and APIs
Unless you have use permissions expressly and specifically granted by Customers in
connection with using your Application, you may not use Microsoft email protocols and
APIs for any purpose other than:
When your Application or services access an Intune API in Microsoft Graph using a Post
command, for example, such as documented at https://learn.microsoft.com/graph, you
must include:
When your Application or services access a Microsoft API for Microsoft OneDrive, other
than the work files of a user or work files created on behalf of a user, you may not
enable storage of system data in Microsoft OneDrive, the systems data including (i)
computer system back-up data, (ii) team, organization, or departmental level data, or (iii)
data related to any assignment of a per user license to a team, organization,
department, or other non-human entity. Such systems data can be stored in Microsoft
SharePoint shared libraries, which is a solution for more advanced content management
and collaboration, including storing and managing files, communications, and intranet
sites across a team or organization.
f) Accessing the Microsoft Yammer Service through a Microsoft API
When your Application or services access a Microsoft API for Yammer, you must adhere
to the following requirements:
1. Contact and Cooperation. You (or the name of the contact you gave to Microsoft
when you applied for your application key if it's not you) must be reachable at all
times for privacy and security questions or concerns. You can change this name or
contact by signing up for a new application key, and providing the correct contact
information and using the new application key instead.
2. Reporting. In addition to the vulnerabilities and data breach requirements of
section 4. Security, you must promptly report any security deficiencies in or
intrusions to your Application or services systems that you discover to Microsoft in
writing via email to [email protected]. You will work with Microsoft to
immediately correct any security deficiency and will disconnect immediately any
intrusions or intruder. In the event of any such security deficiency or intrusion, you
will make no public statements (e.g., press, blogs, social media, bulletin boards,
etc.) without prior written and express permission from Microsoft in each instance.
3. Branding. If your product or service uses or is based upon accessing the Microsoft
Yammer service through a Microsoft API, and you wish to include Yammer
branding or logos, please contact us at [email protected]. Absent express
written permission from us, you may not use Yammer branding, except as outlined
in section 3. f) 4. below.
4. Attribution. The images provided to you through the accessing the Microsoft
Yammer service through a Microsoft API may contain the trade names, trademarks,
service marks, logos, domain names, and other distinctive brand features of
Microsoft and its partners. You may not delete or in any manner alter these trade
names, trademarks, service marks, logos, domain names, and other distinctive
brand features. You agree to maintain, and not to remove, modify, obscure or alter,
any link or notices appearing on any image provided through the Service.
4. Security
You warrant that your Application has been developed to operate with Microsoft API
content in a secure manner. Your network, operating system and the software of your
servers, databases, and computer systems (collectively, "Systems") must be properly
configured to securely operate your Application and store content collected through
your Application (including the Microsoft API content). Your Application must use
reasonable security measures to protect the private data of your users.
We may use technology to detect, prevent or limit the impact of any issues caused by
your Application (before, after, or instead of suspension of your access). This may
include, for example, (i) filtering to stop spam, (ii) performing security or privacy
monitoring regarding scraping, denial of service attacks, user impersonation, application
impersonation, or illicit consent grant(s), or (iii) limiting or terminating your access to the
Microsoft APIs.
You will permit Microsoft reasonable access to your Application for purposes of
monitoring compliance with these API Terms. You will respond to any questions by
Microsoft about your compliance with these API Terms.
Without limiting the foregoing, upon request by Microsoft, you will provide us (or an
independent auditor acting on our behalf) with up to two full-feature client account-
level instances to access your Application (and/or other materials relating to your use of
the API) as reasonably requested by us to verify your compliance with these API Terms
(including, in particular, your security and privacy obligations under these API Terms).
We may restrict or terminate access to the APIs or perform an audit (including by hiring
an independent auditor acting on our behalf) of your Application if you fail to provide
adequate information and materials (including up to two full-featured instances of your
Application) to verify your compliance with these Terms.
You must have a process to respond to any vulnerabilities in your Application, and in the
case of any vulnerabilities related to your Application's connection to the Microsoft APIs
discovered by you or reported to you by a third party, you agree that you will provide
vulnerability details to the Microsoft Security Response Center ([email protected]).
In the event of a data breach by you resulting from any aspect of the Microsoft APIs
involving your Application or any data collected through your Application, you will
promptly contact the Microsoft Security Response Center ([email protected]) and
provide details of the data breach. You agree to refrain from making public statements
(e.g., press, blogs, social media, bulletin boards, etc.) without prior written and express
permission from Microsoft in each instance as it relates to the Microsoft APIs.
The rights and requirements of this section -- 4. Security -- will survive for five (5) years
following any termination of these API Terms.
a) obtain all necessary consents before processing data and obtain additional consent if
the processing changes ("Data Access Consents"),
b) In the event you're storing data locally, ensure that data is kept up to date and
implement corrections, restrictions to data, or the deletion of data as reflected in the
data obtained through your use of the Microsoft APIs,
c) implement proper retention and deletion policies, including deleting all data when
your user abandons your Application, uninstalls your Application, closes its account with
you, or abandons the account,
d) maintain and comply with a written statement available to Customers and users that
describes your privacy practices regarding data and information you collect and use
("Your Privacy Statement"), and that statement must be as protective as the Microsoft
Privacy Statement , and
e) When your Application allows end users to sign in with a Microsoft account and
Microsoft is not providing the user interface for the sign in, your Privacy Statement must
provide a link to https://account.live.com/consent/Manage and/or
https://myapps.microsoft.com , or such other location(s) as we may specify from time
to time, with a clear indication that Customers and end users can go to the Microsoft
site(s) to revoke Data Access Consents at any time. If Customers or end users must take
additional steps to disable your Application's access to Customer or end user data, then
Your Privacy Statement must clearly indicate to Customers and end users the additional
steps required to disable access.
WE MAY MODIFY THESE API TERMS AT ANY TIME, WITH OR WITHOUT PRIOR
NOTICE TO YOU. YOUR CONTINUED USE OF THE MICROSOFT APIs FOLLOWING THE
RELEASE OF A SUBSEQUENT VERSION OF THESE API TERMS WILL BE DEEMED YOUR
ACCEPTANCE OF ANY MODIFICATIONS TO THESE API TERMS.
7. Feedback
If you give feedback about the Microsoft APIs to Microsoft, you give to Microsoft,
without charge, the right to use, share and commercialize your feedback in any way and
for any purpose. You will not give feedback that is subject to a license that requires
Microsoft to license its software or documentation to third parties because Microsoft
includes your feedback in them. These rights survive these API Terms.
8. Confidentiality
You may be given access to certain non-public information, software, and specifications
relating to the Microsoft APIs ("Confidential Information"), which is confidential and
proprietary to Microsoft. You may use Confidential Information only as necessary in
exercising your rights granted under these API Terms. You may not disclose any
Confidential Information to any third party without Microsoft's prior written consent.
You agree that you will protect any Confidential Information from unauthorized use,
access, or disclosure in the same manner that you would use to protect your own
confidential and proprietary information.
b) Limitation of Liability
c) Indemnification
You will defend, hold harmless, and indemnify Microsoft from any claim or action
brought by a third party, including all damages, liabilities, costs and expenses, and
reasonable attorney fees, to the extent resulting from, alleged to have resulted from, or
in connection with your breach of the obligations herein or infringement of Microsoft's
or third party's intellectual property.
d) No Injunctive Relief
In no event shall you seek or be entitled to rescission, injunctive or other equitable relief,
or to enjoin or restrain the operation of the Microsoft APIs, content or other material
used or displayed through the current Microsoft website or successor site.
e) No Third-Party Beneficiaries
There are no third-party beneficiaries to this Agreement.
10. Termination
a) We may suspend or immediately terminate these API Terms, any rights granted
herein, and/or your license to the Microsoft APIs, in our sole discretion at any time, for
any reason. You may terminate these API Terms at any time by ceasing your access to
the Microsoft APIs.
b) Upon termination, all licenses granted herein immediately expire and you must cease
use of the Microsoft APIs. You must also comply with Customer's instruction to return or
delete any data accessed or obtained through the Microsoft APIs, unless expressly
permitted by Microsoft or prohibited by law. Neither party will be liable to the other for
any damages resulting solely from termination of these API Terms.
1. United States. If you reside in the United States, Washington state law governs the
interpretation of these API Terms and applies to claims for breach of it, regardless
of conflict of laws principles. The laws of the state where you live govern all other
claims, including claims under state consumer protection laws, unfair competition
laws, and in tort.
2. Outside the United States. If you reside in any other country, the laws of that
country apply.
b) Support. Because the Microsoft APIs are provided "as is," we may not provide
support services for them. You are solely responsible for the quality of your Application
and providing support for your Application.
c) Assignment and Delegation. You may not assign or delegate any rights or obligations
under these API Terms, including in connection with a change of control. Any purported
assignment and delegation shall be ineffective. We may freely assign or delegate all
rights and obligations under these API Terms, fully or partially without notice to you.
d) Reservation of Rights. All rights not expressly granted herein are reserved by
Microsoft. You acknowledge that all intellectual property rights within the Microsoft APIs
remain the property of Microsoft and nothing within these API Terms will act to transfer
any of these intellectual property rights to you.
e) Microsoft and you are independent contractors. Nothing in this Agreement shall be
construed as creating an employer-employee relationship, processor-subprocessor
relationship, a partnership, or a joint venture between the parties.
f) No Waiver. Either party's failure to act with respect to a breach of these API Terms
does not waive either party's right to act with respect to that breach or subsequent
similar or other breaches.
g) Survival. Sections of these API Terms that, by their terms, require performance after
the termination or expiration of these API Terms will survive, such as, for example, the
rights and requirements of section 4. Security.
h) Modifications. We may modify these API Terms at any time with or without individual
notice to you. Any modifications will be effective upon your continued use of the
Microsoft APIs.
i) Entire Agreement. These API Terms and any documents incorporated into these API
Terms by reference, constitute the entire agreement between you and us regarding the
Microsoft APIs and supersede all prior agreements and understandings, whether written
or oral, or whether established by custom, practice, policy or precedent, with respect to
the subject matter of these API Terms. If any provision of these API Terms is found to be
illegal, void, or unenforceable, the unenforceable provision will be modified so as to
render it enforceable to the maximum extent possible.
Overview of users in Microsoft Graph
Article • 01/27/2023
Users are the representation of an Azure Active Directory (Azure AD) work or school user
account or a Microsoft account in Microsoft Graph. The user resource in Microsoft
Graph is a hub from which you can access the relationships and resources that are
relevant to your users.
https://www.youtube-nocookie.com/embed/TUMPipN3UFI
To access a user's information and data, you'll need to get access on their behalf.
Authenticating your application with admin consent enables you to work with and
update a wider range of entities associated with a user.
API reference
Looking for the API reference for this service?
Next steps
The user resource type.
Training module: Build your skills and learn how to work with users through
Microsoft Graph.
What are the default user permissions in
Azure Active Directory?
Article • 03/13/2023
In Azure Active Directory (Azure AD), all users are granted a set of default permissions. A
user's access consists of the type of user, their role assignments, and their ownership of
individual objects.
This article describes those default permissions and compares the member and guest
user defaults. The default user permissions can be changed only in user settings in Azure
AD.
Member users can register applications, manage their own profile photo and
mobile phone number, change their own password, and invite B2B guests. These
users can also read all directory information (with a few exceptions).
Guest users have restricted directory permissions. They can manage their own
profile, change their own password, and retrieve some information about other
users, groups, and apps. However, they can't read all directory information.
For example, guest users can't enumerate the list of all users, groups, and other
directory objects. Guests can be added to administrator roles, which grant them full
read and write permissions. Guests can also invite other guests.
Users and Enumerate the Read their own Read their own
contacts list of all users properties properties
and contacts Read display name, Change their
Read all public email, sign-in name, own password
properties of photo, user principal Manage their
users and name, and user type own mobile
contacts properties of other users phone number
Invite guests and contacts
Change their Change their own
own password password
Manage their Search for another user
own mobile by object ID (if allowed)
phone number Read manager and direct
Manage their report information of
own photo other users
Invalidate their
own refresh
tokens
Area Member user Default guest user Restricted guest user
permissions permissions permissions
U Caution
Register Setting this option to No prevents users from creating application registrations.
applications You can then grant the ability back to specific individuals, by adding them to
the application developer role.
Allow users to Setting this option to No prevents users from connecting their work or school
connect work account with their LinkedIn account. For more information, see LinkedIn
or school account connections data sharing and consent.
account with
LinkedIn
Create security Setting this option to No prevents users from creating security groups. Global
groups administrators and user administrators can still create security groups. To learn
how, see Azure Active Directory cmdlets for configuring group settings.
Create Setting this option to No prevents users from creating Microsoft 365 groups.
Microsoft 365 Setting this option to Some allows a set of users to create Microsoft 365
groups groups. Global administrators and user administrators can still create Microsoft
365 groups. To learn how, see Azure Active Directory cmdlets for configuring
group settings.
Permission Setting explanation
How do I grant only a specific non-administrator users the ability to use the
Azure AD administration portal?
Set this option to Yes, then assign them a role like global reader.
Restrict non- Users can create tenants in the Azure AD and Entra administration portal under
admin users Manage tenant. The creation of a tenant is recorded in the Audit log as
from creating category DirectoryManagement and activity Create Company. Anyone who
tenants creates a tenant becomes the Global Administrator of that tenant. The newly
created tenant doesn't inherit any settings or configurations.
Restrict non- Setting this option to Yes restricts users from being able to self-service recover
admin users BitLocker key(s) for their owned devices. Setting this option to No allows users
from reading to recover their BitLocker key(s).
BitLocker
key(s) for their
owned devices
Read other This setting is available in Microsoft Graph and PowerShell only. Setting this flag
users to $false prevents all non-admins from reading user information from the
directory. This flag doesn't prevent reading user information in other Microsoft
services like Exchange Online.
The Restrict non-admin users from creating tenants option is shown below
7 Note
The Guest user access restrictions setting replaced the Guest users permissions
are limited setting. For guidance on using this feature, see Restrict guest access
permissions in Azure Active Directory.
Guest user Setting this option to Guest users have the same access as members grants all
access member user permissions to guest users by default.
restrictions
Setting this option to Guest user access is restricted to properties and
memberships of their own directory objects restricts guest access to only their own
user profile by default. Access to other users is no longer allowed, even when
they're searching by user principal name, object ID, or display name. Access to
group information, including groups memberships, is also no longer allowed.
This setting doesn't prevent access to joined groups in some Microsoft 365 services
like Microsoft Teams. To learn more, see Microsoft Teams guest access.
Guest users can still be added to administrator roles regardless of this permission
setting.
Guests can Setting this option to Yes allows guests to invite other guests. To learn more, see
invite Configure external collaboration settings.
Object ownership
An owner can also add or remove other owners. Unlike global administrators, owners
can manage only the applications that they own.
An owner can also add or remove other owners. Unlike global administrators, owners
can manage only the applications that they own.
An owner can also add or remove other owners. Unlike global administrators and user
administrators, owners can manage only the groups that they own.
Ownership permissions
The following tables describe the specific permissions in Azure AD that member users
have over owned objects. Users have these permissions only on objects that they own.
Action Description
Action Description
Owned devices
Action Description
Owned groups
7 Note
Action Description
Next steps
To learn more about the Guest user access restrictions setting, see Restrict guest
access permissions in Azure Active Directory.
To learn more about how to assign Azure AD administrator roles, see Assign a user
to administrator roles in Azure Active Directory.
To learn more about how resource access is controlled in Microsoft Azure, see
Understanding resource access in Azure.
For more information on how Azure AD relates to your Azure subscription, see
How Azure subscriptions are associated with Azure Active Directory.
Manage users.
Working with groups in Microsoft Graph
Article • 03/02/2023
Groups are collections of principals with shared access to resources in Microsoft services
or in your app. Different principals such as users, other groups, devices, and applications
can be part of groups. Using groups helps you avoid working with individual principals
and simplifies management of access to your resources.
Microsoft Graph exposes the groups API to create and manage different types of groups
and group functionality.
7 Note
7 Note
Only Microsoft 365 and security groups can be managed through the Microsoft Graph
groups API. Mail-enabled and distribution groups are read-only through Microsoft
Graph.
In Microsoft Graph, the type of group can be identified by the settings of its groupType,
mailEnabled, and securityEnabled properties as indicated in the table below.
Type groupType mailEnabled securityEnabled Created and
managed via the
groups API
For more information about groups, see the sections below. For more information about
groups in Azure AD, see compare groups in Azure AD.
Outlook conversations
Outlook calendar
SharePoint files
OneNote notebook
SharePoint team site
Planner plans
Intune device management
The following JSON object shows a sample representation of a group when you call the
Microsoft Graph groups API.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
"id": "4c5ee71b-e6a5-4343-9e2c-4244bc7e0938",
"deletedDateTime": null,
"classification": "MBI",
"createdDateTime": "2016-08-23T14:46:56Z",
"description": "This is a group in Outlook",
"displayName": "OutlookGroup101",
"groupTypes": [
"Unified"
],
"mail": "[email protected]",
"mailEnabled": true,
"mailNickname": "outlookgroup101",
"preferredLanguage": null,
"proxyAddresses": [
"smtp:[email protected]",
"SMTP:[email protected]"
],
"securityEnabled": false,
"theme": null,
"visibility": "Public"
}
To learn more about Microsoft 365 groups, see Overview of Microsoft 365 groups in
Microsoft Graph.
Group expiration
Group settings such as whether the group can have guests as members, who is
allowed to create groups, allowed words in group names, and so on.
Mail-enabled security groups are used in the same way as security groups, but can be
used to send emails to group members. Mail-enabled security groups can't be created
or updated through the API; instead, they're read-only. Learn more in the Manage mail-
enabled security groups Exchange article.
The following JSON object shows a sample representation of a security group when you
call the Microsoft Graph groups API.
HTTP
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.type": "#microsoft.graph.group",
"id": "f87faa71-57a8-4c14-91f0-517f54645106",
"deletedDateTime": null,
"classification": null,
"createdDateTime": "2016-07-20T09:21:23Z",
"description": "This group is a Security Group",
"displayName": "SecurityGroup101",
"groupTypes": [],
"mail": null,
"mailEnabled": false,
"mailNickname": "",
"preferredLanguage": null,
"proxyAddresses": [],
"securityEnabled": true
}
Group membership
Not all object types can be members of both Microsoft 365 and security groups.
The following table shows the types of members that can be added to either security
groups or Microsoft 365 groups.
User
Security group
Device
Service principal
Organizational contact
Dynamic membership
Microsoft 365 and security groups can have dynamic membership rules that
automatically add or remove members from the group based on the principal's
properties. For example, a "Marketing employees" group can define a dynamic
membership rule that only users with their department property set to "Marketing" can
be members of the group. In this case, any user's who leave the department are
automatically removed from the group.
Only users and devices are supported as members in dynamic membership groups. You
can create a dynamic membership group for devices or users, but not both.
The dynamic membership rules are specified through the membershipRule property
during group creation. A single expression follows this syntax: Property Operator Value .
The rule syntax supports various operators. For more information, see Supported
expression operators.
A Value of type String must be enclosed in double quotes ("). You must use a
backslash to escape any double quotes inside double quotes. This requirement
doesn't apply when using the rule builder in the Azure portal because the
expression isn't enclosed in double quotes.
You can combine multiple expressions in a rule using the and , or , and not operators.
The groupType property must also include the "DynamicMembership" value in the
collection. The dynamic membership rule can be turned on or off through the
membershipRuleProcessingState property. You can update a group with assigned
membership to have dynamic membership.
The following example request creates a new Microsoft 365 group that can only include
employees in the Marketing department.
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/groups
Content-type: application/json
{
"description": "Marketing department folks",
"displayName": "Marketing department",
"groupTypes": [
"Unified",
"DynamicMembership"
],
"mailEnabled": true,
"mailNickname": "marketing",
"securityEnabled": false,
"membershipRule": "user.department -eq \"Marketing\"",
"membershipRuleProcessingState": "on"
}
The request returns a 201 Created response code and the newly created group object in
the response body.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
"id": "6f7cd676-5445-47c4-9c2b-c47da4671da2",
"createdDateTime": "2023-01-20T07:00:31Z",
"description": "Marketing department folks",
"displayName": "Marketing department",
"groupTypes": [
"Unified",
"DynamicMembership"
],
"mail": "[email protected]",
"mailEnabled": true,
"mailNickname": "marketing",
"membershipRule": "user.department -eq \"Marketing\"",
"membershipRuleProcessingState": "On"
}
To learn more about formulating membership rules, see Dynamic membership rules for
groups in Azure Active Directory.
7 Note
If the signed-in user is a guest user, depending on the permissions an app has been
granted, it can read the profile of a specific group (for example,
https://graph.microsoft.com/v1.0/group/fc06287e-d082-4aab-9d5e-d6fd0ed7c8bc );
however, it can't perform queries against the /groups resource that potentially returns
more than a single resource.
With the appropriate permissions, the app can read the profiles of groups that it obtains
by following links in navigation properties; for example, /groups/{id}/members .
For more information about what guest users can do with groups, see Compare
member and guest default permissions.
Group-based licensing
You can use group-based licensing to assign one or more product licenses to an Azure
AD group. Azure AD ensures that the licenses are assigned to all members of the group.
Any new members who join the group are assigned the appropriate licenses. When they
leave the group, those licenses are removed. The feature can only be used with security
groups and Microsoft 365 groups that have securityEnabled=TRUE . To learn more about
group-based licensing, see What is group-based licensing in Azure Active Directory?.
Create new groups, get existing groups, update the properties on group Create
groups, and delete groups. Currently, only security groups and new
groups in Outlook can be created through the API. groups
List
groups
Update
groups
Delete
groups
List the members of a group, and add or remove members. user List
group members
Add
member
Remove
member
Determine whether a user is a member of a group, get all the user Check
groups the user is a member of. group member
servicePrincipal groups
orgContact Get
member
groups
List the owners of a group, and add or remove owners. user List
group owners
Add
member
Remove
member
What's new
Find out about the latest new features and updates for this API set.
Overview of Microsoft 365 groups in
Microsoft Graph
Article • 05/20/2023
Microsoft 365 groups provide the foundational membership service for users to share
conversations, files, notes, calendars, plans, and many other assets.
https://www.youtube-nocookie.com/embed/WB9w6QM9xIU
Use the Create group API to provision a new group. The group is then made
available in a range of applications, such as Outlook, SharePoint, Microsoft Teams,
Planner, and even Microsoft Stream. Microsoft Graph synchronizes across these
connected services to seamlessly provide access to all group members.
Every Microsoft 365 group is integrated with a default set of Microsoft 365
services
Get information about the SharePoint site that's associated with a group, such as
the document library lists or subsites.
Create a plan in Planner that is owned by a group. The plan provides a visual way
to track teamwork by allowing you to create tasks that can be organized across
buckets.
Access the OneNote notebook associated with a group, which can be used for
collecting meeting notes and organizing ideas.
Delete groups. When a group is deleted, all associated content is also deleted,
which prevents orphaned sites, conversations, or plans.
Configure a broad range of group policy settings that help define behaviors, such
as automatically deleting groups unless they are renewed by an owner and
enforcing naming policies on Microsoft 365 groups.
Renew groups that are about to expire to allow team members to continue with
collaboration and accessing content. If the group is not renewed according to the
established expiration policy, the group is automatically deleted.
Restore deleted groups.
API reference
Looking for the API reference for this service?
Next steps
Try out some sample API requests in Graph Explorer.
Learn more about how to use the groups API in Microsoft Graph.
Set Microsoft 365 group behaviors and
provisioning options
Article • 01/27/2023
Using the group resource in Microsoft Graph, you can set specific group behaviors and
resources to provision when creating a Microsoft 365 group. Depending on the
resource, some can also be provisioned on group update.
Configure groups
resourceBehaviorOptions is a string collection that specifies group behaviors for a
Microsoft 365 group. These behaviors can be set only on group creation ( POST ).
Provision groups
resourceProvisioningOptions is a string collection that specifies group resources to be
provisioned as part of the Microsoft 365 group. These resources can be specified during
group creation or update.
See also
Overview of Microsoft 365 groups in Microsoft Graph
Microsoft Teams API overview
Overview of group settings
Article • 05/13/2023
Group settings (also called directory settings in beta ) are a collection of settings that
allow you to configure either tenant-wide or object-specific allowed behaviors for
specific Azure AD objects like Microsoft 365 groups.
There are eight groups of setting templates with each setting template including a
collection of individual settings.
Group.Unified
Group.Unified.Guest
Application
Custom Policy Settings
Consent Policy Settings
Password Rule Settings
Prohibited Names Restricted Settings
Prohibited Names Settings
The setting templates are available through the groupSettingTemplates resource type in
v1.0 and directorySettingTemplates resource type in beta . These setting templates are
Initially, Azure AD assigns the default configuration to the tenant and there are no
setting objects. To change the default settings, you must create a new settings object
from a settings template.
From the setting templates, you can configure tenant-wide settings or settings for
individual objects. Use the groupSettings resource type in v1.0 or the directorySetting
resource type in beta and their associated APIs.
For groups, only settings for Microsoft 365 groups are available. The following article
describes only settings that are available for Microsoft 365 groups.
Group.Unified
The settings in this object specify whether guests can be added to all or specific
Microsoft 365 groups in the tenant.
Group.Unified.Guest
The settings in this object specify whether guests can be added to all or specific
Microsoft 365 groups in the tenant.
AllowToAddGuests Boolean Indicates whether guest users can be added to all or specific
Microsoft 365 groups. The default setting is true . This setting can
be overwritten when:
EnableMIPLabels is true and a guest policy is applied when a
sensitivity label is assigned to a group
AllowToAddGuests is false at the tenant-level, the group-
level setting is overwritten
Next steps
groupSettingTemplate resource type
groupSettings resource type
Applications API overview
Article • 01/27/2023
Application management
Application registration involves telling Azure AD about your application, including the
URL where it's located, the URL to send replies after authentication, the URI to identify
your application, and more. You can use the application APIs in Microsoft Graph to
manage applications programmatically.
https://www.youtube-nocookie.com/embed/93j0MmRruFo
Application model
Application and service principal objects in Azure Active Directory
Application types for Microsoft identity platform
For more information about application management, see the following articles:
For more information about on-premises publishing, see the following articles:
To learn about using the on-premises publishing APIs, see the following tutorial and its
associated APIs:
Automate the configuration of Application Proxy using the Microsoft Graph API
applicationTemplate
application
onPremisesPublishing
connector
connectorGroup
servicePrincipal
For more information about service principals, see Application and service principal
objects in Azure Active Directory.
Synchronization
You can use the synchronization APIs in Microsoft Graph to manage identity
synchronization programmatically, including:
To learn about using the synchronization APIs, see the following tutorials and their
associated APIs:
Next steps
Try the Microsoft Graph API in Graph Explorer.
Learn about how to add authentication and authorization to your web applications
and web APIs using these samples.
Manage an Azure AD application using
Microsoft Graph
Article • 03/02/2023
Your app must be registered in Azure AD before the Microsoft identity platform can
authorize it to access data stored in Azure Active Directory (Azure AD) or Microsoft 365
tenants. This condition applies to apps that you develop yourself, that are owned by
your organization, or that you access through an active subscription.
Many settings for apps are recorded as objects that can be accessed, updated, or
deleted using Microsoft Graph. In this article, you'll learn how to use Microsoft Graph to
manage app and service principal objects including the properties, permissions, and role
assignments.
Prerequisites
To complete this tutorial, you need the following resources and privileges:
Request
Least privilege delegated permission: Application.ReadWrite.All
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/applications
Content-type: application/json
{
"displayName": "My application"
}
Response
The following code is an example of the default response that includes all the properties
returned by default. The application is assigned an ID that's globally unique in the Azure
AD ecosystem.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#applications/$entity",
"id": "0d0021e2-eaab-4b9f-a5ad-38c55337d63e",
"deletedDateTime": null,
"appId": "5f0f8757-988d-474c-9f85-74a6bc70dfd0",
"applicationTemplateId": null,
"disabledByMicrosoftStatus": null,
"createdDateTime": "2022-02-08T08:58:36.7669085Z",
"displayName": "My application",
"description": null,
"groupMembershipClaims": null,
"identifierUris": [],
"isDeviceOnlyAuthSupported": null,
"isFallbackPublicClient": null,
"notes": null,
"publisherDomain": "M365x010717.onmicrosoft.com",
"serviceManagementReference": null,
"signInAudience": "AzureADandPersonalMicrosoftAccount",
"tags": [],
"tokenEncryptionKeyId": null,
"defaultRedirectUri": null,
"certification": null,
"optionalClaims": null,
"addIns": [],
"api": {
"acceptMappedClaims": null,
"knownClientApplications": [],
"requestedAccessTokenVersion": 2,
"oauth2PermissionScopes": [],
"preAuthorizedApplications": []
},
"appRoles": [],
"info": {
"logoUrl": null,
"marketingUrl": null,
"privacyStatementUrl": null,
"supportUrl": null,
"termsOfServiceUrl": null
},
"keyCredentials": [],
"parentalControlSettings": {
"countriesBlockedForMinors": [],
"legalAgeGroupRule": "Allow"
},
"passwordCredentials": [],
"publicClient": {
"redirectUris": []
},
"requiredResourceAccess": [],
"verifiedPublisher": {
"displayName": null,
"verifiedPublisherId": null,
"addedDateTime": null
},
"web": {
"homePageUrl": null,
"logoutUrl": null,
"redirectUris": [],
"implicitGrantSettings": {
"enableAccessTokenIssuance": false,
"enableIdTokenIssuance": false
}
},
"spa": {
"redirectUris": []
}
}
in with any account type, including Azure AD accounts, personal Microsoft accounts,
and social media credentials, can use your app. You can change the signInAudience to a
different scope.
If you created the application as a user with administrator privileges, you were
automatically assigned ownership to the application. You can confirm ownership by
retrieving the owners navigation property through GET
https://graph.microsoft.com/v1.0/applications/0d0021e2-eaab-4b9f-a5ad-
38c55337d63e/owners . You can also assign another user or app ownership of the
application.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/0d0021e2-eaab-4b9f-
a5ad-38c55337d63e/
Content-type: application/json
{
"tags": [
"HR",
"Payroll",
"HideApp"
],
"info": {
"logoUrl": "https://cdn.pixabay.com/photo/2016/03/21/23/25/link-
1271843_1280.png",
"marketingUrl": "https://www.contoso.com/app/marketing",
"privacyStatementUrl": "https://www.contoso.com/app/privacy",
"supportUrl": "https://www.contoso.com/app/support",
"termsOfServiceUrl":
"https://www.contoso.com/app/termsofservice"
},
"web": {
"homePageUrl": "https://www.contoso.com/",
"logoutUrl": "https://www.contoso.com/frontchannel_logout",
"redirectUris": [
"https://localhost"
]
},
"serviceManagementReference": "Owners aliases: Finance @
[email protected]; The Phone Company HR consulting @
[email protected];"
}
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/servicePrincipals/89473e09-0737-
41a1-a0c3-1418d6908bcd
{
"appRoleAssignmentRequired": true
}
Assigning permissions doesn't automatically grant them to the app. You must still grant
admin consent using the Azure portal. To grant permissions without interactive consent,
see Grant or revoke API permissions programmatically.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/581088ba-83c5-4975-
b8af-11d2d7a76e98
Content-Type: application/json
{
"requiredResourceAccess": [
{
"resourceAppId": "00000002-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "311a71cc-e848-46a1-bdf8-97ff7156d8e6",
"type": "Scope"
},
{
"id": "3afa6a7d-9b1a-42eb-948e-1650a849e176",
"type": "Role"
}
]
}
]
}
Create app roles
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/bbd46130-e957-4c38-
a116-d4d02afd1057
Content-Type: application/json
{
"appRoles": [
{
"allowedMemberTypes": [
"User",
"Application"
],
"description": "Survey.Read",
"displayName": "Survey.Read",
"id": "7a9ddfc4-cc8a-48ea-8275-8ecbffffd5a0",
"isEnabled": false,
"origin": "Application",
"value": "Survey.Read"
}
]
}
Manage owners
This request requires the ConsistencyLevel header set to eventual because $count is in
the request. For more information about the use of ConsistencyLevel and $count , see
Advanced query capabilities on Azure AD directory objects.
This request also returns the count of the apps that match the filter condition.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/servicePrincipals?
$filter=owners/$count eq 0 or owners/$count eq 1&$count=true
ConsistencyLevel: eventual
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/applications/7b45cf6d-9083-4eb2-
92c4-a7e090f1fc40/owners/$ref
Content-Type: application/json
{
"@odata.id":
"https://graph.microsoft.com/v1.0/directoryObjects/8afc02cb-4d62-4dba-
b536-9f6d73e9be26"
}
The following request references the service principal using its appId. 8afc02cb-4d62-
4dba-b536-9f6d73e9be26 is the object ID for a user or service principal.
HTTP
POST https://graph.microsoft.com/v1.0/servicePrincipals(appId='46e6adf4-
a9cf-4b60-9390-0ba6fb00bf6b')/owners/$ref
Content-Type: application/json
{
"@odata.id":
"https://graph.microsoft.com/v1.0/directoryObjects/8afc02cb-4d62-4dba-b536-
9f6d73e9be26"
}
See also
Properties of an enterprise application (service principal)
Add a certificate to an app using Microsoft Graph
Validation differences by supported
account types (signInAudience)
Article • 04/03/2023
When registering an application with the Microsoft identity platform for developers, you're
asked to select which account types your application supports. You can refer to the Help me
choose link under Supported account types during the registration process. The value you
select for this property has implications on other app object properties.
After the application has been registered, you can check or change the account type that the
application supports at any time. Under the Manage pane of your application, search for
Manifest and find the signInAudience value. The different account types, and the
corresponding signInAudience are shown in the following table:
If you change this property you may need to change other properties first.
Validation differences
See the following table for the validation differences of various properties for different
supported account types.
Certificates ( keyCredentials ) Symmetric signing Symmetric signing Encryption and asymmetric signing
key key key
Scopes defined by this API Maximum scope Maximum scope Maximum scope name length of 40
( oauth2Permissions ) name length of name length of 120 characters
120 characters characters
Maximum of 100 scopes defined
No limit* on the No limit* on the
number of scopes number of scopes
defined defined
http scheme isn't http scheme isn't http scheme isn't allowed
allowed allowed
Maximum length of 255 characters
Maximum length Maximum length of
of 255 characters 255 characters Wildcards aren't supported
Tags Individual tag size Individual tag size Individual tag size must be between
must be between must be between 1 1 and 256 characters (inclusive)
1 and 256 and 256 characters
characters (inclusive) No whitespaces or duplicate tags
(inclusive) allowed
No whitespaces or
No whitespaces or duplicate tags No limit* on number of tags
duplicate tags allowed
allowed
No limit* on number
No limit* on of tags
number of tags
* There's a global limit of about 1000 items across all the collection properties on the app
object.
Next steps
For more information about application registrations and their JSON manifest, see:
Application registration
Application manifest
Grant or revoke API permissions
programmatically
Article • 04/19/2023
When you grant API permissions to a client app in Azure Active Directory (Azure AD),
the permission grants are recorded as objects that can be accessed, updated, or deleted
like your data. Using Microsoft Graph to directly create permission grants is a
programmatic alternative to interactive consent and can be useful for automation
scenarios, bulk management, or other custom operations in your organization.
In this guide, you'll learn how to grant and revoke app roles for an app using Microsoft
Graph. App roles, also called application permissions, or direct access permissions, allow
an app to call an API with its own identity.
U Caution
Prerequisites
To complete these instructions, you need the following resources and privileges:
U Caution
Request
The following request retrieves the app roles defined by the Microsoft Graph service
principal in the tenant.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/servicePrincipals?
$filter=displayName eq 'Microsoft
Graph'&$select=id,displayName,appId,appRoles
Response
The following object is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#servicePrincipals(id,displayName
,appId,appRoles)",
"value": [
{
"id": "7ea9e944-71ce-443d-811c-71e8047b557a",
"displayName": "Microsoft Graph",
"appId": "00000003-0000-0000-c000-000000000000",
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "Allows the app to read user profiles
without a signed in user.",
"displayName": "Read all users' full profiles",
"id": "df021288-bdef-4463-88db-98f22de89214",
"isEnabled": true,
"origin": "Application",
"value": "User.Read.All"
}
]
}
]
}
Request
The following request grants your client app (the principal of ID b0d9b9e3-0ecf-4bfd-
8dab-9273dd055a94 ) an app role of ID df021288-bdef-4463-88db-98f22de89214 that's
exposed by a resource service principal of ID 7ea9e944-71ce-443d-811c-71e8047b557a .
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/servicePrincipals/7ea9e944-71ce-
443d-811c-71e8047b557a/appRoleAssignedTo
Content-Type: application/json
{
"principalId": "b0d9b9e3-0ecf-4bfd-8dab-9273dd055a94",
"resourceId": "7ea9e944-71ce-443d-811c-71e8047b557a",
"appRoleId": "df021288-bdef-4463-88db-98f22de89214"
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#servicePrincipals('7ea9e944-
71ce-443d-811c-71e8047b557a')/appRoleAssignedTo/$entity",
"id": "47nZsM8O_UuNq5Jz3QValCxBBiqJea9Drc9CMK4Ru_M",
"deletedDateTime": null,
"appRoleId": "df021288-bdef-4463-88db-98f22de89214",
"createdDateTime": "2022-05-18T15:37:21.8215423Z",
"principalDisplayName": "My application",
"principalId": "b0d9b9e3-0ecf-4bfd-8dab-9273dd055a94",
"principalType": "ServicePrincipal",
"resourceDisplayName": "Microsoft Graph",
"resourceId": "7ea9e944-71ce-443d-811c-71e8047b557a"
}
To confirm all principals with role assignments to the resource service principal, run the
following request.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/servicePrincipals/7ea9e944-71ce-
443d-811c-71e8047b557a/appRoleAssignedTo
Response
The response object includes a collection of app role assignments to your resource
service principal and includes the app role assignment you created using the POST
request.
HTTP
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#servicePrincipals('7ea9e944-
71ce-443d-811c-71e8047b557a')/appRoleAssignedTo",
"value": [
{
"id": "47nZsM8O_UuNq5Jz3QValCxBBiqJea9Drc9CMK4Ru_M",
"deletedDateTime": null,
"appRoleId": "df021288-bdef-4463-88db-98f22de89214",
"createdDateTime": "2022-05-18T15:37:21.8997216Z",
"principalDisplayName": "My application",
"principalId": "b0d9b9e3-0ecf-4bfd-8dab-9273dd055a94",
"principalType": "ServicePrincipal",
"resourceDisplayName": "Microsoft Graph",
"resourceId": "7ea9e944-71ce-443d-811c-71e8047b557a"
}
]
}
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/servicePrincipals/7ea9e944-71ce-
443d-811c-
71e8047b557a/appRoleAssignedTo/47nZsM8O_UuNq5Jz3QValCxBBiqJea9Drc9CMK4Ru
_M
Response
HTTP
See also
Tutorial: Grant app roles in Azure AD using Microsoft Graph PowerShell
appRoleAssignment resource type
Add a certificate to an app using
Microsoft Graph
Article • 03/02/2023
Azure Active Directory (Azure AD) supports three types of credentials to authenticate
apps and service principals: passwords (app secrets), certificates, and federated identity
credentials. If you can't use federated identity credentials for your app, we strongly
recommend that you use certificates instead of secrets.
You can add or remove certificates using the Azure portal. However, in automation
scenarios, you may need to automate the certificate rollover for your app or service
principal.
This article provides guidance for using Microsoft Graph and PowerShell scripts to
update certificate credentials programmatically for an app registration.
Prerequisites
To complete this tutorial, you need the following resources and privileges:
U Caution
Request
PowerShell
Response
The output that's saved in the .txt file can be similar to the following.
PowerShell
Thumbprint Subject
---------- -------
5A126608ED1A1366F714A4A62B7015F3262840F1 CN=20230112
Request
PowerShell
[convert]::ToBase64String((Get-Content C:\Users\admin\Desktop\20230112.cer -
Encoding byte)) | Out-File -FilePath
"C:\Users\admin\Desktop\20230112.key.txt" ## Replace the file path with the
location of your certificate
Response
The output that's saved in the .txt file can be similar to the following.
Note: The key shown here has been shortened for readability.
PowerShell
MIIDADCCAeigAwIBAgIQP6HEGDdZ65xJTcK4dCBvZzANBgkqhkiG9w0BAQsFADATMREwDwYDVQQD
DAgyMDIzMDExMjAeFw0yMzAxMTIwODExNTZaFw0yNDAxMTIwODMxNTZaMBMxETAPBgNVBAMMCDIw
MjMwMTEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAseKf1weEacJ67D6/...dG+7W
MIBsIUy0xz6MmyvfSohz3oNP4jHt7pJ9TyxnvDlaxQPUbuIL+DaXVkKRm1V3GgIpKTBqMzTf4tCp
y7rpUZbhcwAFw6h9A==
Request
The following request adds the certificate details to an app. The settings are as follows:
The startDateTime is the date when or after the certificate was created.
The endDateTime can be a maximum of one year from the startDateTime. If
unspecified, the system will automatically assign a date one year after the
startDateTime.
The type and usage must be AsymmetricX509Cert and Verify respectively.
Assign the certificate subject name to the displayName property.
The key is the Base64 encoded value that you generated in the previous step.
7 Note
If your app has an existing valid certificate that you want to continue using for
authentication, include both the current and new certificate details in the app's
keyCredentials object. Because this a PATCH call, which by protocol replaces the
contents of the property with the new values, including only the new certificate will
replace the existing certificates with the new one.
The following example adds a new certificate and replaces any existing certificates.
Note: The key shown here has been shortened for readability.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/bb77f42f-dacb-4ece-
b3e6-285e63c24d52
Content-type: application/json
{
"keyCredentials": [
{
"endDateTime": "2024-01-11T15:31:26Z",
"startDateTime": "2023-01-12T15:31:26Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"key":
"base64MIIDADCCAeigAwIBAgIQP6HEGDdZ65xJTcK4dCBvZzANBgkqhkiG9w0BAQsFADATM
REwDwYDVQQDDAgyMDIzMDExMjAeFw0yMzAxMTIwODExNTZaFw0yNDAxMTIwODMxNTZaMBMxE
TAPBgNVBAMMCDIwMjMwMTEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAseKf1
weEacJ67D6/...laxQPUbuIL+DaXVkKRm1V3GgIpKTBqMzTf4tCpy7rpUZbhcwAFw6h9A=="
,
"displayName": "CN=20230112"
}
]
}
The following example adds a new certificate without replacing the existing certificate
that's identified by thumbprint 52ED9B5038A47B9E2E2190715CC238359D4F8F73 .
Note: The key shown here has been shortened for readability.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/bb77f42f-dacb-4ece-
b3e6-285e63c24d52
Content-type: application/json
{
"keyCredentials": [
{
"endDateTime": "2024-01-11T15:31:26Z",
"startDateTime": "2023-01-12T09:31:26Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"key":
"base64MIIDADCCAeigAwIBAgIQejfrj3S974xI//npv7hFHTANBgkqhkiG9w0BAQsFADATM
REwDwYDVQQDDAgyMDIzMDExNDAeFw0yMzAxMTIwOTA4NThaFw0yNDAxMTIwOTI4NThaMBMxE
TAPBgNVBAMMCDIwMjMwMTE0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt5vEj
6j1l5wOVHR4eDGe77HWslaIVJ1NqxrXPm/...+R+U7sboj+kUvmFzXI+Ge73Liu8egL2NzOH
HpO43calWgq36a9YW1yhBQR1ioEchu6jmudW3rF6ktmVqQ==",
"displayName": "CN=20230114"
},
{
"customKeyIdentifier":
"52ED9B5038A47B9E2E2190715CC238359D4F8F73",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"key":
"base64MIIDADCCAeigAwIBAgIQfoIvchhpToxKEPI4iMrU1TANBgkqhkiG9w0BAQsFADATM
REwDwYDVQQDDAgyMDIzMDExMzAeFw0yMzAxMTIwODI3NTJaFw0yNDAxMTIwODQ3NTJaMBMxE
TAPBgNVBAMMCDIwMjMwMTEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+iqg
1nMjYmFcFJh/.../S5X6qoEOyJBgtfpSBANWAdA==",
"displayName": "CN=20230113"
}
]
}
Response
HTTP
Request
PowerShell
To confirm that you're running the Microsoft Graph PowerShell session without a
signed-in user, run the following request.
PowerShell
Get-MgContext
PowerShell
ClientId : cf34b10f-50fd-4167-acf6-4f08ddd4561b
TenantId : 38d49456-54d4-455d-a8d6-c383c71e0a6d
CertificateThumbprint :
Scopes :
AuthType : AppOnly
AuthProviderType : ClientCredentialProvider
CertificateName : CN=20230113
Account :
AppName : testApp
ContextScope : Process
Certificate :
PSHostVersion : 5.1.22621.963
ClientTimeout : 00:05:00
Conclusion
You've used Microsoft Graph to update certificate credentials for an app object. This
process is a programmatic alternative to using the Azure portal. You can also update
certificate credentials for a service principal by following a similar process and calling
the https://graph.microsoft.com/v1.0/servicePrincipals/ endpoint.
Configure SAML-based single sign-on
for your application using the Microsoft
Graph API
Article • 03/02/2023
In this article, you'll learn how to create and configure a SAML-based single sign-on
(SSO) for your application in Azure Active Directory (Azure AD) using the Microsoft
Graph API. The application configuration includes basic SAML URLs, a claims mapping
policy, and using a certificate to add a custom signing key. After the application is
created, you assign a user to it to be an administrator. You then can use a URL to obtain
Azure AD SAML metadata for additional configuration of the application.
This article uses an AWS Azure AD application template as an example, but you can use
the steps in this article for any SAML-based app in the Azure AD Gallery.
Prerequisites
Sign in to an API client such as Graph Explorer , Postman, or create your own
client app to call Microsoft Graph. To call Microsoft Graph APIs in this tutorial, you
need to use an account with the global administrator role.
Grant yourself the following delegated permissions: Application.ReadWrite.All ,
AppRoleAssignment.ReadWrite.All , Policy.Read.All ,
Policy.ReadWrite.ApplicationConfiguration , and User.ReadWrite.All .
To create the application from the gallery, you first get the identifier of the application
template and then use that identifier to create the application.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/applicationTemplates?
$filter=displayName eq 'AWS IAM Identity Center (successor to AWS Single
Sign-On)'
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#applicationTemplates",
"value": [
{
"id": "21ed01d2-ec13-4e9e-86c1-cd546719ebc4",
"displayName": "AWS IAM Identity Center (successor to AWS Single
Sign-On)",
"homePageUrl": "https://aws.amazon.com/",
"supportedSingleSignOnModes": [
"saml",
"external"
],
"supportedProvisioningTypes": [
"sync"
],
"logoUrl": "https://az495088.vo.msecnd.net/app-
logo/awssinglesignon_215.png",
"categories": [
"developerServices",
"itInfrastructure",
"security",
"New"
],
"publisher": "Amazon Web Services, Inc.",
"description": "Federate once to AWS IAM Identity Center
(successor to AWS Single Sign-On) & use it to centrally manage access to
multiple AWS accounts and IAM Identity Center enabled apps. Provision users
via SCIM."
}
]
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/applicationTemplates/21ed01d2-
ec13-4e9e-86c1-cd546719ebc4/instantiate
Content-type: application/json
{
"displayName": "AWS Contoso"
}
7 Note
Allow some time for the app to be provisioned into your Azure AD tenant. It is not
instant. One strategy is to do a GET query on the application or service principal
object every 5-10 seconds until the query is successful.
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.applicationServi
cePrincipal",
"application": {
"id": "a9be408a-6c31-4141-8cea-52fcd4a61be8",
"appId": "17cad0e7-cd2b-4e51-a75d-ba810f3e4045",
"applicationTemplateId": "21ed01d2-ec13-4e9e-86c1-cd546719ebc4",
"createdDateTime": "2021-05-10T20:12:03Z",
"deletedDateTime": null,
"displayName": "AWS Contoso",
"groupMembershipClaims": null,
"identifierUris": [],
"isFallbackPublicClient": false,
"signInAudience": "AzureADMyOrg",
"tags": [],
"tokenEncryptionKeyId": null,
"defaultRedirectUri": null,
"optionalClaims": null,
"verifiedPublisher": {
"displayName": null,
"verifiedPublisherId": null,
"addedDateTime": null
},
"addIns": [],
"api": {
"acceptMappedClaims": null,
"knownClientApplications": [],
"requestedAccessTokenVersion": null,
"oauth2PermissionScopes": [
{
"adminConsentDescription": "Allow the application to access AWS
Contoso on behalf of the signed-in user.",
"adminConsentDisplayName": "Access AWS Contoso",
"id": "6f891cd3-c132-4822-930b-f343b4515d19",
"isEnabled": true,
"type": "User",
"userConsentDescription": "Allow the application to access AWS
Contoso on your behalf.",
"userConsentDisplayName": "Access AWS Contoso",
"value": "user_impersonation"
}
],
"preAuthorizedApplications": []
},
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "User",
"id": "8774f594-1d59-4279-b9d9-59ef09a23530",
"isEnabled": true,
"description": "User",
"value": null,
"origin": "Application"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "msiam_access",
"id": "e7f1a7f3-9eda-48e0-9963-bd67bf531afd",
"isEnabled": true,
"description": "msiam_access",
"value": null,
"origin": "Application"
}
],
"info": {
"logoUrl": null,
"marketingUrl": null,
"privacyStatementUrl": null,
"supportUrl": null,
"termsOfServiceUrl": null
},
"keyCredentials": [],
"parentalControlSettings": {
"countriesBlockedForMinors": [],
"legalAgeGroupRule": "Allow"
},
"passwordCredentials": [],
"publicClient": {
"redirectUris": []
},
"requiredResourceAccess": [],
"web": {
"homePageUrl": "https://*.signin.aws.amazon.com/platform/saml/acs/*?
metadata=awssinglesignon|ISV9.1|primary|z",
"redirectUris": []
}
},
"servicePrincipal": {
"id": "a750f6cf-2319-464a-bcc3-456926736a91",
"deletedDateTime": null,
"accountEnabled": true,
"appId": "17cad0e7-cd2b-4e51-a75d-ba810f3e4045",
"applicationTemplateId": "21ed01d2-ec13-4e9e-86c1-cd546719ebc4",
"appDisplayName": "AWS Contoso",
"alternativeNames": [],
"appOwnerOrganizationId": "8500cad3-193d-48a6-8d00-c129b114dc10",
"displayName": "AWS Contoso",
"appRoleAssignmentRequired": true,
"loginUrl": null,
"logoutUrl": null,
"homepage": "https://*.signin.aws.amazon.com/platform/saml/acs/*?
metadata=awssinglesignon|ISV9.1|primary|z",
"notificationEmailAddresses": [],
"preferredSingleSignOnMode": null,
"preferredTokenSigningKeyThumbprint": null,
"replyUrls": [],
"servicePrincipalNames": [
"17cad0e7-cd2b-4e51-a75d-ba810f3e4045"
],
"servicePrincipalType": "Application",
"tags": [
"WindowsAzureActiveDirectoryIntegratedApp"
],
"tokenEncryptionKeyId": null,
"samlSingleSignOnSettings": null,
"verifiedPublisher": {
"displayName": null,
"verifiedPublisherId": null,
"addedDateTime": null
},
"addIns": [],
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "User",
"id": "8774f594-1d59-4279-b9d9-59ef09a23530",
"isEnabled": true,
"description": "User",
"value": null,
"origin": "Application"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "msiam_access",
"id": "e7f1a7f3-9eda-48e0-9963-bd67bf531afd",
"isEnabled": true,
"description": "msiam_access",
"value": null,
"origin": "Application"
}
],
"info": {
"logoUrl": null,
"marketingUrl": null,
"privacyStatementUrl": null,
"supportUrl": null,
"termsOfServiceUrl": null
},
"keyCredentials": [],
"oauth2PermissionScopes": [
{
"adminConsentDescription": "Allow the application to access AWS
Contoso on behalf of the signed-in user.",
"adminConsentDisplayName": "Access AWS Contoso",
"id": "6f891cd3-c132-4822-930b-f343b4515d19",
"isEnabled": true,
"type": "User",
"userConsentDescription": "Allow the application to access AWS
Contoso on your behalf.",
"userConsentDisplayName": "Access AWS Contoso",
"value": "user_impersonation"
}
],
"passwordCredentials": []
}
}
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/servicePrincipals/a750f6cf-2319-
464a-bcc3-456926736a91
Content-type: application/json
{
"preferredSingleSignOnMode": "saml"
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/a9be408a-6c31-4141-
8cea-52fcd4a61be8
Content-type: application/json
{
"web": {
"redirectUris": [
"https://signin.aws.amazon.com/saml"
]
},
"identifierUris": [
"https://signin.aws.amazon.com/saml"
]
}
Response
HTTP
7 Note
When adding app roles, don't modify the default app roles msiam_access .
Use the id for the service principal that you recorded earlier.
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/serviceprincipals/a750f6cf-2319-
464a-bcc3-456926736a91
Content-type: application/json
{
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "User",
"id": "8774f594-1d59-4279-b9d9-59ef09a23530",
"isEnabled": true,
"description": "User",
"value": null,
"origin": "Application"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "msiam_access",
"id": "e7f1a7f3-9eda-48e0-9963-bd67bf531afd",
"isEnabled": true,
"description": "msiam_access",
"value": null,
"origin": "Application"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Admin,WAAD",
"displayName": "Admin,WAAD",
"id": "3a84e31e-bffa-470f-b9e6-754a61e4dc63",
"isEnabled": true,
"value": "arn:aws:iam::212743507312:role/accountname-aws-
admin,arn:aws:iam::212743507312:saml-provider/WAAD"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Finance,WAAD",
"displayName": "Finance,WAAD",
"id": "7a960000-ded3-455b-8c04-4f2ace00319b",
"isEnabled": true,
"value": "arn:aws:iam::212743507312:role/accountname-aws-
finance,arn:aws:iam::212743507312:saml-provider/WAAD"
}
]
}
Response
HTTP
https://aws.amazon.com/SAML/Attributes/Role assignedroles
https://aws.amazon.com/SAML/Attributes/RoleSessionName userprincipalname
https://aws.amazon.com/SAML/Attributes/SessionDuration "900"
roles assignedroles
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier userprincipalname
7 Note
Some keys in the claims mapping policy are case sensitive (for example, "Version").
If you receive an error message such as "Property has an invalid value", it might be
a case sensitive issue.
Create the claims mapping policy and record the value of the id property to use later in
this tutorial.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/policies/claimsMappingPolicies
Content-type: application/json
{
"definition": [
"{\"ClaimsMappingPolicy\":
{\"Version\":1,\"IncludeBasicClaimSet\":\"true\", \"ClaimsSchema\":
[{\"Source\":\"user\",\"ID\":\"assignedroles\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/Role\"},
{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/RoleSessionName\"},
{\"Value\":\"900\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/SessionDuration\"},
{\"Source\":\"user\",\"ID\":\"assignedroles\",\"SamlClaimType\":
\"appRoles\"},
{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/nameidentifier\"}]}}"
],
"displayName": "AWS Claims Policy",
"isOrganizationDefault": false
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#policies/claimsMappingPolicies/$
entity",
"id": "4bce7ba7-466d-4239-94b8-cf4f21428ca7",
"deletedDateTime": null,
"definition": [
"{\"ClaimsMappingPolicy\":
{\"Version\":1,\"IncludeBasicClaimSet\":\"true\", \"ClaimsSchema\":
[{\"Source\":\"user\",\"ID\":\"assignedroles\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/Role\"},
{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/RoleSessionName\"},
{\"Value\":\"900\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/SessionDuration\"},
{\"Source\":\"user\",\"ID\":\"assignedroles\",\"SamlClaimType\":
\"appRoles\"},
{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/nameidentifier\"}]}}"
],
"displayName": "AWS Claims Policy",
"isOrganizationDefault": false
}
Assign a claims mapping policy to a service principal
Use the id for the service principal that you recorded earlier to assign a claims mapping
policy to it. Use the value of the id property for the claims mapping policy in the body of
the request.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/servicePrincipals/a750f6cf-2319-
464a-bcc3-456926736a91/claimsMappingPolicies/$ref
Content-type: application/json
"@odata.id":"https://graph.microsoft.com/v1.0/policies/claimsMappingPoli
cies/a4b35718-fd5e-4ca8-8248-a3c9934b1b78"
}
Response
HTTP
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/servicePrincipals/a750f6cf-2319-
464a-bcc3-456926736a91/addTokenSigningCertificate
Content-type: application/json
{
"displayName":"CN=AWSContoso",
"endDateTime":"2024-01-25T00:00:00Z"
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.selfSignedCertif
icate",
"customKeyIdentifier": "p9PEYmuKhP2oaMzGfSdNQC/9ChA=",
"displayName": "CN=AWSContoso",
"endDateTime": "2024-01-25T00:00:00Z",
"key":
"MIICqjCCAZKgAwIBAgIId....4rnrk43wp75yqjRbOhAZ1ExAxVqW+o2JslhjUeltUMNQW+ynOf
s9oHu1ZdnGmxrE=",
"keyId": "70883316-50be-4016-ba80-19d9fbad873d",
"startDateTime": "2021-05-10T20:35:37.5754318Z",
"thumbprint": "A7D3C4626B8A84FDA868CCC67D274D402FFD0A10",
"type": "AsymmetricX509Cert",
"usage": "Verify"
}
PowerShell script
PowerShell
Param(
[Parameter(Mandatory=$true)]
[string]$fqdn,
[Parameter(Mandatory=$true)]
[string]$pwd,
[Parameter(Mandatory=$true)]
[string]$location
)
if (!$PSBoundParameters.ContainsKey('location'))
{
$location = "."
}
After running the previous code, extract the values for the following parameters from
the PFX file. You will add this information to the service principal:
Private key
Password
Public key
For more information about the properties, see keyCredential resource type.
Make sure that the keyId for the keyCredential used for "Sign" matches the keyId of the
passwordCredential. You can generate the customkeyIdentifier by getting the hash of
the cert's thumbprint. See the previous C# reference code.
Request
7 Note
The "key" value in the keyCredentials property is shortened for readability. The
value is base 64 encoded. For the private key the property usage is "Sign". For the
public key the property usage is "Verify".
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/servicePrincipals/f47a6776-bca7-
4f2e-bc6c-eec59d058e3e
Content-type: application/json
{
"keyCredentials":[
{
"customKeyIdentifier":
"lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
"endDateTime": "2021-04-22T22:10:13Z",
"keyId": "4c266507-3e74-4b91-aeba-18a25b450f6e",
"startDateTime": "2020-04-22T21:50:13Z",
"type": "X509CertAndPassword",
"usage": "Sign",
"key":"MIIKIAIBAz.....HBgUrDgMCERE20nuTptI9MEFCh2Ih2jaaLZBZGeZBRFVNXeZmA
AgIH0A==",
"displayName": "CN=awsAPI"
},
{
"customKeyIdentifier":
"lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
"endDateTime": "2021-04-22T22:10:13Z",
"keyId": "e35a7d11-fef0-49ad-9f3e-aacbe0a42c42",
"startDateTime": "2020-04-22T21:50:13Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"key":
"MIIDJzCCAg+gAw......CTxQvJ/zN3bafeesMSueR83hlCSyg==",
"displayName": "CN=awsAPI"
}
],
"passwordCredentials": [
{
"customKeyIdentifier":
"lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
"keyId": "4c266507-3e74-4b91-aeba-18a25b450f6e",
"endDateTime": "2022-01-27T19:40:33Z",
"startDateTime": "2020-04-20T19:40:33Z",
"secretText": "61891f4ee44d"
}
]
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/servicePrincipals/a750f6cf-2319-
464a-bcc3-456926736a91
Content-type: application/json
{
"preferredTokenSigningKeyThumbprint":
"A7D3C4626B8A84FDA868CCC67D274D402FFD0A10"
}
Response
HTTP
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
Content-type: application/json
{
"accountEnabled":true,
"displayName":"MyTestUser1",
"mailNickname":"MyTestUser1",
"userPrincipalName":"[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn":true,
"password":"Contoso1234"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"id": "040f9599-7c0f-4f94-aa75-8394c4c6ea9b",
"businessPhones": [],
"displayName": "MyTestUser1",
"userPrincipalName": "[email protected]"
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/servicePrincipals/a750f6cf-2319-
464a-bcc3-456926736a91/appRoleAssignments
Content-type: application/json
{
"principalId": "040f9599-7c0f-4f94-aa75-8394c4c6ea9b",
"principalType": "User",
"appRoleId":"3a84e31e-bffa-470f-b9e6-754a61e4dc63",
"resourceId":"a750f6cf-2319-464a-bcc3-456926736a91"
}
Response
HTTP
HTTP/1.1 201
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#servicePrincipals('a750f6cf-
2319-464a-bcc3-456926736a91')/appRoleAssignments/$entity",
"id": "mZUPBA98lE-qdYOUxMbqm2qY3odGRGdFtpYJkAfUC0Q",
"deletedDateTime": null,
"appRoleId": "3a84e31e-bffa-470f-b9e6-754a61e4dc63",
"createdDateTime": "2021-05-10T21:04:11.0480851Z",
"principalDisplayName": "MyTestUser1",
"principalId": "040f9599-7c0f-4f94-aa75-8394c4c6ea9b",
"principalType": "User",
"resourceDisplayName": "AWS Contoso",
"resourceId": "a750f6cf-2319-464a-bcc3-456926736a91"
}
Step 6: Get Azure AD SAML metadata
Use the following URL to get the Azure AD SAML metadata for the specific configured
application. The metadata contains information such as the signing certificate, Azure AD
entityID, and Azure AD SingleSignOnService, among others.
https://login.microsoftonline.com/{tenant-id}/federationmetadata/2007-
06/federationmetadata.xml?appid={app-id}
The following shows an example of what you might see for your application:
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
ID="_05fbbf53-e892-43c9-9300-1f6738ace02c"
entityID="https://sts.windows.net/2f82f566-5953-43f4-9251-79c6009bdf24/">
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
...
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-
Redirect" Location="https://login.microsoftonline.com/2f82f566-5953-43f4-
9251-79c6009bdf24/saml2"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-
Redirect" Location="https://login.microsoftonline.com/2f82f566-5953-43f4-
9251-79c6009bdf24/saml2"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-
POST" Location="https://login.microsoftonline.com/2f82f566-5953-43f4-9251-
79c6009bdf24/saml2"/>
</IDPSSODescriptor>
</EntityDescriptor>
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/applications/a9be408a-6c31-4141-
8cea-52fcd4a61be8
Response
HTTP
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/users/040f9599-7c0f-4f94-aa75-
8394c4c6ea9b
Response
HTTP
Request
HTTP
HTTP
DELETE
https://graph.microsoft.com/v1.0/policies/claimsMappingPolicies/a4b35718
-fd5e-4ca8-8248-a3c9934b1b78
Response
HTTP
See also
For AWS, you can enable user provisioning to fetch all the roles from that AWS
account. For more information, see Configure the role claim issued in the SAML
token.
Customize claims emitted in tokens for a specific app in a tenant.
You can use the applicationTemplate API to instantiate Non-Gallery apps. Use
applicationTemplateId 8adf8e6e-67b2-4cf2-a259-e3dc5476c621 .
applicationTemplate
appRoleAssignment
servicePrincipal
application
claimsMappingPolicy
keyCredential
addTokenSigningCertificate
Configure Application Proxy using the
Microsoft Graph API
Article • 03/02/2023
In this article, you'll learn how to configure Azure Active Directory (Azure AD)
Application Proxy for an application. Application Proxy provides secure remote access
and single sign-on to on-premises web applications. After configuring Application Proxy
for an application, users can access their on-premises applications through an external
URL, the My Apps portal, or other internal application portals.
Prerequisites
This tutorial assumes you have already installed a connector and completed the
prerequisites for Application Proxy so that connectors can communicate with
Azure AD services.
Sign in to an API client such as Graph Explorer , Postman, or create your own
client app to call Microsoft Graph. To call Microsoft Graph APIs in this tutorial, you
need to use an account with the global administrator role.
Grant yourself the following delegated permission: Directory.ReadWrite.All .
7 Note
Record the id, appId, servicePrincipalId of the application to use later in the tutorial.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/applicationTemplates/8adf8e6e-
67b2-4cf2-a259-e3dc5476c621/instantiate
Content-type: application/json
{
"displayName": "Contoso IWA App"
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#applications/$entity",
"id": "bf21f7e9-9d25-4da2-82ab-7fdd85049f83",
"deletedDateTime": null,
"addIns": [],
"appId": "d7fbfe28-c60e-46d2-8335-841923950d3b",
"applicationTemplateId": null,
"identifierUris": [],
"createdDateTime": "2020-08-11T21:07:47.5919755Z",
"description": null,
"displayName": "Contoso IWA App",
"isAuthorizationServiceEnabled": false,
"isDeviceOnlyAuthSupported": null,
"isFallbackPublicClient": null,
"groupMembershipClaims": null,
"notes": null,
"optionalClaims": null,
"orgRestrictions": [],
"publisherDomain": "f128.info",
"signInAudience": "AzureADandPersonalMicrosoftAccount",
"tags": [],
"tokenEncryptionKeyId": null,
"uniqueName": null,
"verifiedPublisher": {
"displayName": null,
"verifiedPublisherId": null,
"addedDateTime": null
},
}
Step 2: Configure Application Proxy
Insert the id that you recorded for the application into the URL to start the configuration
of Application Proxy. In this example, you're using an app with the internal URL:
https://contosoiwaapp.com . You also use the default domain for the external URL:
https://contosoiwaapp-contoso.msappproxy.net . Update the following properties in the
request body:
identifierUri, redirectUri, and homepageUrl - Set each to the same external URL.
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/bf21f7e9-9d25-4da2-
82ab-7fdd85049f83
Content-type: application/json
{
"identifierUris": [
"https://contosoiwaapp-contoso.msappproxy.net"
],
"web": {
"redirectUris": [
"https://contosoiwaapp-contoso.msappproxy.net"
],
"homePageUrl": "https://contosoiwaapp-contoso.msappproxy.net"
}
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/beta/applications/bf21f7e9-9d25-4da2-
82ab-7fdd85049f83
Content-type: application/json
{
"onPremisesPublishing": {
"externalAuthenticationType": "aadPreAuthentication",
"internalUrl": "https://contosoiwaapp.com",
"externalUrl": "https://contosoiwaapp-contoso.msappproxy.net",
"isHttpOnlyCookieEnabled": true,
"isOnPremPublishingEnabled": true,
"isPersistentCookieEnabled": true,
"isSecureCookieEnabled": true,
"isStateSessionEnabled": true,
"isTranslateHostHeaderEnabled": true,
"isTranslateLinksInBodyEnabled": true
}
}
Response
HTTP
Get connectors
List the connectors that are available. Record the id of the connector that you want to
assign to a connector group.
Request
HTTP
HTTP
GET
https://graph.microsoft.com/beta/onPremisesPublishingProfiles/applicatio
nProxy/connectors
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#connectors",
"value": [
{
"id": "d2b1e8e8-8511-49d6-a4ba-323cb083fbb0",
"machineName": "connectorA.redmond.contoso.com"",
"externalIp": "131.137.147.164",
"status": "active"
},
{
"id": "f2cab422-a1c8-4d70-a47e-2cb297a2e051",
"machineName": "connectorB.contoso.com"",
"externalIp": "68.0.191.210",
"status": "active"
}
]
}
Create a connectorGroup
For this example, a new connectorGroup is created named IWA Demo Connector Group
that is used for the application. Record the id that is returned to use in the next step.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/beta/onPremisesPublishingProfiles/applicatio
nProxy/connectorGroups
Content-type: application/json
{
"name": "IWA Demo Connector Group"
}
Response
HTTP
HTTP/1.1 201
Content-type: connectorGroup/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#connectorGroups/$entity",
"id": "3e6f4c35-a04b-4d03-b98a-66fff89b72e6",
"name": "IWA Demo Connector Group",
"connectorGroupType": "applicationProxy",
"isDefault": false
}
Request
HTTP
HTTP
POST
https://graph.microsoft.com/beta/onPremisesPublishingProfiles/applicatio
nProxy/connectors/f2cab422-a1c8-4d70-a47e-2cb297a2e051/memberOf/$ref
Content-type: application/json
"@odata.id":"https://graph.microsoft.com/beta/onPremisesPublishingProfil
es/applicationProxy/connectorGroups/3e6f4c35-a04b-4d03-b98a-
66fff89b72e6"
}
Response
HTTP
Request
HTTP
HTTP
PUT https://graph.microsoft.com/beta/applications/bf21f7e9-9d25-4da2-
82ab-7fdd85049f83/connectorGroup/$ref
Content-type: application/json
{
"@odata.id":"https://graph.microsoft.com/onPremisesPublishingProfiles/ap
plicationproxy/connectorGroups/3e6f4c35-a04b-4d03-b98a-66fff89b72e6"
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/beta/applications/bf21f7e9-9d25-4da2-
82ab-7fdd85049f83
Content-type: appplication/json
{
"onPremisesPublishing": {
"singleSignOnSettings": {
"kerberosSignOnSettings": {
"kerberosServicePrincipalName": "HTTP/iwademo.contoso.com",
"kerberosSignOnMappingAttributeType": "userPrincipalName"
},
"singleSignOnMode": "onPremisesKerberos"
}
}
}
Response
HTTP
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/servicePrincipals/a8cac399-cde5-
4516-a674-819503c61313/appRoles
Response
HTTP
HTTP/1.1 200
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#servicePrincipals('a8cac399-
cde5-4516-a674-819503c61313')/appRoles",
"value": [
{
"allowedMemberTypes": [
"User"
],
"description": "User",
"displayName": "User",
"id": "18d14569-c3bd-439b-9a66-3a2aee01d14f",
"isEnabled": true,
"origin": "Application",
"value": null
},
]
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
Content-type: application/json
{
"accountEnabled":true,
"displayName":"MyTestUser1",
"mailNickname":"MyTestUser1",
"userPrincipalName":"[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn":true,
"password":"Contoso1234"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"id": "4628e7df-dff3-407c-a08f-75f08c0806dc",
"businessPhones": [],
"displayName": "MyTestUser1",
"givenName": null,
"jobTitle": null,
"mail": null,
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "[email protected]"
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/servicePrincipals/b00c693f-9658-
4c06-bd1b-c402c4653dea/appRoleAssignments
Content-type: appRoleAssignments/json
{
"principalId": "4628e7df-dff3-407c-a08f-75f08c0806dc",
"principalType": "User",
"appRoleId":"18d14569-c3bd-439b-9a66-3a2aee01d14f",
"resourceId":"a8cac399-cde5-4516-a674-819503c61313"
}
Response
HTTP
HTTP/1.1 200
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#appRoleAssignments/$entity",
"id": "I23pL8ZdNU-CIgQmqMEVyLJ0E6fx0ixEo92az8MnhtU",
"creationTimestamp": "2020-06-09T00:06:07.5129268Z",
"appRoleId": "18d14569-c3bd-439b-9a66-3a2aee01d14f",
"principalDisplayName": "MyTestUser1",
"principalId": "2fe96d23-5dc6-4f35-8222-0426a8c115c8",
"principalType": "User",
"resourceDisplayName": "Contoso IWA App",
"resourceId": "a8cac399-cde5-4516-a674-819503c61313"
}
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/users/4628e7df-dff3-407c-a08f-
75f08c0806dc
Response
HTTP
No Content - 204
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/applications/bf21f7e9-9d25-4da2-
82ab-7fdd85049f83
Response
HTTP
No Content - 204
Request
HTTP
HTTP
DELETE
https://graph.microsoft.com/beta/onPremisesPublishingProfiles/applicatio
nProxy/connectorGroups/3e6f4c35-a04b-4d03-b98a-66fff89b72e6
Response
HTTP
No Content - 204
See also
Application Proxy
application
Configure provisioning using Microsoft
Graph APIs
Article • 10/12/2022
The Azure portal is a convenient way to configure provisioning for individual apps one
at a time. But if you're creating several—or even hundreds—of instances of an
application, it can be easier to automate app creation and configuration with the
Microsoft Graph APIs. This article outlines how to automate provisioning configuration
through APIs. This method is commonly used for applications like Amazon Web
Services.
Step Details
Step 2. Create provisioning job based on Retrieve the template for the provisioning
template connector
Create the provisioning job
Request
HTTP
GET https://graph.microsoft.com/beta/applicationTemplates?
$filter=displayName eq 'AWS Single-Account Access'
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "8b1025e4-1dd2-430b-a150-2ef79cd700f5",
"displayName": "AWS Single-Account Access",
"homePageUrl": "http://aws.amazon.com/",
"supportedSingleSignOnModes": [
"password",
"saml",
"external"
],
"supportedProvisioningTypes": [
"sync"
],
"logoUrl": "https://az495088.vo.msecnd.net/app-logo/aws_215.png",
"categories": [
"developerServices"
],
"publisher": "Amazon",
"description": "Federate to a single AWS account and use SAML
claims to authorize access to AWS IAM roles. If you have many AWS accounts,
consider using the AWS Single Sign-On gallery application instead."
}
Create the gallery application
Use the template ID retrieved for your application in the last step to create an instance
of the application and service principal in your tenant.
Request
HTTP
POST https://graph.microsoft.com/beta/applicationTemplates/{id}/instantiate
Content-type: application/json
{
"displayName": "AWS Contoso"
}
Response
HTTP
HTTP/1.1 201 OK
Content-type: application/json
{
"application": {
"objectId": "cbc071a6-0fa5-4859-8g55-e983ef63df63",
"appId": "92653dd4-aa3a-3323-80cf-e8cfefcc8d5d",
"applicationTemplateId": "8b1025e4-1dd2-430b-a150-2ef79cd700f5",
"displayName": "AWS Contoso",
"homepage": "https://signin.aws.amazon.com/saml?
metadata=aws|ISV9.1|primary|z",
"replyUrls": [
"https://signin.aws.amazon.com/saml"
],
"logoutUrl": null,
"samlMetadataUrl": null,
},
"servicePrincipal": {
"objectId": "f47a6776-bca7-4f2e-bc6c-eec59d058e3e",
"appDisplayName": "AWS Contoso",
"applicationTemplateId": "8b1025e4-1dd2-430b-a150-2ef79cd700f5",
"appRoleAssignmentRequired": true,
"displayName": "My custom name",
"homepage": "https://signin.aws.amazon.com/saml?
metadata=aws|ISV9.1|primary|z",
"replyUrls": [
"https://signin.aws.amazon.com/saml"
],
"servicePrincipalNames": [
"93653dd4-aa3a-4323-80cf-e8cfefcc8d7d"
],
"tags": [
"WindowsAzureActiveDirectoryIntegratedApp"
],
}
}
Request
HTTP
GET
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/temp
lates
Response
HTTP
HTTP/1.1 200 OK
{
"value": [
{
"id": "aws",
"factoryTag": "aws",
"schema": {
"directories": [],
"synchronizationRules": []
}
}
]
}
Create the provisioning job
To enable provisioning, you'll first need to create a job. Use the following request to
create a provisioning job. Use the templateId from the previous step when specifying
the template to be used for the job.
Request
HTTP
POST
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/jobs
Content-type: application/json
{
"templateId": "aws"
}
Response
HTTP
HTTP/1.1 201 OK
Content-type: application/json
{
"id": "{jobId}",
"templateId": "aws",
"schedule": {
"expiration": null,
"interval": "P10675199DT2H48M5.4775807S",
"state": "Disabled"
},
"status": {
"countSuccessiveCompleteFailures": 0,
"escrowsPruned": false,
"synchronizedEntryCountByType": [],
"code": "NotConfigured",
"lastExecution": null,
"lastSuccessfulExecution": null,
"lastSuccessfulExecutionWithExports": null,
"steadyStateFirstAchievedTime": "0001-01-01T00:00:00Z",
"steadyStateLastAchievedTime": "0001-01-01T00:00:00Z",
"quarantine": null,
"troubleshootingUrl": null
}
}
Step 3: Authorize access
Request
HTTP
POST
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/jobs
/{id}/validateCredentials
{
"credentials": [
{
"key": "ClientSecret", "value": "xxxxxxxxxxxxxxxxxxxxx"
},
{
"key": "SecretToken", "value": "xxxxxxxxxxxxxxxxxxxxx"
}
]
}
Response
HTTP
Request
HTTP
PUT
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/secr
ets
{
"value": [
{
"key": "ClientSecret", "value": "xxxxxxxxxxxxxxxxxxxxx"
},
{
"key": "SecretToken", "value": "xxxxxxxxxxxxxxxxxxxxx"
}
]
}
Response
HTTP
Request
HTTP
POST
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/jobs
/{jobId}/start
Response
HTTP
Request
HTTP
GET
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/jobs
/{jobId}/
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"id": "{jobId}",
"templateId": "aws",
"schedule": {
"expiration": null,
"interval": "P10675199DT2H48M5.4775807S",
"state": "Disabled"
},
"status": {
"countSuccessiveCompleteFailures": 0,
"escrowsPruned": false,
"synchronizedEntryCountByType": [],
"code": "Paused",
"lastExecution": null,
"lastSuccessfulExecution": null,
"progress": [],
"lastSuccessfulExecutionWithExports": null,
"steadyStateFirstAchievedTime": "0001-01-01T00:00:00Z",
"steadyStateLastAchievedTime": "0001-01-01T00:00:00Z",
"quarantine": null,
"troubleshootingUrl": null
},
"synchronizationJobSettings": [
{
"name": "QuarantineTooManyDeletesThreshold",
"value": "500"
}
]
}
Request
HTTP
GET https://graph.microsoft.com/beta/auditLogs/provisioning
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#auditLogs/provisioning",
"value": [
{
"id": "gc532ff9-r265-ec76-861e-42e2970a8218",
"activityDateTime": "2019-06-24T20:53:08Z",
"tenantId": "7928d5b5-7442-4a97-ne2d-66f9j9972ecn",
"cycleId": "44576n58-v14b-70fj-8404-3d22tt46ed93",
"changeId": "eaad2f8b-e6e3-409b-83bd-e4e2e57177d5",
"action": "Create",
"durationInMilliseconds": 2785,
"sourceSystem": {
"id": "0404601d-a9c0-4ec7-bbcd-02660120d8c9",
"displayName": "Azure Active Directory",
"details": {}
},
"targetSystem": {
"id": "cd22f60b-5f2d-1adg-adb4-76ef31db996b",
"displayName": "AWS Contoso",
"details": {
"ApplicationId": "f2764360-e0ec-5676-711e-cd6fc0d4dd61",
"ServicePrincipalId": "chc46a42-966b-47d7-9774-
576b1c8bd0b8",
"ServicePrincipalDisplayName": "AWS Contoso"
}
},
"initiatedBy": {
"id": "",
"displayName": "Azure AD Provisioning Service",
"initiatorType": "system"
}
]
}
]
}
See also
Review the synchronization Microsoft Graph documentation
Integrating a custom SCIM app with Azure AD
Generate proof of possession tokens for
rolling keys
Article • 05/25/2023
You can use the addKey and removeKey methods defined on the application and
servicePrincipal resources to roll expiring keys programmatically.
As part of the request validation for these methods, a proof of possession of an existing
key is verified before the methods can be invoked. The proof is represented by a self-
signed JWT token. This JWT token must be signed using the private key of one of the
application's existing valid certificates. The token lifespan should not exceed 10 minutes.
Note: Applications that don't have any existing valid certificates (no certificates have
been added yet, or all certificates have expired), can't use this service action. You can
use the Update application operation to perform an update instead.
the appId).
nbf - Not before time.
You can use the following code examples to generate this proof of possession token.
C#
C#
using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.JsonWebTokens;
namespace MicrosoftIdentityPlatformProofTokenGenerator
{
class Program
{
static void Main(string[] args)
{
// Configure the following
string pfxFilePath = "<Path to your certificate file";
string password = "<Certificate password>";
string objectId = "<id of the application or
servicePrincipal object>";
// audience
string aud = $"00000003-0000-0000-c000-000000000000";
You can also generate the proof using signature in Azure KeyVault. It is important to
note that padding character '=' must not be included in the JWT header and payload or
an Authentication_MissingOrMalformed error will be returned.
Next steps
Now that you have your proof of possession token, you can use it to:
Namespace: microsoft.graph
You can customize your synchronization schema to include custom attributes that are
defined in the target directory. This article describes how to customize a Salesforce
subscription by adding a new field called officeCode . You set up synchronization from
Azure Active Directory (Azure AD) to Salesforce, and for each user, you will populate the
officeCode field in Salesforce with the value from the extensionAttribute10 field in
Azure AD.
This article assumes that you have already added an application that supports
synchronization to your tenant through the Azure Portal , that you know the
application display name, and that you have an authorization token for Microsoft Graph.
For information about how to get the authorization token, see Get access tokens to call
Microsoft Graph.
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/servicePrincipals?
$select=id,appId,displayName&$filter=startswith(displayName,
'salesforce')
Authorization: Bearer {Token}
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#servicePrincipals(id,appId,displ
ayName)",
"value": [
{
"id": "167e33e9-f80e-490e-b4d8-698d4a80fb3e",
"appId": "cd3ed3de-93ee-400b-8b19-b61ef44a0f29",
"displayName": "Salesforce"
},
{
"id": "8cbbb70b-7290-42da-83ee-89fa3517a977",
"appId": "b0f2e3b1-fe31-4658-b216-44dcaeabb63a",
"displayName": "salesforce 1"
},
{
"id": "60443998-8cf7-4e61-b05c-a53b658cb5e1",
"appId": "79079396-c301-405d-900f-e2e0c2439a90",
"displayName": "Salesforce Sandbox"
}
]
}
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/servicePrincipals/60443998-8cf7-
4e61-b05c-a53b658cb5e1/synchronization/jobs
Authorization: Bearer {Token}
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#servicePrincipals('60443998-
8cf7-4e61-b05c-a53b658cb5e1')/synchronization/jobs",
"value": [
{
"id": "SfSandboxOutDelta.e4bbf44533ea4eabb17027f3a92e92aa",
"templateId": "SfSandboxOutDelta",
"schedule": {},
"status": {}
}
]
}
HTTP
HTTP
GET
https://graph.microsoft.com/beta/servicePrincipals/{servicePrincipalId}/
synchronization/jobs/{jobId}/schema
Authorization: Bearer {Token}
Note: The response object shown here might be shortened for readability. All the
properties will be returned in an actual call.
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"directories": [
{
"id": "66e4a8cc-1b7b-435e-95f8-f06cea133828",
"name": "Azure Active Directory",
"objects": [
{
"attributes": [
{
"anchor": true,
"caseExact": false,
"defaultValue": null,
"metadata": [],
"multivalued": false,
"mutability": "ReadWrite",
"name": "objectId",
"required": false,
"referencedObjects": [],
"type": "String"
},
{
"anchor": false,
"caseExact": false,
"defaultValue": null,
"metadata": [],
"multivalued": false,
"mutability": "ReadWrite",
"name": "streetAddress",
"required": false,
"referencedObjects": [],
"type": "String"
}
],
"name": "User"
}
]
},
{
"id": "8ffa6169-f354-4751-9b77-9c00765be92d",
"name": "salesforce.com",
"objects": []
}
],
"synchronizationRules": [
{
"editable": true,
"id": "4c5ecfa1-a072-4460-b1c3-4adde3479854",
"name": "USER_OUTBOUND_USER",
"objectMappings": [
{
"attributeMappings": [
{
"defaultValue": "True",
"exportMissingReferences": false,
"flowBehavior": "FlowWhenChanged",
"flowType": "Always",
"matchingPriority": 0,
"source": {
"expression": "Not([IsSoftDeleted])",
"name": "Not",
"parameters": [
{
"key": "source",
"value": {
"expression": "[IsSoftDeleted]",
"name": "IsSoftDeleted",
"parameters": [],
"type": "Attribute"
}
}
],
"type": "Function"
},
"targetAttributeName": "IsActive"
}
],
"enabled": true,
"flowTypes": "Add, Update, Delete",
"name": "Synchronize Azure Active Directory Users to
salesforce.com",
"scope": null,
"sourceObjectName": "User",
"targetObjectName": "User"
}
]
}
]
}
Under directories, find the directory with the name salesforce.com, and in the
object's array, find the one named User.
Add the new attribute to the list, specifying the name and type, as shown in
the following example.
JSON
{
"directories": [
{
"id": "8ffa6169-f354-4751-9b77-9c00765be92d",
"name": "salesforce.com",
"objects": [
{
"attributes": [
{
"name": "officeCode",
"type": "String"
}
],
"name":"User"
}]
}
],
"synchronizationRules": [
{
"editable": true,
"id": "4c5ecfa1-a072-4460-b1c3-4adde3479854",
"name": "USER_OUTBOUND_USER",
"objectMappings": [
{
"attributeMappings": [
{
"source": {
"name": "extensionAttribute10",
"type": "Attribute"
},
"targetAttributeName": "officeCode"
}
],
"name": "Synchronize Azure Active Directory Users to
salesforce.com",
"scope": null,
"sourceObjectName": "User",
"targetObjectName": "User"
}
],
"priority": 1,
"sourceDirectoryName": "Azure Active Directory",
"targetDirectoryName": "salesforce.com"
}
]
}
HTTP
HTTP
PUT
https://graph.microsoft.com/beta/servicePrincipals/{servicePrincipalId}/
synchronization/jobs/{jobId}/schema
Authorization: Bearer {Token}
{
"directories": [..],
"synchronizationRules": [..]
}
If the schema was saved successfully, the request returns a 204 No Content response
code. On the next iteration of the synchronization job, it will start re-processing all the
accounts in your Azure AD, and the new mappings will be applied to all provisioned
accounts.
Configure synchronization with
directory extension attributes
Article • 03/09/2023
Namespace: microsoft.graph
You can customize your synchronization schema to include Azure Active Directory
(Azure AD) directory extension attributes. This article describes how to use a directory
extension attribute (extension_9d98asdfl15980a_Nickname) to populate the value of
User.CommunityNickname in Salesforce. In this scenario, you have Azure AD Connect
set up to provision a number of directory extension attributes from Windows Server
Active Directory on-premises to Azure AD.
This article assumes that you have already added an application that supports
synchronization to your tenant through the Azure Portal , that you know the
application display name, and that you have an authorization token for Microsoft Graph.
For information about how to get the authorization token, see Get access tokens to call
Microsoft Graph.
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/servicePrincipals?
$select=id,appId,displayName&$filter=startswith(displayName,
'salesforce')
Authorization: Bearer {Token}
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#servicePrincipals(id,appId,displ
ayName)",
"value": [
{
"id": "167e33e9-f80e-490e-b4d8-698d4a80fb3e",
"appId": "cd3ed3de-93ee-400b-8b19-b61ef44a0f29",
"displayName": "Salesforce"
},
{
"id": "8cbbb70b-7290-42da-83ee-89fa3517a977",
"appId": "b0f2e3b1-fe31-4658-b216-44dcaeabb63a",
"displayName": "salesforce 1"
},
{
"id": "60443998-8cf7-4e61-b05c-a53b658cb5e1",
"appId": "79079396-c301-405d-900f-e2e0c2439a90",
"displayName": "Salesforce Sandbox"
}
]
}
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/servicePrincipals/60443998-8cf7-
4e61-b05c-a53b658cb5e1/synchronization/jobs
Authorization: Bearer {Token}
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#servicePrincipals('60443998-
8cf7-4e61-b05c-a53b658cb5e1')/synchronization/jobs",
"value": [
{
"id": "SfSandboxOutDelta.e4bbf44533ea4eabb17027f3a92e92aa",
"templateId": "SfSandboxOutDelta",
"schedule": {},
"status": {}
}
]
}
HTTP
HTTP
GET
https://graph.microsoft.com/beta/servicePrincipals/{servicePrincipalId}/
synchronization/jobs/{jobId}/schema
Authorization: Bearer {Token}
Note: The response object shown here might be shortened for readability. All the
properties will be returned in an actual call.
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"directories": [
{
"id": "66e4a8cc-1b7b-435e-95f8-f06cea133828",
"name": "Azure Active Directory",
"objects": [
{
"attributes": [
{
"anchor": true,
"caseExact": false,
"defaultValue": null,
"metadata": [],
"multivalued": false,
"mutability": "ReadWrite",
"name": "objectId",
"required": false,
"referencedObjects": [],
"type": "String"
},
{
"anchor": false,
"caseExact": false,
"defaultValue": null,
"metadata": [],
"multivalued": false,
"mutability": "ReadWrite",
"name": "streetAddress",
"required": false,
"referencedObjects": [],
"type": "String"
}
],
"name": "User"
}
]
},
{
"id": "8ffa6169-f354-4751-9b77-9c00765be92d",
"name": "salesforce.com",
"objects": []
}
],
"synchronizationRules": [
{
"editable": true,
"id": "4c5ecfa1-a072-4460-b1c3-4adde3479854",
"name": "USER_OUTBOUND_USER",
"objectMappings": [
{
"attributeMappings": [
{
"defaultValue": "True",
"exportMissingReferences": false,
"flowBehavior": "FlowWhenChanged",
"flowType": "Always",
"matchingPriority": 0,
"source": {
"expression": "Not([IsSoftDeleted])",
"name": "Not",
"parameters": [
{
"key": "source",
"value": {
"expression": "[IsSoftDeleted]",
"name": "IsSoftDeleted",
"parameters": [],
"type": "Attribute"
}
}
],
"type": "Function"
},
"targetAttributeName": "IsActive"
}
],
"enabled": true,
"flowTypes": "Add, Update, Delete",
"name": "Synchronize Azure Active Directory Users to
salesforce.com",
"scope": null,
"sourceObjectName": "User",
"targetObjectName": "User"
}
]
}
]
}
Under directories, find the directory with the name "Azure Active Directory",
and in the object's array, find the one named User.
Add the new attribute to the list, specifying the name and type, as shown in
the following example.
JSON
{
"directories": [
{
"id": "66e4a8cc-1b7b-435e-95f8-f06cea133828",
"name": "Azure Active Directory",
"objects": [
{
"attributes": [
,{
"name":
"extension_9d98asdfl15980a_Nickname",
"type": "String"
}
],
"name":"User"
}]
}
],
"synchronizationRules": [
{
"editable": true,
"id": "4c5ecfa1-a072-4460-b1c3-4adde3479854",
"metadata": [..],
"name": "USER_OUTBOUND_USER",
"objectMappings": [
{
"attributeMappings": [
,{
"source": {
"name": "extension_9d98asdfl15980a_Nickname",
"type": "Attribute"
},
"targetAttributeName": "CommunityNickname"
}
],
"name": "Synchronize Azure Active Directory Users to
salesforce.com",
"scope": null,
"sourceObjectName": "User",
"targetObjectName": "User"
}
],
"priority": 1,
"sourceDirectoryName": "Azure Active Directory",
"targetDirectoryName": "salesforce.com"
},
]
}
HTTP
PUT
https://graph.microsoft.com/beta/servicePrincipals/{servicePrincipalId}/sync
hronization/jobs/{jobId}/schema
Authorization: Bearer {Token}
{
"directories": [],
"synchronizationRules": []
}
If the schema was saved successfully, the request returns a 204 No Content response
code. On the next iteration of the synchronization job, it will start re-processing all the
accounts in your Azure AD, and the new mappings will be applied to all provisioned
accounts.
Overview of Microsoft Graph Data
Connect
Article • 09/08/2022
Microsoft Graph Data Connect augments Microsoft Graph’s transactional model with an
intelligent way to access rich data at scale. The data covers how workers communicate,
collaborate, and manage their time across all the applications and services in Microsoft
365.
Ideal for big data and machine learning, Data Connect lets you develop applications for
analytics, intelligence, and business process optimization by extending Microsoft 365
data into Azure. By integrating in this way, you can take advantage of the vast suite of
compute and storage options in Azure while staying compliant with industry standards
and keeping your data secure.
Microsoft Graph Data Connect uses Azure Synapse or Azure Data Factory to copy
Microsoft 365 data to your application’s storage at configurable intervals. It also
provides a set of tools to streamline the delivery of this data to Microsoft Azure, letting
you access the most applicable development and hosting tools available.
Data Connect also grants a more granular control and consent model: you can manage
data, see who is accessing it, and request specific properties of an entity. This enhances
the Microsoft Graph model, which grants or denies applications access to entire entities.
You can use Data Connect to enable machine learning scenarios for your organization.
In these scenarios, you can create applications that provide valuable information to your
stakeholders, train machine learning models, and even perform forecasting based on
large amounts of acquired data.
https://www.microsoft.com/en-us/videoplayer/embed/RWEJsy?
autoplay=false&postJsllMsg=true
You can take advantage of Microsoft Graph Data Connect if you agree to the Microsoft
APIs Terms of Use and the Microsoft Privacy Statement , and you are:
Microsoft Graph Data Connect resolves this challenge by accessing data in bulk and
repeatedly copying Microsoft 365 data to your application by using Azure Synapse or
Azure Data Factory. Data Connect also lets you choose between accessing data from
everyone in your organization or just specific groups of people.
Microsoft Graph Data Connect enables more granular consent, allowing applications to
request access to specific properties in an entity or filter the data in those properties.
Administrators must give explicit approval before Microsoft Graph data can be accessed.
The request must specify the level of access requested, data policy enforcement, the
reason for the request, and the schema of the data requested. As a result, applications
can only use data that is essential to their function, and any unrelated content is
excluded. For example, an app might consume email metadata but exclude body
content and attachments.
To minimize compliance management overhead for apps that you build with Data
Connect, you can specify a set of detailed policies that you intend to comply with, which
Microsoft 365 administrators can then review. After consent is given for these policies,
Microsoft monitors the application’s adherence to policy. If an application violates (or
attempts to violate) a policy established by the organization, Microsoft stops the flow of
data to that application.
See also
Build your first Microsoft Graph Data Connect application (tutorial)
Data Connect frequently asked questions
Datasets, regions, and sinks
Datasets, regions, and sinks supported
by Microsoft Graph Data Connect
Article • 04/29/2023
Microsoft Graph Data Connect supports a variety of datasets, data regions, and storage
locations in Microsoft Azure. This article describes the supported datasets and how to
access the dataset schemas, the Microsoft 365 and Microsoft Azure regions that are
supported, and the storage locations that Microsoft Graph Data Connect utilizes
through Azure Synapse or Azure Data Factory.
Datasets
Microsoft Graph Data Connect currently supports the following datasets. To view the
schemas for each dataset, create a new dataset in Azure Synapse or Azure Data Factory
and use the Schema tab to view it.
Microsoft Teams
Microsoft Groups
Viva Insights
Regions
Microsoft Graph Data Connect supports extracting data from a variety of Microsoft 365
regions. To successfully move data from the Microsoft 365 datacenter into your
Microsoft Azure storage, the Azure Synapse or Azure Data Factory instance and the
Azure storage location must both map to a supported region for the location of the
Microsoft 365 data.
The following table indicates which Microsoft 365 regions are supported and the
corresponding Azure regions required for data movement.
When using Azure Storage Blob as the sink, you must ensure that your application
has Storage Blob Data Contributor access to the Azure Storage Blob location.
For copy activity, the output files are formatted as JSON. This format is fixed and
modifying the format is not supported. However, you can use Azure Synapse or
Azure Data Factory to copy the result of a Microsoft Graph Data Connect pipeline
into another storage mechanism (such as Azure SQL Database).
Mapping data flows: Copy and transform data from Microsoft 365 (Office 365) -
Azure Data Factory & Azure Synapse | Microsoft Learn |
Output can be in parquet format. For details about the supported data
transformations, see Flatten transformation in mapping data flow.
Microsoft Graph Data Connect on mapping data flows supports direct output of
the data into Azure SQL DB.
The following table indicates the areas that are supported for the corresponding copy
activity and mapping data flows.
Supported data sinks ADLS gen2, Azure Blob ADLS gen2, Azure
Blob, Azure SQL DB
See also
Azure Synapse and Azure Data Factory connector for Microsoft 365 data
Policies and billing
Microsoft Graph Data Connect policies
and billing
Article • 03/03/2023
Microsoft Graph Data Connect uses Azure managed applications to allow you to create
and deploy your solutions in your Azure environment. Managed applications let you
support certain Azure policies, giving customers greater confidence and comfortability
when using your applications.
Policies
The following Azure policies are supported for an Azure managed application built by
using Microsoft 365 data:
7 Note
Azure Data Lake Storage Gen1 and Gen2 use different policies because Azure Data
Lake Storage Gen2 implements Azure Storage.
When you select any of the policies during Azure Marketplace publishing, the policy
compliance status is checked and enforced for all installations of your application. All
selected policies that are compliant are shown to the data approvers as part of the data
request. Any policy compliance violation causes the pipeline run to fail and stop the
data extraction.
Billing
A bill is associated with the Azure subscription of the Azure Synapse or Azure Data
Factory you are using. The price in this new billing model is based on the number of
Microsoft Graph objects that you are accessing. For more information about billing, see
the Pricing page .
Microsoft Graph Data Connect consumption charges are billed monthly on a pay-as-
you-go basis. The Data Connect billing unit is in a multiple of 1000s of objects, where 1
object maps to 1 individual instance of an entity in Microsoft 365. For example, 1 email
== 1 object, 1 file == 1 object, 1 Teams chat message == 1 object, and so on.
We have some datasets available for free or are currently free in preview while other
datasets are charged. Microsoft Graph Data Connect offers datasets across multiple
different Microsoft 365 products and services. For more information on datasets that are
available through Microsoft Graph Data Connect, please refer to Dataset, regions and
sinks.
BasicDataSet_v0.User_v0
BasicDataSet_v0.User_v1
BasicDataSet_v0.MailboxSettings
BasicDataSet_v0.Manager
BasicDataSet_v0.DirectReport
BasicDataSet_v0.GroupDetails
BasicDataSet_v0.GroupMembers
BasicDataSet_v0.GroupOwners
See also
User selection and filtering
Data Connect frequently asked questions
Dataset, regions and sinks.
User selection and filtering capabilities
in Microsoft Graph Data Connect
Article • 09/08/2022
You can use Microsoft Graph Data Connect to select the users that you want to extract
data for and to include filters to limit the data returned. This article describes the user
selection options that Data Connect provides and the filtering that it supports.
User selection
You can run pipelines on a set of users. The following are the options for user selection:
Specify your user selection in the SourceDataSet of the Azure Synapse or Azure Data
Factory copy activity. To run on a list of groups, add a new field allowedGroups under
typeProperties and set this to a list of up to 10 groups' Object Ids separated by
commas. If no groups are specified by default, data is extracted for the entire
organization.
To specify a predicate to run on the entire tenant, add a new field userScopeFilterUri
under typeProperties and set this to the predicate. The predicate format should match
the query format of Microsoft Graph APIs. For example, if you want to limit the selection
to users who work in the Finance department, you can use
https://graph.microsoft.com/v1.0/users?$filter=Department eq 'Finance' . If you want
Your query only returns users within the Microsoft 365 organization that you're
querying. Guest users and non-user mailboxes are not returned.
Filtering
You can limit the results extracted for your query by using DateTime properties.
Depending on the type of data requested, a DateTime filter might be required. The
DateTime filter is provided by using properties in the SourceDataSet of the Azure
Synapse or Azure Data Factory copy activity. To specify a DateTime filter, add a new field
dateFilterColumn under typeProperties and set this to one of the properties that
support filtering in the following table. Next, add a startTime and endTime that
represent the DateTime values that the property is filtered upon.
BasicDataSet_v0.Event_v0 CreatedDateTime
BasicDataSet_v0.Event_v1 LastModifiedDateTime
BasicDataSet_v0.Message_v0 CreatedDateTime
BasicDataSet_v0.Message_v1 LastModifiedDateTime
ReceivedDateTime
SentDateTime
BasicDataSet_v0.SentItem_v0 CreatedDateTime
BasicDataSet_v0.SentItem_v1 LastModifiedDateTime
ReceivedDateTime
SentDateTime
7 Note
See also
Integrate with PAM
Data Connect frequently asked questions
Microsoft Graph Data Connect
integration with PAM
Article • 09/08/2022
Microsoft Graph Data Connect relies on Privileged Access Management (PAM) to allow
Microsoft 365 administrators to approve data movement requests. Data Connect
pipelines must be approved by a member of the data access request approver group
specified by the Microsoft 365 administrator during enablement. To set up the approver
group, see Set up your Microsoft 365 tenant and enable Microsoft Graph Data Connect.
Approval request emails are sent to each member of the approver group to notify them
when copy activities request access to extract Microsoft 365 data. Approvers can
approve or deny these requests, specify a user group that should be scrubbed out of
extracted data, or revoke a previously approved request. Approvals persist for six
months, and one approval is needed per copy activity in the Azure Synapse or Azure
Data Factory pipeline.
Each request always includes the following details about the dataset and the users
about whom data is being extracted:
The following fields in the request are available only in some cases:
Application Name and the Marketplace URI (available only for applications
installed from the Azure Marketplace).
Links to the application's privacy policy and terms of service (available only if the
application provides it).
The compliance policies that the application enforces, such as data encryption at
rest in the output storage location (available only if the application provides it and
if the application is installed from the Azure Marketplace).
Deny List: The user group that can be scrubbed out of the extracted data. This field
is empty as a part of the request for datasets that support privacy scrubbing of
extracted data. It can be populated by the member of the approver group who
approves the request at approval time.
Approving requests
Microsoft Graph Data Connect pipelines must be approved by a member of a data
access request approver group. Approvers can approve, deny, or revoke pipelines by
using the Exchange Online PowerShell module or the PAM user experience.
1. Install the Exchange Online PowerShell module. For installation instructions, see
Connect to Exchange Online PowerShell using multi-factor authentication.
7 Note
3. Sign in with your account. You must be part of the configured data access
approver group to be able to approve, deny, or revoke requests. Guest users
cannot approve requests, even if they are in the approver group.
PowerShell
Connect-EXOPSSession
7 Note
The value in the Identity property is used to identify and approve or deny the
request. Note this value and use it in the -RequestId parameter.
PowerShell
5. Take a closer look at the context field of the request that you are interested in.
7 Note
The context field of the data access request describes the parameters and
properties of the copy activity.
PowerShell
PowerShell
Key Value
--- -----
ApplicationName
ComplianceStatus [{"Timestamp":"2018-05-
02T18:29:21.5705664Z","RequirementName":"adlsEncryption","PolicyComplia
nceState":"Compliant","Violations":0},{"Timestamp":"2018-05-02T...
ApplicationMarketPlaceUri
OutputUri
adl://myadlserumvrroyspmq.azuredatalakestore.net/targetFolder/Event
ApplicationPrivacyPolicyUri http://www.wkw.com/privacy
ApplicationTermsOfServiceUri http://www.wkw.com/tos
InstallerIdentity a89885c3-4b0e-499e-86ed-
14d7ed9147c2@942229f8-4656-4fb0-828b-e938dad4019a
SourceTenantId 942229f8-4656-4fb0-828b-e938dad4019a
UserScopeQuery tenant in (942229f8-4656-4fb0-828b-
e938dad4019a)
ApplicationId
DataTable Calendar Events
DestinationTenantId 942229f8-4656-4fb0-828b-e938dad4019a
Columns Subject:string, HasAttachments:bool,
End:DateTime, Start:DateTime, ResponseStatus:string, Organizer:Object,
Attendees:string, Importance:string, Sensitivity:...
6. Approve/deny the request by using the value for Identity for the -RequestId
parameter.
PowerShell
You can also approve the request with a deny list to ensure data from certain users is
not included. To do so, you need to modify the context of the request to add the object
Id of the group that you want to omit, and then approve the request.
PowerShell
You can also revoke requests that were previously approved. Similar to approving
requests, the value for Identity is what is required in the -RequestId parameter.
PowerShell
PowerShell
AuthorizedBy : [email protected]
Type : Task
AuthorizedAccess : Data Access Request
StartTimeUtc : 7/24/2018 6:02:42 PM
EndTimeUtc : 10/22/2018 6:02:42 PM
Revoked : True
RevocationDateTimeUtc : 7/24/2018 9:12:55 PM
RevokedBy : NAMPR00A001.prod.outlook.com/Microsoft Exchange
Hosted Organizations/tenant.onmicrosoft.com/user
RevocationComment : Revoking this request!
Identity : bda75607-0d87-43cb-bdf1-284b18446b34
DateCreatedUtc : 1/1/0001 12:00:00 AM
DateUpdatedUtc : 7/24/2018 9:12:55 PM
1. Sign in to the Microsoft 365 admin portal by using admin credentials, and then go
to the Privileged Access Management approval user experience page. This page
shows you all the access requests (pending/approved/expired/denied).
2. On the resulting page, select the request that you're interested in. To select a deny
list for privacy scrubbing, select the DenyList dropdown, select the group that
needs to be scrubbed, and then select Approve.
3. To revoke a previously approved request, select the approved request that needs
to be revoked, and then choose Revoke. The next attempt to move data by using
that approval fails.
Approval behavior
Microsoft Graph Data Connect approval requests have particular characteristics that you
should be aware of:
Approval requests are based on the Azure Synapse or Azure Data Factory, pipeline,
and copy activity names. Every copy activity run verifies that the Microsoft 365
admin has approved the copy activity's request to access Office data, and validates
the important parameters of the copy activity run against the parameters of the
approval.
Under certain conditions, a new approval request is automatically triggered. A Data
Connect approver must approve the new request before the copy activity can
access Microsoft 365 data.
If the parameters of the copy activity run changes, a new approval request is
triggered.
A new approval request is triggered if the Azure Synapse or Azure Data Factory
pipeline or copy activity's name change. For example, a new approval is required if
the data table or set of columns that the copy activity is accessing changes.
Copy activities must be approved once every six months. If the original approval
was approved six months ago, a new approval request is automatically triggered.
If a Microsoft 365 data access approver has denied an approval request or revoked
a previously approved request, the copy activity fails continually. Work with the
approver to understand the reason for the denial or revocation, and fix the
parameters of the copy activity accordingly. To trigger a new request for approval,
a new copy activity must be deployed or the name of the existing copy activity
must be changed.
An approval request expires in 24 hours unless a Microsoft 365 data access
approver acts on the request. A new request is submitted once every 24 hours for
approval. If you see your copy activity waiting for approval (in the Consent Pending
stage), then work with a Microsoft 365 data access approver to get your request
approved.
Privacy scrubbing
The member of the approver group who approves the request can specify the name of
one user group whose data would be scrubbed out of extracted data. The rows
containing email addresses corresponding to the members of the denied group are
scrubbed out of extracted data. Groups nested within the denied group are expanded,
and only users are scrubbed out. Refer to the approving requests section of this article
for details about how to apply the deny list during approval through either PowerShell
or the PAM user experience.
The following table shows the names of the datasets and the columns for which the
contents are checked for privacy scrubbing.
BasicDataSet_v0.Contact_v0 EmailAddresses
BasicDataSet_v0.Contact_v1
This article explains the concept of groups in Microsoft Graph Data Connect and the
options for scope selection. Scope selection allows you to specify how to extract objects;
for example, you can extract objects for all users in a Microsoft 365 tenant or select
groups in the Microsoft 365 tenant. For more information, see Demystifying User
Scopes .
You can create and manage several different types of groups in the Microsoft 365 admin
center; for details, see Compare groups. The following types of groups are applicable to
Microsoft Graph Data Connect:
Microsoft 365 Groups - Used for collaboration between users, both inside and
outside your company. They include collaboration services such as SharePoint and
Planner.
Distribution groups - Used for sending email notifications to a group of people.
Security groups - Used for granting access to resources such as SharePoint sites.
Mail-enabled security groups - Used for granting access to resources such as
SharePoint and emailing notifications to those users.
User-scoped datasets
User-scoped datasets can be messages, events, users, and so on. These datasets focus
on data around the individual user for the respective dataset.
* **All users in the tenant**: Returns data for all the users in the tenant.
Data is extracted for individual users in the selected group. For details,
see [User selection and filtering capabilities](/graph/data-connect-
filtering).
* **All users in the tenant with a scope filter**: Returns data for all the
users in the tenant that are part of the scope filter applied. Data is
extracted for individual users from the selected filter (group).
* A scope Filter can help filter the users. If it's left empty, all data
for all users is returned.
* **Select groups from the Microsoft 365 tenant**: Data is extracted for
individual users in the group.
Example
A customer wants to extract the messages dataset and creates a security group of users
A, B, and C in a tenant of 500 users, and passes this group. Microsoft Graph Data
Connect expands the security group into a list of users, extracts the message data for
those users, and delivers the data for those users to the customer. The customer will
only receive the messages dataset for individual users A, B, and C out of their tenant of
500 users.
Group-scoped datasets
Group-scoped datasets can be Outlook group conversations, Teams channel messages,
group details. These datasets focus on the collective data in a group from Outlook or
Teams.
* **All groups in the tenant**: Returns data for all the groups in the
tenant.
* **All groups in the tenant with a scope filter**: Returns data for all the
groups in the tenant with the scope filter applied. The scope Filter can
help narrow down the list of groups.
* **Select groups from the Microsoft 365 tenant**: Returns collective data
for the selected groups. Microsoft Graph Data Connect looks for data
associated with those specific groups rather than the individuals of the
group.
Note: When the customer specifies a group or groups to be the scope, Microsoft
Graph Data Connect looks for data associated with those specific groups rather than
the individuals of the group.
The following table maps certain datasets with certain types of groups. This helps you to
understand which types of groups are compatible with which datasets when you extract
data and use scope filters. Groups can either be distribution groups, security groups, or
Microsoft 365 groups. The types of groups supported varies based on which dataset
you're requesting.
TeamsStandardChannelMessages Yes* No No No
TeamsChannelDetails_v0 Yes* No No No
OutlookGroupConversations Yes No No No
Viva Insights NA NA NA NA
**Group datasets don't contain a primary mailbox; the region defaults to the region of
the tenant.
Example
A customer wants to extract the group details dataset with a security group of users A,
B, and C out of their tenant of 500 users. Because this is a group-scoped dataset, the
customer will only receive group details data for the specified group. The customer will
not receive any individual data for users A, B, and C in the group.
Note: For Teams group-scoped datasets, if the group in scope is not a Teams-
enabled group, it will not return any data. Microsoft 365 groups can be enabled as
Teams groups, but distribution groups and security groups are not Teams-enabled.
The following section provides details about the type of groups that are available to
select.
2. On the Scope tab, select the group-scoped dataset, search for and add a group or
groups, or group IDs, and choose Add.
3. View the group ID. Copy the IDs of the groups you want to verify.
4. In a new tab, go to the Azure homepage and choose Azure Active Directory.
5. On the Overview tab, paste the group ID copied from step 2, and then and choose
the Groups tab.
6. In the Type field for the group, verify the type of group that you have.
Microsoft Graph Data Connect
frequently asked questions
Article • 10/11/2022
Microsoft Graph Data Connect lets developers create applications that customers can
use to provide managed access to their at-scale Microsoft Graph datasets. This article
provides tips that will help you take advantage of the Microsoft Graph Data Connect
feature. For an introduction to Microsoft Graph Data Connect, see the overview.
For more questions, see troubleshooting, or reach out to the Data Connect team.
For example, you might want to use Microsoft Graph Data Connect to do an initial
extraction of the last year of email data, and then use Microsoft Graph APIs to analyze
emails in real time moving forward. Microsoft Graph Data Connect and Microsoft Graph
APIs are different tools for different jobs. It's important to think about which access
method best fits your scenario. For more information, see When should I use Microsoft
Graph API or Microsoft Graph Data Connect.
Business Process Analytics: For better operations, see how work really flows
through the organization on a day-to-day basis. Pinpoint the manual processes
and workflow bottlenecks that should be automated or optimized.
Security and Compliance Analytics: To secure sensitive data, learn how employees
are using and sharing sensitive information. Implement anomaly detection, threat
intelligence, audit log analysis, risk management, and legal forensics.
When customers are looking for insights and analytics beyond Viva Insights, Data
Connect provides the extensibility to deliver custom requirements. For example, it offers
Teams call records and transcripts as well as SharePoint Online data sets, which are not
currently in scope for Viva Insights. Additionally, Data Connect raw data provides
granular details that aren’t otherwise available from Viva Insights.
7 Note
Your tenant admin will need to approve and consent within 24 hours of kicking off
the pipeline. If the consent is not given within 24 hours, it will expire and you will
need to restart the consent process by kicking off your pipelines again. The
overhead time does not include time taken in consent approval.
For a list of Office to Azure regions and mappings, see Dataset, regions and sinks.
Basic: Datasets generated from raw customer created content and inputs from
Microsoft 365 applications and services (for example, Azure Active Directory,
Outlook, or Teams datasets).
Curated: Datasets custom generated for a specific use case or analytics scenarios,
or datasets from first-party Microsoft 365 analytics applications for their
extensibility for example, Viva Insights metrics).
Teams
Outlook
Azure Active Directory (Azure AD)
OneDrive/Sharepoint
Viva Insights
New datasets are added to Microsoft Graph Data Connect on a regular basis. For a
complete list, see Dataset, regions, and sinks.
For information about datasets that are generally avaialble or in preview only, see
Dataset, regions, and sinks.
How much do I have to pay for Microsoft
Graph Data Connect?
Microsoft Graph Data Connect consumption charges are billed monthly on a pay-as-
you-go basis. The Data Connect billing unit is in a multiple of 1000s of objects, where 1
object maps to 1 individual instance of an entity in Microsoft 365. For example, 1 email
== 1 object, 1 file == 1 object, 1 Teams chat message == 1 object, and so on.
Some datasets are available for free or are currently free in preview while other datasets
are charged. Microsoft Graph Data Connect offers datasets across multiple different
Microsoft 365 products and services. For details about datasets that are available
through Microsoft Graph Data Connect, see Dataset, regions, and sinks. For details
about billing, see the Pricing page .
BasicDataSet_v0.User_v0
BasicDataSet_v0.User_v1
BasicDataSet_v0.MailboxSettings
BasicDataSet_v0.Manager
BasicDataSet_v0.DirectReport
BasicDataSet_v0.GroupDetails
BasicDataSet_v0.GroupMembers
BasicDataSet_v0.GroupOwners
For example, a customer has 20 pipeline runs within the month, each yielding 500 rows.
In total, the customer runs pipelines for 10,000 rows that month. However, their bill will
not be 10,000 rows/1000 rows = 10 units.
Instead, the customer will be billed for 20 units because Microsoft Graph Data Connect
rounds up fractions. Because 500 rows /1000 rows = 0.5 and 0.5 is a fraction, it will
rounds up to 1. The customer will be billed one unit per pipeline run, which results in 20
units billed in total.
Does my current Azure discount apply to the
Microsoft Graph Data Connect monthly bill?
Microsoft Graph Data Connect is offered through Azure and is currently available to
Microsoft 365 customers. Your existing discounts can be applied to Microsoft Graph
Data Connect charges because it is billed through Azure. For more information, reach
out to your account manager.
If you create an Azure managed application for others to use in their tenants, you still
provide a service principal for the app to use. This service principal exists in your (the
publisher's) tenant. However, if the app needs other service principals, your customer
(the installer) creates them in their own tenant. For example, your Azure Synapse or
Azure Data Factory pipeline likely needs access to a storage resource in Azure. The
customer creates the service principal with permissions to the storage account for the
pipeline to use.
For more information about building your application with Azure Synapse or Azure Data
Factory, see the Data Connect quick start.
The first time you trigger a pipeline, it waits for a Microsoft 365 administrator (or
appointed delegate) to approve the access request. Although the pipeline status shows
In progress, the underlying copy activity will have a status of ConsentPending until
approval is granted, as shown in the following screenshot.
During development, it's a good idea to make sure that your pipeline runs aren't stuck
on ConsentPending, especially after you make a change to your pipeline. For example, if
you add an additional field to the schema, the next pipeline run issues a new PAM
request that has to be approved. Don't waste time waiting on a pipeline that's waiting
for your approval.
Note that consent requests will expire after 24 hours if not approved and the pipeline
will fail. Additionally, PAM approval is valid for only 6 months (unless revoked).
To approve a request:
When enabling Microsoft Graph Data Connect, you must be within the approver’s
group.
Users must have a Global Admin role.
Users must have an Exchange Online license assigned.
However, even if this account is part of the approver group that you set up, you can't
use it to approve the PAM request because self-approvals are not allowed. If you try,
you'll get an error message in the PAM portal: "Requestor and approver are the same.
Self-approval is not allowed."
For development, you'll want to have a second account in addition to the admin who
approves requests. Both the submitter and the approver must have active Exchange
Online accounts.
You can deduplicate the exported JSON objects based on the internetMessageId of the
messages: two messages with the same internetMessageId are duplicate copies of the
same instance. Because the duplicates can exist in different blobs, you must deduplicate
across all blobs rather than deduplicating in each blob separately.
Can I use the puser field to determine the
relevant user?
The extracted data includes some meta properties that don't exist when using the
corresponding Microsoft Graph APIs. Specifically, the puser field can be useful for
determining which user the data was extracted from. In the scenario where you have
two copies of the same email in different mailboxes, you can use the puser field to
determine which copy came from which mailbox. The puser field is also useful for
datasets such as the Manager dataset. The exported JSON contains information about a
manager, but this is only useful if you know whose manager they are. The puser field
tells you whose manager that JSON object corresponds to.
Microsoft Graph Data Connect enbles you to extend Microsoft 365 data into Azure in
order to create applications for analytics, intelligence, and business process
optimization. This article provides troubleshooting information for working with
Microsoft Graph Data Connect.
The service principal's owner must be a valid user account within the tenant, not
another service principal.
If the owning member is no longer valid in a tenant's system, pipelines will fail this
check unless a current valid user within the tenant owns the account. If there is a
change in ownership, make sure that the owning account is updated to another
member who meets the requirements.
PAM approver issues
If you're having issues approving jobs within your tenant for your specified pipeline runs
or extractions, verify that the approvers in your tenant meet the following criteria.
Certain privileges must be granted to designated approvers to successfully approve
jobs.
Approvers must be active user accounts within the tenant, not other service
principals or groups.
The user account must have an Office 365 or Microsoft 365 E5 license with
Exchange Online capabilities and a mailbox.
If approvers want to approve jobs through the Microsoft 365 admin center, they
will need global admin privileges. Global admin privileges are not needed when
approving jobs via PowerShell script .
Keep the following in mind when customers with multi-geo tenants extract data:
Data Connect only allows datasets to be extracted from the same region as the
tenant. For example, if you have a tenant in Europe (EUR) but want to run your
pipeline for your users in North America (NAM), you will only get data for users in
NAM, because you specified a pipeline for NAM.
Multi-geo tenants can extract data for their tenants by setting up region-specific
pipelines. For example, one region maps to one or a set of pipelines for that
region.
3. On the Sink tab, specify the location where you want the combined file to be
created and make sure you select the Merge files behavior.
You can resolve this issue with an SSP request: INTERNT PROXY (SWG) - EXCEPTION ON
SECURITY FILTERING POLICY .
1. Find an Office-to-Azure region mapping. To look up which Office region you will
be extracting user data from, see the following table.
7 Note
The Azure region you're running a pipeline in must map to an Office region to
extract the users for the tenant. Microsoft Graph Data Connect does not extract
data across regions. For example, if you're running a pipeline in the West Europe
Azure region, it will only extract the users for the Europe (EUR) Office region
because the West Europe Azure region maps to the Europe Office region.
2. After you find the Office to Azure mapping, you need to determine the compatible
location of your destination storage account (see the following table). You can look
up how to configure your Azure storage account and grant access from an internet
IP range.
7 Note
This indicates the Azure regions that may NOT be used per region for the
destination storage when it is closed for public access. This is also the region for
which the IP addresses need to be added to the allow list to allow data delivery. To
find IP ranges, see Azure IP Ranges and Service Tags .
At this point, customers can understand and configure the region they want
to extract users from (what their Office to Azure region mapping is).
Customers can understand which region their destination storage account
can't be in.
Based on a compatible destination storage account, customers can use the
information to understand which IP addresses they need to add to the allow
list.
3. You can create a new integration run time on the same region that you have added
to the allow list, or use auto resolve, depending on your preference and settings.
We recommend creating a new IR in the same region. For details, see Azure
Integration Runtime IP addresses: Specific regions.
If you're using Auto Resolve IR, the region depends on several factors. For
details, see Azure IR location.
1. A user wants to extract data for users in the Europe (EUR) Office region. They
identify their Office to Azure region mapping. Because the Office region is EUR, the
Azure region is in West Europe.
2. All resources, ADF, and storage account are in the West Europe Azure region,
initially.
3. The user closed the destination storage account for public access.
4. The user needs to identify where their compatible destination storage account can
be based on the Office region I want to extract (EUR).
5. Because they cannot add allow list services in the same region as the storage
account, the destination storage account cannot be on the West Europe Azure
region. They can create a new storage account in North Europe.
6. For Data Connect internal services to copy the data into the destination storage
account, they need to add IP addresses to the allow list from compatible regions
based on their Office region (EUR). They will need to add ADF public IPs to the
allow list in the West Europe Azure region.
7. For the ADF destination linked service to also access the destination storage
account, they need to create and use an Integration Runtime on the West Europe
region, or use auto resolve IR instead.
8. The user lists these IP addresses and moves the destination storage to North
Europe because the Office region is EUR, and the Azure region is West Europe.
1. The consent request is only valid for 24 hours. Contact your tenant admin to
approve within this timeframe.
a. If not approved in that timeframe, subsequent runs will fail with the same error
and regenerate a consent request.
b. When approved, the pipeline can be rerun at any time to retrieve data.
2. Verify that the destination storage is set up correctly to allow the app to write data
into it.
See also
Data Connect overview
Data Connect FAQ
Outlook calendar API overview
Article • 10/06/2022
Outlook calendar is part of the Outlook messaging hub in Microsoft 365 that also lets
you manage emails and contacts, find information about users in an organization,
initiate online conversations, share files, and collaborate in groups.
https://www.youtube-nocookie.com/embed/_ST4nyz4g9E
Most features in the Outlook calendar API apply to calendars in personal Microsoft
accounts and work or school accounts.
** Denotes features below that are specifically applicable to Outlook calendars in only
work or school accounts.
In Outlook, customers can create individual calendars for work, family, and other
purposes, and organize them in calendar groups. They can turn on the free
Birthdays and Holiday calendar to remind them of contacts' birthdays and local
holidays. They can add calendars that match their interests, such as calendars for
sport teams and TV programs. Customers can select and overlay calendars, and see
their events in the same view. Through the calendar API, your app can similarly
organize calendars in calendar groups, and interact with interesting calendars just
like any other calendar in the user's mailbox.
Outlook customers can apply categories to events, messages, contacts, tasks, and
group posts in a consistent way to enhance organization and discovery. The
calendar API lets you access and define a user's master list of categories, which
opens up additional creative scenarios. For example, an athletic club can organize a
sports tournament and offer an app that differentiates emails and events for each
sport with their own color category. For last-minute news such as unforeseen
timetable changes, the app can also set the importance property of those events
and emails to alert customers.
In a calendar folder, you can create and update single instance events, or schedule
and maintain recurring events. You can let your customers respond to meeting
requests, and snooze or dismiss reminders using the associated event navigation
property.
You can keep the app local store synchronized by subscribing to change
notifications and tracking changes to events in a user's calendar.
You can display the user's agenda based on a light-weight reminder view.
You can let the user conveniently accept and take a meeting online through its
webLink property, which opens the meeting in Outlook on the web.
Users can also tentatively accept or decline a meeting while on the go.
Enhance collaboration
In Outlook, customers can share calendars with one another and give permissions
to read, write, or delete calendar contents. Or, they can delegate a calendar to let
another customer respond to meeting requests on their behalf. Programmatically,
while you cannot initiate a share or delegate action on behalf of a user, you can
use a set of properties to verify the sharing status and enable scenarios around
shared or delegated calendars: canEdit, canShare, canViewPrivateItems, isShared,
and isSharedWithMe.
The calendar API lets you get calendar items of the signed-in user, or users who
have shared or delegated their calendars to the signed-in user. For example, if
Garth has shared a calendar with John, or if Garth has delegated access to John,
then delegated permissions from John would give you read access to Garth's
shared calendar and contents as well.
Microsoft 365 groups make it convenient for group members to collaborate and
access group conversations and calendars right in Outlook. Aside from a few minor
differences between group calendars and user calendars, the calendar API lets you
interact with group calendars just like user calendars. See the calendar resource for
more information**.
Schedule smart
Outlook and the calendar API offer many smart conveniences to schedule events:
Through Outlook calendar app settings, customers can enable automatic adding of
events from emails, such as flight, hotel, or dining reservations, and billing invoices.
Once added, you can interact with these events just like any other event objects in
the user's mailbox, and build creative scenarios upon this Outlook capability.
In Outlook, booking a meeting room is as straight-forward as adding an attendee
to the event. The calendar API represents a meeting room as an emailAddress
object. You can get rooms and get room lists that are available in a tenant. To
organize a meeting in a specific room, assign it to the location property of the
event.**
You can look up the free/busy information for users and resources for a specific
time period. You can then use this data to apply to different scenarios including
resource planning and event scheduling.**
If your scenario involves scheduling meetings at an optimal time, you can consider
using findMeetingTimes to identify possible times or locations to meet. The
findMeetingTimes function considers the free/busy status of the attendees, and
any preferred rooms, time, and other constraints you provide. If the first try doesn't
return a common meeting time, check the reason, adjust your criteria and call
findMeetingTimes again.**
Incorporate place details in calendar events to help users navigate their day and
enhance productivity.**
Catering applications can use the places API to assist venue navigation and set
up.**
Automate emailing pre-meeting details to attendees and include a map on how to
get to a room.**
Set up reception bot assistants to provide information about specific rooms in a
building.**
Depending on your app scenario, you can use the places API within the context of
Outlook, or independent of Outlook.
Take advantage of social intelligence and other
developer conveniences in Microsoft Graph
Use the people API in Microsoft Graph to connect to people data which is based on a
user's communication and collaboration patterns and business relationships. You can
implement controls such as a people picker and suggest persons relevant to the user
when organizing meetings on the user's behalf.
Save overhead in storing and managing app data in external data stores. With Microsoft
Graph, you can store custom app data as open extensions in individual resource
instances. If you require the data to be typed or would like to be able to share the typed
schema, you can store custom app data in schema extensions.
The API does not support accessing in-place archive mailboxes, not on Exchange Online
nor on Exchange Server.
API reference
Looking for the API reference for this service?
Next steps
Select and try calendar sample queries in Graph Explorer.
Learn about:
Finding possible meeting times on the Outlook calendar
Getting the free/busy schedule for users and resources
Propose meeting times in an Outlook calendar (preview)
Create or set an event as an online meeting in an Outlook calendar
Scheduling repeating appointments as recurring events in Outlook
Getting shared events
Attaching large files to Outlook messages or events
Getting immutable identifiers for Outlook resources
Take a look at the Outlook calendar API reference.
Find possible meeting times on the
Outlook calendar
Article • 07/09/2022
In a workplace or school, looking for a common time and place to meet often incurs
overhead. Microsoft Graph applications can use findMeetingTimes to identify any
possible meeting times that satisfy time, location, and other constraints.
The findMeetingTimes action lets you specify conditions such as the meeting date/time
range, duration, optional or required attendees, and nature of the activity
(activityDomain). The action takes into account the attendees' and organizer's normal
work schedules and free/busy status, and suggests times that are appropriate for the
participants and type of activity. For instance, suggestions for a work-related activity
always occur during the work hours of the organizer and attendees, and suggestions
where required attendees are available are ordered higher up in the suggested list.
In Microsoft 365, work hours and time zones are configurable per mailbox. The
findMeetingTimes action handles time zone variations among the organizer and
attendees. By default, findMeetingTimes returns suggestions in UTC. You can use the
following request header to have findMeetingTimes return suggestions expressed in a
specific time zone.
HTTP
Prefer: outlook.timezone="{time-zone-string}}"
7 Note
Organizer's calendar
Attendee's calendar
The example makes 2 calls to findMeetingTimes:
1. The first call looks in the date range of April 18-20. As the attendee is out-of-office
on April 18-19, and there is no commonly available time on April 20, the first call
returns no suggestions with the reason (emptySuggestionsReason) that attendees
are not available.
2. The second call looks for availability on April 21 and returns a suggestion of 2-
4pm.
The two calls to findMeetingTimes include the following parameters. All parameters for
findMeetingTimes are optional.
attendees: one attendee, Samantha Booth, set as required for the type property
locationConstraint: does not require any location suggestion
timeConstraint: the first call looks in the date/time range of April 18, 9am to April
20, 5pm; after the first call fails to suggest any times, the second call looks at April
21, 9am to 5pm
meetingDuration: two hours
returnSuggestionReasons: this example requires a reason for each suggestion
minimumAttendeePercentage: 100%, as the attendee must be able to attend for
any suggested time
First request
Look for a 2-hour free time slot for both users over April 18-20.
HTTP
POST https://graph.microsoft.com/v1.0/me/findMeetingTimes
Prefer: outlook.timezone="Pacific Standard Time"
Content-type: application/json
{
"attendees": [
{
"type": "required",
"emailAddress": {
"name": "Samantha Booth",
"address": "[email protected]"
}
}
],
"locationConstraint": {
"isRequired": false,
"suggestLocation": false,
"locations": [
{
"resolveAvailability": false,
"displayName": "Conf room Hood"
}
]
},
"timeConstraint": {
"activityDomain":"work",
"timeslots": [
{
"start": {
"dateTime": "2017-04-18T09:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2017-04-20T17:00:00",
"timeZone": "Pacific Standard Time"
}
}
]
},
"meetingDuration": "PT2H",
"returnSuggestionReasons": true,
"minimumAttendeePercentage": 100
}
First response
There is no 2-hour time slot during the work hours of April 18-20 when both users are
available.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
Preference-Applied: outlook.timezone="Pacific Standard Time"
Content-Length: 184
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph
.meetingTimeSuggestionsResult",
"emptySuggestionsReason":"AttendeesUnavailable",
"meetingTimeSuggestions":[
]
}
Second request
Look for a 2-hour time slot on April 21.
HTTP
POST https://graph.microsoft.com/v1.0/me/findMeetingTimes
Prefer: outlook.timezone="Pacific Standard Time"
Content-type: application/json
{
"attendees": [
{
"type": "required",
"emailAddress": {
"name": "Samantha Booth",
"address": "[email protected]"
}
}
],
"locationConstraint": {
"isRequired": false,
"suggestLocation": false,
"locations": [
{
"resolveAvailability": false,
"displayName": "Conf room Hood"
}
]
},
"timeConstraint": {
"activityDomain":"work",
"timeslots": [
{
"start": {
"dateTime": "2017-04-21T09:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2017-04-21T17:00:00",
"timeZone": "Pacific Standard Time"
}
}
]
},
"meetingDuration": "PT2H",
"returnSuggestionReasons": true,
"minimumAttendeePercentage": 100
}
Second response
The second findMeetingTimes request suggests April 21, 2-4pm for both users to meet.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
Preference-Applied: outlook.timezone="Pacific Standard Time"
Content-Length: 714
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph
.meetingTimeSuggestionsResult",
"emptySuggestionsReason":"",
"meetingTimeSuggestions":[
{
"confidence":100.0,
"organizerAvailability":"free",
"suggestionReason":"Suggested because it is one of the nearest
times when all attendees are available.",
"meetingTimeSlot":{
"start":{
"dateTime":"2017-04-21T14:00:00.0000000",
"timeZone":"Pacific Standard Time"
},
"end":{
"dateTime":"2017-04-21T16:00:00.0000000",
"timeZone":"Pacific Standard Time"
}
},
"attendeeAvailability":[
{
"availability":"free",
"attendee":{
"type":"required",
"emailAddress":{
"address":"[email protected]"
}
}
}
],
"locations":[
{
"displayName":"Conf room Hood"
}
]
}
]
}
Next steps
There are times when not all attendees can attend a meeting. You can have
findMeetingTimes suggest a time if the confidence for attendance reaches a certain
percentage, by specifying the minimumAttendeePercentage optional parameter. Learn
more about the confidence of a meeting suggestion and other parameters, and apply
them as appropriate for meetings of larger sizes.
In a work or school setting, a common scenario is to see when a user is free for meeting,
or to browse the availability of a team, room, or equipment for a time period.
The getSchedule action lets you get the availability information of one or more entities -
users, distribution lists, or resources - for a specific period of time.
Example
A simple example is to find the free/busy schedule of a coworker, Alex, on a specific day,
from 9am to 6pm, Pacific Standard Time:
HTTP
POST https://graph.microsoft.com/v1.0/me/calendar/getschedule
Prefer: outlook.timezone="Pacific Standard Time"
Content-Type: application/json
{
"Schedules": ["[email protected]"],
"StartTime": {
"dateTime": "2018-08-06T09:00:00",
"timeZone": "Pacific Standard Time"
},
"EndTime": {
"dateTime": "2018-08-06T18:00:00",
"timeZone": "Pacific Standard Time"
},
"availabilityViewInterval": "15"
}
getSchedule returns two schedule items that match existing events in Alex' default
calendar, showing the start and end times of each event and its free/busy status. You
can assume Alex is free for the remaining time in that date/time range.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(micr
osoft.graph.scheduleInformation)",
"value":[
{
"scheduleId":"[email protected]",
"availabilityView":"111111002222222200000000000000000000",
"scheduleItems":[
{
"status":"Tentative",
"start":{
"dateTime":"2018-08-06T09:00:00.0000000",
"timeZone":"Pacific Standard Time"
},
"end":{
"dateTime":"2018-08-06T10:30:00.0000000",
"timeZone":"Pacific Standard Time"
}
},
{
"status":"Busy",
"start":{
"dateTime":"2018-08-06T11:00:00.0000000",
"timeZone":"Pacific Standard Time"
},
"end":{
"dateTime":"2018-08-06T13:00:00.0000000",
"timeZone":"Pacific Standard Time"
}
}
],
"workingHours":{
"daysOfWeek":[
"monday",
"tuesday",
"wednesday",
"thursday",
"friday"
],
"startTime":"08:00:00.0000000",
"endTime":"17:00:00.0000000",
"timeZone":{
"@odata.type":"#microsoft.graph.customTimeZone",
"bias":480,
"name":"Customized Time Zone",
"standardOffset":{
"time":"02:00:00.0000000",
"dayOccurrence":1,
"dayOfWeek":"sunday",
"month":11,
"year":0
},
"daylightOffset":{
"daylightBias":-60,
"time":"02:00:00.0000000",
"dayOccurrence":2,
"dayOfWeek":"sunday",
"month":3,
"year":0
}
}
}
}
]
}
Apart from the free/busy schedule and working hours of Alex, getSchedule also returns
availabilityView, which is a merged view of Alex' availability for that day. The merged
view is a string that consists of time slots covering that day, with each time slot
indicating Alex' availability using the following convention:
0 = free
1 = tentative
2 = busy
3 = out of office
4 = working elsewhere.
By default, the length of each time slot is 30 minutes. This example uses the
availabilityViewInterval property to customize the time slot to be 15 minutes.
Application
findMeetingTimes applies certain business logic to suggest meeting times and
locations, such as:
App-only support
findmeetingtimes supports only delegated scenarios which require a user to have
signed in to the app. The app can read events in only the calendars that the signed-in
user can access. This can include calendars that other users have delegated or shared
with the signed-in user.
Permissions
The least privileged permissions required by findmeetingtimes is
Calendars.Read.Shared.
Version support
findmeetingtimes and getSchedule are both generally available and appropriate for use
in production apps.
While the consented permission lets an app use getSchedule on the requested users'
calendars, through Outlook, the requested user controls which event data, if any, that
getSchedule returns.
For example, getSchedule can return the free/busy status and working hours of the
requested users, or it can also return the subject, location, and isPrivate properties of an
event, provided that:
The event is marked with low sensitivity level - normal or personal - AND one or
more of the following conditions apply:
The requested user’s calendar settings allow the signed-in user to view subject
lines and locations
The requested user’s calendar is shared with the signed-in user
HTTP
See also
Permissions reference
Find possible meeting times on the Outlook calendar
Propose new meeting times in Outlook
calendar
Article • 08/26/2022
In Outlook, a meeting organizer can allow invitees to propose alternative meeting times,
if they cannot meet at the original set date/time and accept tentatively or decline. The
organizer can accept a proposal by adjusting the meeting time as appropriate.
HTTP
POST https://graph.microsoft.com/v1.0/me/events
Prefer: outlook.timezone="Pacific Standard Time"
Content-type: application/json
{
"subject": "Let's go for lunch",
"body": {
"contentType": "HTML",
"content": "Does noon work for you?"
},
"start": {
"dateTime": "2019-08-15T12:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-15T14:00:00",
"timeZone": "Pacific Standard Time"
},
"allowNewTimeProposals": true,
"location":{
"displayName":"Harry's Bar"
},
"attendees": [
{
"emailAddress": {
"address":"[email protected]",
"name": "Adele Vance"
},
"type": "required"
}
]
}
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-
b4ab-004ae54f3747')/events/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAAAhBhkg==\"",
"id": "AAMkADAwJXJGu0AAACEhWOAAA=",
"createdDateTime": "2019-08-01T06:41:07.805128Z",
"lastModifiedDateTime": "2019-08-01T06:41:08.3298275Z",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAAAhBhkg==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Let's go for lunch",
"bodyPreview": "Does noon work for you?",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": true,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "busy",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADAwJXJGu0AAACEhWOAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"allowNewTimeProposals": true,
"recurrence": null,
"responseStatus": {
"response": "organizer",
"time": "0001-01-01T00:00:00Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nDoes late morning work for
you?\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-08-15T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-15T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"location": {
"displayName": "Harry's Bar",
"locationType": "default",
"uniqueId": "Harry's Bar",
"uniqueIdType": "private"
},
"locations": [
{
"displayName": "Harry's Bar",
"locationType": "default",
"uniqueId": "Harry's Bar",
"uniqueIdType": "private"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
}
HTTP
POST
https://graph.microsoft.com/v1.0/me/events/AAMkADU5NRaRqdoI4oeRpAAAB_wo
NAAA=/tentativelyAccept
Content-type: application/json
{
"comment": "Can you make the next day instead?",
"sendResponse": "true",
"proposedNewTime": {
"Start": {
"DateTime": "2019-08-16T12:00:00",
"TimeZone": "Pacific Standard Time"
},
"End": {
"DateTime": "2019-08-16T14:00:00",
"TimeZone": "Pacific Standard Time"
}
}
}
HTTP
The subject includes a prefix and says "New Time Proposed: Let's go for
lunch"
The sender is Adele Vance
The responseType is tentativelyAccepted
Adele's proposal is in the proposedNewTime property of the
eventMessageResponse
HTTP
GET https://graph.microsoft.com/v1.0/me/messages?$top=1
Prefer: outlook.timezone="Pacific Standard Time"
For demonstration purpose, assume Adele's reply is the latest message in Alex'
mailbox, and Alex can simply request that latest message.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
Preference-Applied: outlook.timezone="Pacific Standard Time"
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-
b4ab-004ae54f3747')/messages",
"@odata.nextLink": "https://graph.microsoft.com/v1.0/me/messages?
$top=1&$skip=4"",
"value": [
{
"@odata.type": "#microsoft.graph.eventMessageResponse",
"@odata.etag":
"W/\"DAAAABYAAAA0RfLCCxWuR42wWzJXJGu0AAACEGHC\"",
"id": "AAMkADAwJXJGu0AAACEiVAAAA=",
"createdDateTime": "2019-08-01T07:06:27Z",
"lastModifiedDateTime": "2019-08-01T07:06:28Z",
"changeKey": "DAAAABYAAAA0RfLCCxWuR42wWzJXJGu0AAACEGHC",
"categories": [],
"receivedDateTime": "2019-08-01T07:06:28Z",
"sentDateTime": "2019-08-01T07:06:24Z",
"hasAttachments": false,
"internetMessageId": "
<[email protected]>",
"subject": "New Time Proposed: Let's go for lunch",
"bodyPreview": "Can you make the next day instead?",
"importance": "normal",
"parentFolderId": "AQMkADAwQAAAIBDAAAAA==",
"conversationId": "AAQkADAwQAQAMkh89RO3QpBiUCETTtVbIo=",
"conversationIndex": "AdVINBlgySHz1E7dCkGJQIRNO1VsigAA4n6R",
"isDeliveryReceiptRequested": null,
"isReadReceiptRequested": false,
"isRead": false,
"isDraft": false,
"webLink": "https://outlook.office365.com/owa/?
ItemID=AAMkADAwJXJGu0AAACEiVAAAA%3D&exvsurl=1&viewmodel=ReadMessageItem
",
"inferenceClassification": "focused",
"unsubscribeData": [],
"unsubscribeEnabled": false,
"meetingMessageType": "meetingTentativelyAccepted",
"type": "singleInstance",
"isOutOfDate": false,
"isAllDay": false,
"isDelegated": false,
"responseType": "tentativelyAccepted",
"recurrence": null,
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-
Type\" content=\"text/html; charset=utf-8\">\r\n<meta
content=\"text/html; charset=us-ascii\">\r\n</head>\r\n<body>\r\nCan
you make the next day instead?\r\n</body>\r\n</html>\r\n"
},
"sender": {
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
},
"from": {
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
},
"toRecipients": [
{
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
],
"ccRecipients": [],
"bccRecipients": [],
"replyTo": [],
"flag": {
"flagStatus": "notFlagged"
},
"startDateTime": {
"dateTime": "2019-08-15T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"endDateTime": {
"dateTime": "2019-08-15T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"location": {
"displayName": "Harry's Bar",
"locationType": "default",
"uniqueIdType": "unknown"
},
"proposedNewTime": {
"start": {
"dateTime": "2019-08-16T12:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-16T14:00:00",
"timeZone": "Pacific Standard Time"
}
}
}
]
}
4. Alex also notices the event for the lunch now includes a proposedNewTime
property that indicates Adele's proposal. This property is only present as part of an
attendee instance if the corresponding attendee has suggested an alternative
meeting time.
HTTP
GET
https://graph.microsoft.com/v1.0/me/events/AAMkADAwJXJGu0AAACEhWOAAA=?
$select=subject,allowNewTimeProposals,start,end,attendees,organizer
Prefer: outlook.timezone="Pacific Standard Time"
HTTP
HTTP/1.1 200 Ok
{
"@odata.context":
"https://graph.microsoft.com/testexchangev1.0/$metadata#users('64339082
-ed84-4b0b-b4ab-
004ae54f3747')/events(subject,allowNewTimeProposals,start,end,attendees
,organizer)/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAAAhEDMA==\"",
"id": "AAMkADAwJXJGu0AAACEhWOAAA=",
"subject": "Let's go for lunch",
"allowNewTimeProposals": true,
"start": {
"dateTime": "2019-08-15T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-15T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"attendees": [
{
"type": "required",
"status": {
"response": "tentativelyAccepted",
"time": "2019-08-01T07:06:24.5046431Z"
},
"proposedNewTime": {
"start": {
"dateTime": "2019-08-16T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-16T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
}
},
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
}
5. Alex decides to accept Adele's proposal by updating the event to the proposed
start and end date/time.
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/events/AAMkADAwJXJGu0AAACEhWOAAA=
Prefer: outlook.timezone="Pacific Standard Time"
Content-type: application/json
{
"start": {
"dateTime": "2019-08-16T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-16T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
}
}
HTTP
HTTP/1.1 200 Ok
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-
b4ab-004ae54f3747')/events/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAAAhBizA==\"",
"id": "AAMkADAwJXJGu0AAACEhWOAAA=",
"createdDateTime": "2019-08-01T06:41:07.805128Z",
"lastModifiedDateTime": "2019-08-01T08:21:43.5696529Z",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAAAhBizA==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Let's go for lunch",
"bodyPreview": "Does noon work for you?",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": true,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "busy",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADAwJXJGu0AAACEhWOAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"allowNewTimeProposals": true,
"recurrence": null,
"responseStatus": {
"response": "organizer",
"time": "0001-01-01T00:00:00Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nDoes noon work for you?
\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-08-16T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-16T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"location": {
"displayName": "Harry's Bar",
"locationType": "default",
"uniqueId": "Harry's Bar",
"uniqueIdType": "private"
},
"locations": [
{
"displayName": "Harry's Bar",
"locationType": "default",
"uniqueId": "Harry's Bar",
"uniqueIdType": "private"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "notResponded",
"time": "4501-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
}
See also
Finding possible meeting times on the Outlook calendar
Getting the free/busy schedule for users and resources
Scheduling repeating appointments as recurring events in Outlook
Create or set an event as an online
meeting in an Outlook calendar
Article • 04/19/2023
Use the Outlook calendar API to organize an event where meeting invitees can select a
join URL and attend the meeting online in Microsoft Teams or Skype.
7 Note
The calendar API lets you conveniently set up an online meeting in an Outlook
calendar where attendees can click to join the meeting and continue their
experience in Teams or Skype. For a more customized, richer integration with Teams
or Skype, use the cloud communications API. See Choose an API in Microsoft
Graph to create and join online meetings for more information.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/calendar
Response
HTTP
HTTP/1.1 200 Ok
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/calendar/$entity",
"id": "AQMkADAwAGVAAAJfygAAAA==",
"name": "Calendar",
"color": "auto",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAAAAACOg==",
"canShare": true,
"canViewPrivateItems": true,
"canEdit": true,
"allowedOnlineMeetingProviders": [
"teamsForBusiness",
"skypeForBusiness"
],
"defaultOnlineMeetingProvider": "teamsForBusiness",
"isTallyingResponses": true,
"isRemovable": false,
"owner": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
7 Note
Once you enable a meeting online, Microsoft Graph sets the meeting information
in onlineMeeting. Subsequently, you cannot change the onlineMeetingProvider
property, nor set isOnlineMeeting to false to disable the meeting online.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/me/events
Prefer: outlook.timezone="Pacific Standard Time"
Content-type: application/json
{
"subject": "Prep for customer meeting",
"body": {
"contentType": "HTML",
"content": "Does this time work for you?"
},
"start": {
"dateTime": "2019-11-20T13:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-11-20T14:00:00",
"timeZone": "Pacific Standard Time"
},
"location":{
"displayName":"Cordova conference room"
},
"attendees": [
{
"emailAddress": {
"address":"[email protected]",
"name": "Adele Vance"
},
"type": "required"
}
],
"allowNewTimeProposals": true,
"isOnlineMeeting": true,
"onlineMeetingProvider": "teamsForBusiness"
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/events/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAASBUEsA==\"",
"id": "AAMkADAAABIGYDZAAA=",
"createdDateTime": "2019-11-15T01:55:54.8022848Z",
"lastModifiedDateTime": "2019-11-15T01:55:56.5162924Z",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAASBUEsA==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"iCalUId":
"040000008200E00074C5B7101A82E0080000000076B29D94B32CD6010000000000000000100
000005F31C591C3C328459653D025BD277439",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Prep for customer meeting",
"bodyPreview": "Does this time work for you?
\r\n________________________________________________________________________
________\r\nJoin Microsoft Teams Meeting\r\n+1 323-555-0166 United States,
Los Angeles (Toll)\r\nConference ID: 291 633 251#\r\nLocal numbers | Reset
PIN | Lea",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": true,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "busy",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADAABIGYDZAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"isOnlineMeeting": true,
"onlineMeetingProvider": "teamsForBusiness",
"allowNewTimeProposals": true,
"recurrence": null,
"responseStatus": {
"response": "organizer",
"time": "0001-01-01T00:00:00Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nDoes this time work for you?
\r\n<div style=\"width:100%; height:20px\"><span style=\"white-space:nowrap;
color:gray;
opacity:.36\">______________________________________________________________
__________________</span>\r\n</div>\r\n<div class=\"me-email-text\"
style=\"color:#252424; font-family:'Segoe UI','Helvetica
Neue',Helvetica,Arial,sans-serif\">\r\n<div style=\"margin-top:24px; margin-
bottom:10px\"><a class=\"me-email-headline\"
href=\"https://teams.microsoft.com/l/meetup-
join/19%3ameeting_ODkyNWFmNGYtZjBjYS00MDdlLTllOWQtN2E3MzJlNjM0ZWRj%40thread.
v2/0?context=%7b%22Tid%22%3a%2298a79ebe-74bf-4e07-a017-
7b410848cb32%22%2c%22Oid%22%3a%2264339082-ed84-4b0b-b4ab-
004ae54f3747%22%7d\" target=\"_blank\" rel=\"noreferrer noopener\"
style=\"font-size:18px; font-family:'Segoe UI Semibold','Segoe
UI','Helvetica Neue',Helvetica,Arial,sans-serif; text-decoration:underline;
color:#6264a7\">Join\r\n Microsoft Teams Meeting</a>
</div>\r\n<div>\r\n<div><a class=\"me-email-link\" href=\"tel:+1 323-
886-7531,,291633251# \" target=\"_blank\" rel=\"noreferrer noopener\"
style=\"font-size:14px; text-decoration:none; color:#6264a7\">+1 323-
886-7531</a>\r\n<span style=\"font-size:12px\"> United States, Los
Angeles (Toll) </span></div>\r\n</div>\r\n<div style=\"margin-top:10px;
margin-bottom:20px\"><span style=\"font-size:12px\">Conference
ID:\r\n</span><span style=\"font-size:14px\">291 633 251# </span>
</div>\r\n<div style=\"margin-bottom:24px\"><a class=\"me-email-link\"
target=\"_blank\" href=\"https://dialin.teams.microsoft.com/1f9a0550-737c-
41bd-8c7d-4c81dc1c4070?id=291633251\" rel=\"noreferrer noopener\"
style=\"font-size:12px; text-decoration:none; color:#6264a7\">Local\r\n
numbers</a> | <a class=\"me-email-link\" target=\"_blank\"
href=\"https://mysettings.lync.com/pstnconferencing\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nReset PIN</a> | <a class=\"me-email-link\"
target=\"_blank\" href=\"https://aka.ms/JoinTeamsMeeting\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nLearn more about Teams</a> | <a class=\"me-email-link\"
target=\"_blank\" href=\"https://teams.microsoft.com/meetingOptions/?
organizerId=64339082-ed84-4b0b-b4ab-004ae54f3747&tenantId=98a79ebe-74bf-
4e07-a017-
7b410848cb32&threadId=19_meeting_ODkyNWFmNGYtZjBjYS00MDdlLTllOWQtN2E3MzJ
[email protected]&messageId=0&language=en-US\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nMeeting options</a> </div>\r\n<div style=\"font-
size:14px; margin-bottom:4px\"></div>\r\n<div style=\"font-size:12px\">
</div>\r\n</div>\r\n<div style=\"width:100%; height:20px\"><span
style=\"white-space:nowrap; color:gray;
opacity:.36\">______________________________________________________________
__________________</span>\r\n</div>\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-11-20T13:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-11-20T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"location": {
"displayName": "Cordova conference room",
"locationType": "default",
"uniqueId": "Cordova conference room",
"uniqueIdType": "private"
},
"locations": [
{
"displayName": "Cordova conference room",
"locationType": "default",
"uniqueId": "Cordova conference room",
"uniqueIdType": "private"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
},
"onlineMeeting": {
"joinUrl": "https://teams.microsoft.com/l/meetup-
join/19%3ameeting_ODkyNWFmNGYtZjBjYS00MDdlLTllOWQtN2E3MzJlNjM0ZWRj%40thread.
v2/0?context=%7b%22Tid%22%3a%2298a79ebe-74bf-4e07-a017-
7b410848cb32%22%2c%22Oid%22%3a%2264339082-ed84-4b0b-b4ab-
004ae54f3747%22%7d",
"conferenceId": "291633251",
"tollNumber": "+1 323-555-0166"
}
}
) Important
Access the URL to join a meeting using joinUrl, available via the onlineMeeting
property of the event. Do not use the onlineMeetingUrl property of the event
because onlineMeetingUrl will soon be deprecated.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/events/AAMkADAGu0AABIGYDZAAA=?
$select=isOnlineMeeting,onlineMeetingProvider,onlineMeeting
Response
HTTP
HTTP/1.1 200 Ok
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/events(isOnlineMeeting,onlineMeetingProvider,onlineMeeting)/$
entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAASBUExA==\"",
"id": "AAMkADAGu0AABIGYDZAAA=",
"isOnlineMeeting": true,
"onlineMeetingProvider": "teamsForBusiness",
"onlineMeeting": {
"joinUrl": "https://teams.microsoft.com/l/meetup-
join/19%3ameeting_ODkyNWFmNGYtZjBjYS00MDdlLTllOWQtN2E3MzJlNjM0ZWRj%40thread.
v2/0?context=%7b%22Tid%22%3a%2298a79ebe-74bf-4e07-a017-
7b410848cb32%22%2c%22Oid%22%3a%2264339082-ed84-4b0b-b4ab-
004ae54f3747%22%7d",
"conferenceId": "291633251",
"tollNumber": "+1 323-555-0166"
}
}
7 Note
Once you enable a meeting online, Microsoft Graph sets the meeting information
in onlineMeeting. Subsequently, you cannot change the onlineMeetingProvider
property, nor set isOnlineMeeting to false to disable the meeting online.
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/me/events/AAMkADAGu0AABIGYDaAAA=
{
"isOnlineMeeting": true,
"onlineMeetingProvider": "teamsForBusiness"
}
Response
HTTP
HTTP/1.1 200 Ok
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/events/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAASBUFEA==\"",
"id": "AAMkADAGu0AABIGYDaAAA=",
"createdDateTime": "2019-11-15T02:13:38.5558455Z",
"lastModifiedDateTime": "2019-11-15T02:15:00.0654529Z",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAASBUFEA==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"iCalUId":
"040000008200E00074C5B7101A82E00800000000CD93094B5A9BD5010000000000000000100
00000A16AF77C6F6C254EA13F69C3B2808B4A",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Price strategy",
"bodyPreview": "Let's define our
strategy.\r\n_______________________________________________________________
_________________\r\nJoin Microsoft Teams Meeting\r\n+1 323-555-0166
United States, Los Angeles (Toll)\r\nConference ID: 275 984 951#\r\nLocal
numbers | Reset PIN | Learn",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": true,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "busy",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADAGu0AABIGYDaAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"isOnlineMeeting": true,
"onlineMeetingProvider": "teamsForBusiness",
"allowNewTimeProposals": true,
"recurrence": null,
"responseStatus": {
"response": "organizer",
"time": "0001-01-01T00:00:00Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\n<div>Let's define our strategy.
</div>\r\n<div style=\"width:100%; height:20px\"><span style=\"white-
space:nowrap; color:gray;
opacity:.36\">______________________________________________________________
__________________</span>\r\n</div>\r\n<div class=\"me-email-text\"
style=\"color:#252424; font-family:'Segoe UI','Helvetica
Neue',Helvetica,Arial,sans-serif\">\r\n<div style=\"margin-top:24px; margin-
bottom:10px\"><a class=\"me-email-headline\"
href=\"https://teams.microsoft.com/l/meetup-
join/19%3ameeting_NTRkMWViMmEtNzcxNC00OTk3LWJjOTEtYTdhMDU3ZmJhYWFi%40thread.
v2/0?context=%7b%22Tid%22%3a%2298a79ebe-74bf-4e07-a017-
7b410848cb32%22%2c%22Oid%22%3a%2264339082-ed84-4b0b-b4ab-
004ae54f3747%22%7d\" target=\"_blank\" rel=\"noreferrer noopener\"
style=\"font-size:18px; font-family:'Segoe UI Semibold','Segoe
UI','Helvetica Neue',Helvetica,Arial,sans-serif; text-decoration:underline;
color:#6264a7\">Join\r\n Microsoft Teams Meeting</a>
</div>\r\n<div>\r\n<div><a class=\"me-email-link\" href=\"tel:+1 323-
886-7531,,275984951# \" target=\"_blank\" rel=\"noreferrer noopener\"
style=\"font-size:14px; text-decoration:none; color:#6264a7\">+1 323-
886-7531</a>\r\n<span style=\"font-size:12px\"> United States, Los
Angeles (Toll) </span></div>\r\n</div>\r\n<div style=\"margin-top:10px;
margin-bottom:20px\"><span style=\"font-size:12px\">Conference
ID:\r\n</span><span style=\"font-size:14px\">275 984 951# </span>
</div>\r\n<div style=\"margin-bottom:24px\"><a class=\"me-email-link\"
target=\"_blank\" href=\"https://dialin.teams.microsoft.com/1f9a0550-737c-
41bd-8c7d-4c81dc1c4070?id=275984951\" rel=\"noreferrer noopener\"
style=\"font-size:12px; text-decoration:none; color:#6264a7\">Local\r\n
numbers</a> | <a class=\"me-email-link\" target=\"_blank\"
href=\"https://mysettings.lync.com/pstnconferencing\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nReset PIN</a> | <a class=\"me-email-link\"
target=\"_blank\" href=\"https://aka.ms/JoinTeamsMeeting\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nLearn more about Teams</a> | <a class=\"me-email-link\"
target=\"_blank\" href=\"https://teams.microsoft.com/meetingOptions/?
organizerId=64339082-ed84-4b0b-b4ab-004ae54f3747&tenantId=98a79ebe-74bf-
4e07-a017-
7b410848cb32&threadId=19_meeting_NTRkMWViMmEtNzcxNC00OTk3LWJjOTEtYTdhMDU
[email protected]&messageId=0&language=en-US\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nMeeting options</a> </div>\r\n<div style=\"font-
size:14px; margin-bottom:4px\"></div>\r\n<div style=\"font-size:12px\">
</div>\r\n</div>\r\n<div style=\"width:100%; height:20px\"><span
style=\"white-space:nowrap; color:gray;
opacity:.36\">______________________________________________________________
__________________</span>\r\n</div>\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-11-18T23:00:00.0000000",
"timeZone": "UTC"
},
"end": {
"dateTime": "2019-11-19T00:00:00.0000000",
"timeZone": "UTC"
},
"location": {
"displayName": "Conf Room Baker",
"locationType": "conferenceRoom",
"uniqueId": "[email protected]",
"uniqueIdType": "directory"
},
"locations": [
{
"displayName": "Conf Room Baker",
"locationType": "conferenceRoom",
"uniqueId": "[email protected]",
"uniqueIdType": "directory"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
},
"onlineMeeting": {
"joinUrl": "https://teams.microsoft.com/l/meetup-
join/19%3ameeting_NTRkMWViMmEtNzcxNC00OTk3LWJjOTEtYTdhMDU3ZmJhYWFi%40thread.
v2/0?context=%7b%22Tid%22%3a%2298a79ebe-74bf-4e07-a017-
7b410848cb32%22%2c%22Oid%22%3a%2264339082-ed84-4b0b-b4ab-
004ae54f3747%22%7d",
"conferenceId": "275984951",
"tollNumber": "+1 323-555-0166"
}
}
See also
For information on Microsoft Teams interoperability with Microsoft 365, see:
How Exchange and Microsoft Teams interact
Setting your coexistence and upgrade settings
Choose an API in Microsoft Graph to create and join online meetings
Finding possible meeting times on the Outlook calendar
Getting the free/busy schedule for users and resources
Propose meeting times in an Outlook calendar (preview)
Scheduling repeating appointments as recurring events in Outlook
Choose an API in Microsoft Graph to
create and join online meetings
Article • 11/15/2022
Microsoft Graph offers two API sets that arrange and join online meetings on Microsoft
Teams or Skype:
Programmatic support:
Apps can directly create or update an event as an online meeting in the Outlook
calendar, with a join-Teams-meeting blob inserted in the Outlook calendar
event.
Apps get properties for joining meeting over the Internet or by dialing in.
Attendees' UI experience with the programmatically created calendar event is in
full parity with any event that has been created through the Outlook UI:
Attendees can choose to meet online or in person.
Attendees can click in the join-Teams-meeting blob to join meeting over the
Internet or by dialing in.
Attendees can use other rich features of Teams, including video conferencing
and meeting lobby, if configured.
7 Note
Integration with Outlook calendar assumes an administrator has set up Outlook for
online meetings. Verify the support before using the API.
Choose the cloud communications API for flexibility and broader programmatic support:
Apps have more flexibility to further integrate the API results with line of business
and other apps. The API is decoupled with any specific calendar, and does not
create an event in any calendar.
Apps can provide the following capabilities for attendees:
Locale-based join information.
Joining meeting over the Internet or by dialing in.
Video-conferencing.
Additional security features such as meeting lobby and automating attendee
admission (preview).
Associating meeting with a Microsoft Teams chat.
Meeting lobby - No direct API integration. - API differentiates attendees from the
and - In the injected join-Teams- organizer’s company and federated
automating meeting blob of the event, companies, and other attendees including
attendee attendee can click a Meeting anonymous ones.
admission into options link to access meeting - Use the lobbyBypassSettings property.
online lobby, if enabled by the
meeting administrator.
Recurring events are an important part of Outlook calendaring. Whether it's a weekly
one-on-one meeting with your manager or a division-wide review meeting that happens
on the second Tuesday of each month, recurring events make it easy to create the event
once and let the server fill in the rest of the series.
The key bit of information that allows recurring events to "expand" into individual
occurrences is the recurrence rule. The rule specifies both how often an event repeats
and for how long. The Outlook REST APIs model recurrence rules in the recurrence
property of the event resource.
Each recurrence is made up of two parts: the recurrence pattern (how often) and the
recurrence range (for how long).
Recurrence patterns
The first part of a recurrence is the pattern. This specifies how often the event repeats.
For example, an event could repeat "every 3 days," "every Thursday," or "on July 22
every year." A pattern is represented in the API by the recurrencePattern resource.
Depending on the type of pattern, certain fields of the recurrencePattern are required,
optional, or ignored.
7 Note
Even if a field is ignored, it is still validated. If a field has a set list of possible values,
using a value outside the allowed set causes an error, even if that field is ignored.
Daily
The daily recurrence pattern causes an event to repeat based on a number of days
between each occurrence.
Relevant properties
Property Relevance Description
Examples
Repeat this event every day
JSON
"pattern": {
"type": "daily",
"interval": 1
}
JSON
"pattern": {
"type": "daily",
"interval": 3
}
Weekly
The weekly recurrence pattern causes an event to repeat on the same day or days of the
week, based on the number of weeks between each set of occurrences.
Relevant properties
daysOfWeek Required Specifies on which day(s) of the week the event occurs.
firstDayOfWeek Optional Specifies which day is considered the first day of the week.
Default value: Sunday .
interval Required Specifies the number of weeks between each set of occurrences.
JSON
"pattern": {
"type": "weekly",
"interval": 1,
"daysOfWeek": [ "Thursday" ]
}
JSON
"pattern": {
"type": "weekly",
"interval": 2,
"daysOfWeek": [
"Monday",
"Tuesday"
]
}
Absolute monthly
The absolute monthly pattern causes an event to repeat on the same day of the month
(for example, the 15th), based on the number of months between each occurrence.
Relevant properties
dayOfMonth Required Specifies on which day of the month the event occurs.
Examples
Repeat this event on the 15th of every month
JSON
"pattern": {
"type": "absoluteMonthly",
"interval": 1,
"dayOfMonth": 15
}
JSON
"pattern": {
"type": "absoluteMonthly",
"interval": 3,
"dayOfMonth": 7
}
Relative monthly
The relative monthly pattern causes an event to repeat on the same day of the week in
the same relative position in the month, based on the number of months between each
occurrence. For example, "every second Wednesday of the month."
Relevant properties
daysOfWeek Required Specifies on which day(s) of the week the event can occur. Relative
monthly events only occur once per month, so if more than one
value is specified, the event falls on the first day that satisfies the
pattern.
Examples
Repeat this event on the second Wednesday of every month
JSON
"pattern": {
"type": "relativeMonthly",
"interval": 1,
"daysOfWeek": [ "Wednesday" ],
"index": "second"
}
JSON
"pattern": {
"type": "relativeMonthly",
"interval": 1,
"daysOfWeek": [ "Thursday", "Friday" ],
"index": "first"
}
Absolute yearly
The absolute yearly pattern causes an event to repeat on the same month and day (for
example, April 15), based on the number of years between each occurrence.
Relevant properties
dayOfMonth Required Specifies on which day of the month the event occurs.
Example
Repeat this event on April 15 every year
JSON
"pattern": {
"type": "absoluteYearly",
"interval": 1,
"dayOfMonth": 15,
"month": 4
}
Relative yearly
The relative yearly pattern causes an event to repeat on the same day of the week in the
same relative position in a specific month, based on the number of years between each
occurrence. For example, "every last Wednesday of November."
Relevant properties
daysOfWeek Required Specifies on which day(s) of the week the event can occur. Relative
yearly events only occur once per year, so if more than one value is
specified, the event falls on the first day that satisfies the pattern.
Examples
JSON
"pattern": {
"type": "relativeYearly",
"interval": 1,
"daysOfWeek": [ "Wednesday" ],
"index": "last",
"month": 11
}
Recurrence ranges
The second part of a recurrence is the range. This specifies how long the pattern
repeats. For example, an event could end after 10 occurrences, by a specific date, or
could have no end. A range is represented in the API by the recurrenceRange resource.
7 Note
Even if a field is ignored, it is still validated. If a field has a set list of possible values,
using a value outside the allowed set causes an error, even if that field is ignored.
Numbered range
The numbered range causes an event to occur a fixed number of times (based on the
pattern) from a start date.
Relevant properties
recurrenceTimeZone Optional Specifies the time zone for the startDate property. If not
specified, the time zone of the event is used.
startDate Required Specifies the date to start applying the pattern. The value
of startDate MUST correspond to the date value of the
start property on the event resource. Note that the first
occurrence of the meeting may not occur on this date if it
does not fit the pattern.
Examples
Repeat this event 10 times
JSON
"range": {
"type": "numbered",
"startDate": "2017-04-02",
"numberOfOccurrences": 10
}
Relevant properties
endDate Required Specifies the date to stop applying the pattern. Note that the
last occurrence of the meeting may not occur on this date if
it does not fit the pattern.
recurrenceTimeZone Optional Specifies the time zone for the startDate and endDate
properties. If not specified, the time zone of the event is
used.
startDate Required Specifies the date to start applying the pattern. The value of
startDate MUST correspond to the date value of the start
property on the event resource. Note that the first
occurrence of the meeting may not occur on this date if it
does not fit the pattern.
Examples
JSON
"range": {
"type": "endDate",
"startDate": "2017-07-01",
"endDate": "2017-07-31"
}
No end range
The no end range causes an event to occur on all days that fit the applicable pattern
after a start date.
Relevant properties
recurrenceTimeZone Optional Specifies the time zone for the startDate property. If not
specified, the time zone of the event is used.
startDate Required Specifies the date to start applying the pattern. The value of
startDate MUST correspond to the date value of the start
property on the event resource. Note that the first
occurrence of the meeting may not occur on this date if it
does not fit the pattern.
Examples
Repeat this event from May 15, 2017, forever
JSON
"range": {
"type": "noEnd",
"startDate": "2017-05-15"
}
Examples
Meet from 1:00 PM to 1:30 PM every Monday starting September 4, 2017, until
the end of the year
The "every Monday" requirement is easily met by the weekly recurrence pattern
type.
The "until the end of the year" requirement indicates an endDate recurrence
range type.
JSON
"recurrence": {
"pattern": {
"type": "weekly",
"interval": 1,
"daysOfWeek": [ "Monday" ]
},
"range": {
"type": "endDate",
"startDate": "2017-09-04",
"endDate": "2017-12-31"
}
}
Because December 31, 2017, is on a Sunday, the last occurrence in this series will
be on Monday, December 25.
Meet from 2:00 PM to 3:00 PM on the first Thursday of every other month
starting August 29, 2017
The "first Thursday of every other month" requirement is achievable by using a
relative monthly pattern. The "every other month" portion indicates that the
interval should be set to 2 .
Because there is no requirement on an end date, a noEnd range type can be
used.
JSON
"recurrence": {
"pattern": {
"type": "relativeMonthly",
"interval": 2,
"daysOfWeek": [ "Thursday" ],
"index": "first"
},
"range": {
"type": "noEnd",
"startDate": "2017-08-29"
}
}
Because the value of startDate is after the first Thursday in August, the first
occurrence of this series will be in September.
Next steps
Find out more about integrating with Outlook calendar.
See other recurring event examples in the calendar API reference:
Create a recurring event that occurs once a week
Create a daily recurring event
Share or delegate a calendar in Outlook
Article • 03/02/2023
In Outlook, a calendar owner can share the calendar with another user. The owner can
specify which information in non-private events is viewable, and can give write access to
the calendar to users in the same organization.
The owner can also delegate another user to manage meetings in the owner's primary
calendar. Delegates are sharees who can view all information in and have write access to
non-private events. They also receive meeting requests and responses, and respond to
meeting requests on behalf of the owner. Additionally, the owner can give explicit
permissions to delegates to view the owner's private events on the calendar.
Before calendar sharing or delegation can take effect, the owner sends a sharee or
delegate an invitation, and the sharee or delegate accepts the invitation, or, explicitly
adds the shared or delegated calendar for access. The invitation and adding a shared or
delegated calendar occur in an Outlook client.
After sharing or delegation is set up in Outlook, apps can then use the Microsoft Graph
API to manage the sharing and delegation.
Alex Wilber has delegated Megan Bowen to his primary calendar, and also
permitted Megan to view private events in that calendar.
Alex shared a "Kids parties" calendar with Adele Vance and Megan Bowen, and
gave both Adele and Megan read permissions to all the details of non-private
events on the "Kids parties" calendar, and free/busy status for private events.
This article describes programmatically carrying out the following tasks with a shared or
delegated calendar:
Get calendar information about sharees, delegates, and allowed permissions, and
update individual permissions.
Get the properties that describe the sharing or delegation of the calendar.
Get or set mailbox setting to receive meeting requests and responses for a
delegated calendar.
Delete a sharee or delegate of a calendar.
Apps can also do the following using API that is generally available:
The properties and API for calendar sharing and delegating as described in this
topic are currently available in the v1.0 endpoint, with the exception of the calendar
properties isShared and isSharedWithMe. These two properties are exposed in
only the beta endpoint.
none This value applies to only My Organization which does not have any
permissions to the calendar. It doesn't apply to individual users, as only users with
permissions are associated with a calendarPermission object for the calendar.
freeBusyRead The sharee can view the owner's free/busy status, but not other
view all the details and edit (create, update, or delete) non-private events on the
calendar.
delegateWithoutPrivateEventAccess The delegate can view the owner's free/busy
status in private events, and has write access to non-private events on the
calendar.
delegateWithPrivateEventAccess The delegate can view details of the owner's
private and non-private events, and has write access to all the events on the
calendar.
The primary calendar of a user is always shared with "My Organization", which
represents the users in the same organization as the owner. By default, they can read
the owner's free/busy status on that calendar and have the freeBusyRead permission.
The first calendarPermission object is assigned to the delegate, Megan, and has
the following property values:
isRemovable is set to true, providing Alex the option to cancel the delegation.
isInsideOrganization is true as only users in the same organization can be
delegates.
role for Megan is delegateWithPrivateEventAccess , as set up by Alex.
allowedRoles includes the role types delegateWithoutPrivateEventAccess and
delegateWithPrivateEventAccess that support delegation.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/users/[email protected]/cal
endar/calendarPermissions
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/calendar/calendarPermissions",
"value": [
{
"id": "L289RXhjaGFuZ2VMYWJTWVnYW5C",
"isRemovable": true,
"isInsideOrganization": true,
"role": "delegateWithPrivateEventAccess",
"allowedRoles": [
"freeBusyRead",
"limitedRead",
"read",
"write",
"delegateWithoutPrivateEventAccess",
"delegateWithPrivateEventAccess"
],
"emailAddress": {
"name": "Megan Bowen",
"address": "[email protected]"
}
},
{
"id": "RGVmYXVsdA==",
"isRemovable": false,
"isInsideOrganization": true,
"role": "freeBusyRead",
"allowedRoles": [
"none",
"freeBusyRead",
"limitedRead",
"read",
"write"
],
"emailAddress": {
"name": "My Organization"
}
}
]
}
Aside from the role property, you cannot update other properties of an existing sharee
or delegate. Changing the emailAddress property value requires deleting the sharee or
delegate and setting up a new instance of calendarPermission again.
The example in this section updates the role property, changing the permission of an
existing sharee, Adele, from read to write for the custom calendar "Kids parties".
HTTP
HTTP
PATCH
https://graph.microsoft.com/beta/users/[email protected]/cal
endars/AAMkADAwAABf02bAAAA=/calendarPermissions/L289RXhjaGFuZ2VMYWJQWRlb
GVW
Content-type: application/json
{
"role": "write"
}
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/calendars('AAMkADAwAABf02bAAAA%3D')/calendarPermissions/$enti
ty",
"id": "L289RXhjaGFuZ2VMYWJQWRlbGVW",
"isRemovable": true,
"isInsideOrganization": true,
"role": "write",
"allowedRoles": [
"freeBusyRead",
"limitedRead",
"read",
"write"
],
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
Recalling in this example, Alex has delegated his primary calendar and given the
delegate, Megan Bowen, the permission to view calendar items that are marked private.
This section shows the properties of the delegated calendar, first from the perspective of
and with the consent of the owner, Alex, and then from the perspective of and with the
consent of the delegate, Megan. Consent from the administrator also works for each
case.
HTTP
GET
https://graph.microsoft.com/beta/users/[email protected]/cal
endar
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/calendar/$entity",
"id": "AQMkADAw7QAAAJfygAAAA==",
"name": "Calendar",
"color": "auto",
"hexColor": "",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAAAAACOg==",
"canShare": true,
"canViewPrivateItems": true,
"isShared": true,
"isSharedWithMe": false,
"canEdit": true,
"allowedOnlineMeetingProviders": [
"teamsForBusiness"
],
"defaultOnlineMeetingProvider": "teamsForBusiness",
"isTallyingResponses": true,
"isRemovable": false,
"owner": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
7 Note
HTTP
HTTP
GET
https://graph.microsoft.com/beta/users/[email protected]/ca
lendars/AAMkADlAABhbftjAAA=
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('meganb%40contoso.OnMicros
oft.com')/calendars/$entity",
"id": "AAMkADlAABhbftjAAA=",
"name": "Alex Wilber",
"color": "auto",
"hexColor": "",
"changeKey": "E6LznKWmX0KTsAD9qRJjeAAAYWo3EQ==",
"canShare": false,
"canViewPrivateItems": true,
"isShared": false,
"isSharedWithMe": true,
"canEdit": true,
"allowedOnlineMeetingProviders": [
"teamsForBusiness"
],
"defaultOnlineMeetingProvider": "teamsForBusiness",
"isTallyingResponses": true,
"isRemovable": true,
"owner": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
Depending on the level of delegation a calendar owner prefers, the owner can specify
who should receive meeting requests and responses to manage meetings on the
calendar.
sendToDelegateOnly
sendToDelegateAndInformationToPrincipal
sendToDelegateAndPrincipal
This is a mailbox-wide setting, so the same setting applies to all delegates of the
mailbox owner.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/users/[email protected]/mai
lboxsettings
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/mailboxSettings",
"archiveFolder": "AQMkADAwAGVQAAAKfowAAAA==",
"timeZone": "Pacific Standard Time",
"delegateMeetingMessageDeliveryOptions": "sendToDelegateOnly",
"dateFormat": "M/d/yyyy",
"timeFormat": "h:mm tt",
"automaticRepliesSetting": {
"status": "disabled",
"externalAudience": "all",
"internalReplyMessage": "",
"externalReplyMessage": "",
"scheduledStartDateTime": {
"dateTime": "2019-12-24T05:00:00.0000000",
"timeZone": "UTC"
},
"scheduledEndDateTime": {
"dateTime": "2019-12-25T05:00:00.0000000",
"timeZone": "UTC"
}
},
"language": {
"locale": "en-US",
"displayName": "English (United States)"
},
"workingHours": {
"daysOfWeek": [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday"
],
"startTime": "08:00:00.0000000",
"endTime": "17:00:00.0000000",
"timeZone": {
"name": "Pacific Standard Time"
}
}
}
HTTP
HTTP
PATCH
https://graph.microsoft.com/beta/users/[email protected]/mai
lboxsettings
Content-type: application/json
{
"delegateMeetingMessageDeliveryOptions": "sendToDelegateAndPrincipal"
}
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/mailboxSettings",
"delegateMeetingMessageDeliveryOptions": "sendToDelegateAndPrincipal"
}
HTTP
HTTP
DELETE
https://graph.microsoft.com/beta/users/[email protected]/cal
endars/AAMkADAwAABf02bAAAA=/calendarPermissions/L289RXhjaGFuZ2VMYWJTWVnY
W5C
HTTP
In Outlook, a calendar owner can share a calendar with other users and let them view or
modify events in that calendar; the shared calendar can be the owner's primary calendar
or a custom calendar created by the owner. The owner can also grant a delegate to their
primary calendar and act on their behalf to receive or respond to meeting requests or
create or change items in the primary calendar.
The three examples specify the owner's identity (Alex' user ID or user principal name)
and the calendar shortcut. They access calendar and event IDs that correspond to only
the owner's mailbox. Specifying these calendar and event IDs in the sharee's mailbox
(Megan's user ID or user principal name) would return an error. To use calendar and
event IDs that correspond to the sharee's mailbox, see Sharee: Get shared, custom
calendar or its events from sharee's mailbox.
7 Note
HTTP
On successful completion, you'll get HTTP 200 OK and a calendar instance that
represents Alex' shared, primary calendar, in Alex' mailbox.
HTTP
On successful completion, you'll get HTTP 200 OK and the event instance identified by
{id} in Alex' primary calendar, directly from Alex' mailbox.
HTTP
The same GET capabilities apply if Alex has delegated Megan access to Alex' primary
calendar, or if Alex has delegated Megan his entire mailbox.
If Alex has not shared nor delegated his primary calendar with Megan, specifying Alex’s
user ID or user principal name in the preceding GET operations will return an error.
1. Signed in as Adele, use either of the following requests to get all the calendars that
Adele has access to, including the shared custom calendar.
HTTP
GET https://graph.microsoft.com/v1.0/me/calendars
GET https://graph.microsoft.com/v1.0/users/{Adele-userId | Adele-
userPrincipalName}/calendars
A successful response includes the response code HTTP 200, and the collection of
calendars that Adele has access to, including the calendar ("Kids parties") that has
the owner name as "Alex Wilber" as the second calendar in the response. For a
sharee, Adele, the canShare property of the shared calendar is always false.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('d3b9214b-dd8b-441d-
b7dc-c446c9fa0e69')/calendars",
"value": [
{
"id": "AQMkADU5NAAAJMjAAAAA==",
"name": "Calendar",
"color": "auto",
"changeKey": "NDznl+Uh50WkanaCOKHkaQAAAAACXQ==",
"canShare": true,
"canViewPrivateItems": true,
"canEdit": true,
"owner": {
"name": "Adele Vance",
"address": "[email protected]"
}
},
{
"id": "AAMkADAABf0JlyAAA=",
"name": "Kids parties",
"color": "lightYellow",
"changeKey": "NDznl+Uh50WkanaCOKHkaQAAYumJRQ==",
"canShare": false,
"canViewPrivateItems": false,
"canEdit": false,
"owner": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
]
}
2. Signed in as Adele, get the shared calendar, or get one or more events in the
shared calendar, using the second calendar ID in the response from step 1. The IDs
of the shared calendar and its event correspond to the local copy of Alex' calendar
in Adele's mailbox.
HTTP
GET https://graph.microsoft.com/v1.0/me/calendars/AAMkADAABf0JlyAAA=
GET https://graph.microsoft.com/v1.0/users/{Adele-userId | Adele-
userPrincipalName}/calendars/AAMkADAABf0JlyAAA=
GET
https://graph.microsoft.com/v1.0/me/calendars/AAMkADAABf0JlyAAA=/events
/{id}
GET https://graph.microsoft.com/v1.0/users/{Adele-userId | Adele-
userPrincipalName}/calendars/AAMkADAABf0JlyAAA=/events/{id}
GET
https://graph.microsoft.com/v1.0/me/calendars/AAMkADAABf0JlyAAA=/events
GET https://graph.microsoft.com/v1.0/users/{Adele-userId | Adele-
userPrincipalName}/calendars/AAMkADAABf0JlyAAA=/events
On successful completion, you'll get HTTP 200 OK and the requested event, events, or
calendar that Alex has shared with Adele.
Next steps
Find out more about:
In Outlook, customers can share a calendar with other users and let them view, create,
or modify events in that calendar. Customers can also grant a delegate to act on their
behalf to receive or respond to meeting requests or create or change items in the
calendar.
The walkthrough below uses the example scenario where Alex has delegated his primary
calendar to Adele in Outlook, and kept the default Outlook mailbox setting to direct
meeting requests and responses to only delegates. (This setting corresponds to the
delegateMeetingMessageDeliveryOptions property of Alex' mailboxSettings set as the
default value sendToDelegateOnly .)
If Alex has shared and not delegated his calendar with Adele:
Signed in as Adele, an app can get the calendar that Alex has shared with Adele.
The app can use the requests and responses in steps 2 to 4 to apply to the shared
calendar the same way as the delegated calendar.
In step 5, the app can sign in as Alex, instead of Adele, to receive Christie's
response message.
Step 1: Adele gets the delegated calendar
Signed in as Adele, get the calendars she has access to and identify the one Alex has
delegated to her, so to use it in the next step to create an event in that calendar.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/calendars
Notice a successful response includes the response code HTTP 200, Adele's own primary
calendar, and a copy of the calendar delegated by Alex in Adele's mailbox, with the
following properties:
canShare is false since Adele is only a delegate and not the calendar owner.
canEdit is true since as delegate, Adele has write access to non-private events in
the delegated calendar.
owner is Alex Wilber indicating it is Alex' calendar.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69')/calendars",
"value": [
{
"id": "AQMkADGkAAAJMjAAAAA==",
"name": "Calendar",
"color": "auto",
"changeKey": "NDznl+Uh50WkanaCOKHkaQAAAAACXQ==",
"canShare": true,
"canViewPrivateItems": true,
"canEdit": true,
"owner": {
"name": "Adele Vance",
"address": "[email protected]"
}
},
{
"id": "AAMkADRpAABf0JlzAAA=",
"name": "Alex Wilber",
"color": "auto",
"changeKey": "NDznl+Uh50WkanaCOKHkaQAAX8m4eQ==",
"canShare": false,
"canViewPrivateItems": false,
"canEdit": true,
"owner": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
]
}
7 Note
Signed in as Adele, you can alternatively get the delegated calendar directly from
Alex' mailbox, by specifying Alex' identity and the calendar shortcut, as in GET
https://graph.microsoft.com/v1.0/users/[email protected]/calendar .
The returned calendar ID corresponds to only Alex' mailbox.
HTTP
POST
https://graph.microsoft.com/v1.0/me/calendars/AAMkADRpAABf0JlzAAA=/events
{
"subject": "Christmas dinner",
"body": {
"contentType": "HTML",
"content": "Happy holidays!"
},
"start": {
"dateTime": "2019-12-25T18:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-12-25T22:00:00",
"timeZone": "Pacific Standard Time"
},
"location":{
"displayName":"Alex' home"
},
"attendees": [
{
"emailAddress": {
"address":"[email protected]",
"name": "Megan Bowen"
},
"type": "required"
},
{
"emailAddress": {
"address":"[email protected]",
"name": "Christie Cline"
},
"type": "required"
}
]
}
C#
Read the SDK documentation for details on how to add the SDK to your project
and create an authProvider instance.
Notice a successful response includes the response code HTTP 200 and the following
eventMessage properties:
Adele's identity appears only in the sender property of the eventMessage and not in the
associated event.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('662b947c-d9a1-4064-926c-
eba1316d4462')/messages(microsoft.graph.eventMessage/event())/$entity",
"@odata.type": "#microsoft.graph.eventMessage",
"@odata.etag": "W/\"CwAAABYAAADK82uJYVo4RrFV3ADVj3fyAABZ378h\"",
"id": "AAMkADADVj3fyAABZ5hYdAAA=",
"createdDateTime": "2019-12-21T04:59:03Z",
"lastModifiedDateTime": "2019-12-21T04:59:04Z",
"changeKey": "CwAAABYAAADK82uJYVo4RrFV3ADVj3fyAABZ378h",
"categories": [],
"receivedDateTime": "2019-12-21T04:59:03Z",
"sentDateTime": "2019-12-21T04:59:01Z",
"hasAttachments": false,
"internetMessageId": "
<DM6PR17MB3593711A1C0A098167F5A977A12C0@DM6PR17MB3593.namprd17.prod.outlook.
com>",
"subject": "Christmas dinner",
"bodyPreview": "Happy holidays!",
"importance": "normal",
"parentFolderId": "AQMkADIAAAIBDAAAAA==",
"conversationId": "AAQkADNqQlzYAM8jQM=",
"conversationIndex": "AdW3u1xx5S7TYrbluE2pCXNgAzyNAw==",
"isDeliveryReceiptRequested": null,
"isReadReceiptRequested": false,
"isRead": true,
"isDraft": false,
"webLink": "https://outlook.office365.com/owa/?
ItemID=AAMkADADVj3fyAABZ5hYdAAA%3D&exvsurl=1&viewmodel=ReadMessageItem",
"inferenceClassification": "focused",
"meetingMessageType": "meetingRequest",
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nHappy
holidays!\r\n</body>\r\n</html>\r\n"
},
"sender": {
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
},
"from": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
},
"toRecipients": [
{
"emailAddress": {
"name": "Megan Bowen",
"address": "[email protected]"
}
},
{
"emailAddress": {
"name": "Christie Cline",
"address": "[email protected]"
}
}
],
"ccRecipients": [],
"bccRecipients": [],
"replyTo": [],
"flag": {
"flagStatus": "notFlagged"
},
"event": {
"@odata.etag": "W/\"yvNriWFaOEaxVdwA1Y938gAAX+T7Jg==\"",
"id": "AAMkADADVj3fyAABZ5ieyAAA=",
"createdDateTime": "2019-12-21T04:59:03.4336242Z",
"lastModifiedDateTime": "2019-12-27T01:38:32.3766961Z",
"changeKey": "yvNriWFaOEaxVdwA1Y938gAAX+T7Jg==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"iCalUId": "040000008200FEFE0BA532444B5FD89BDE22BA103",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Christmas dinner",
"bodyPreview": "Happy holidays!",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": false,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "tentative",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADADVj3fyAABZ5ieyAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"recurrence": null,
"responseStatus": {
"response": "none",
"time": "2019-12-21T05:16:48.8931825Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-
Type\" content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nHappy
holidays!\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-12-26T02:00:00.0000000",
"timeZone": "UTC"
},
"end": {
"dateTime": "2019-12-26T06:00:00.0000000",
"timeZone": "UTC"
},
"location": {
"displayName": "Alex' home",
"locationType": "default",
"uniqueId": "Alex' home",
"uniqueIdType": "private"
},
"locations": [
{
"displayName": "Alex' home",
"locationType": "default",
"uniqueId": "1396aaf3-e344-4567-a4e3-797557ec24c8",
"uniqueIdType": "locationStore"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
},
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Megan Bowen",
"address": "[email protected]"
}
},
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Christie Cline",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
}
}
HTTP C#
HTTP
POST
https://graph.microsoft.com/v1.0/me/events/AAMkADADVj3fyAABZ5ieyAAA=/ten
tativelyAccept
Content-type: application/json
{
"comment": "I will probably be able to make it.",
"sendResponse": true
}
C#
// Code snippets are only available for the latest version. Current
version is 5.x
Read the SDK documentation for details on how to add the SDK to your project
and create an authProvider instance.
HTTP
Signed in as Adele, get the eventMessage that represents the response from Christie in
step 4.
HTTP C#
HTTP
GET
https://graph.microsoft.com/v1.0/me/messages/AAMkADI4oeRpAABf0HJUAAA=
C#
// Code snippets are only available for the latest version. Current
version is 5.x
Read the SDK documentation for details on how to add the SDK to your project
and create an authProvider instance.
Notice a successful response includes the response code HTTP 200 and the following
eventMessage properties:
meetingMessageType is meetingTenativelyAccepted .
from is Christie.
toRecipients includes only Adele, but not the calendar owner Alex. This is because
Alex kept the default to have Outlook direct all meeting responses to only
delegates.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69')/messages/$entity",
"@odata.type": "#microsoft.graph.eventMessage",
"@odata.etag": "W/\"DAAAABYAAAA0POeX5SHnRaRqdoI4oeRpAABfybkT\"",
"id": "AAMkADI4oeRpAABf0HJUAAA=",
"createdDateTime": "2019-12-21T05:16:55Z",
"lastModifiedDateTime": "2019-12-21T05:16:57Z",
"changeKey": "DAAAABYAAAA0POeX5SHnRaRqdoI4oeRpAABfybkT",
"categories": [],
"receivedDateTime": "2019-12-21T05:16:56Z",
"sentDateTime": "2019-12-21T05:16:49Z",
"hasAttachments": false,
"internetMessageId": "
<86880ccb8ec64184996e46eaddaed279@DM6PR17MB3593.namprd17.prod.outlook.com>",
"subject": "Tentative: Christmas dinner",
"bodyPreview": "I will probably be able to make it.",
"importance": "normal",
"parentFolderId": "AQMkAD5GkAAAIBDAAAAA==",
"conversationId": "AAQkADK25bhNqQlzYAM8jQM=",
"conversationIndex": "AdW3u1xx5S7TYrbluE2pCXNgAzyNAwAAoBoZ",
"isDeliveryReceiptRequested": null,
"isReadReceiptRequested": false,
"isRead": false,
"isDraft": false,
"webLink": "https://outlook.office365.com/owa/?
ItemID=AAMkADI4oeRpAABf0HJUAAA%3D&exvsurl=1&viewmodel=ReadMessageItem",
"inferenceClassification": "focused",
"meetingMessageType": "meetingTenativelyAccepted",
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nI will probably be able to make
it.\r\n</body>\r\n</html>\r\n"
},
"sender": {
"emailAddress": {
"name": "Christie Cline",
"address": "[email protected]"
}
},
"from": {
"emailAddress": {
"name": "Christie Cline",
"address": "[email protected]"
}
},
"toRecipients": [
{
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"ccRecipients": [],
"bccRecipients": [],
"replyTo": [],
"flag": {
"flagStatus": "notFlagged"
}
}
Signed in as Alex, get the event that Adele created in step 2 and get responses from the
attendees property.
Use the least privileged delegated permission, Calendars.Read . For more information,
see calendar permissions.
HTTP C#
HTTP
GET
https://graph.microsoft.com/v1.0/me/calendar/events/AAMkADJXJGu0AABf02qw
AAA=
C#
// Code snippets are only available for the latest version. Current
version is 5.x
Read the SDK documentation for details on how to add the SDK to your project
and create an authProvider instance.
Notice a successful response includes the response code HTTP 200 and the following
event properties:
isOrganizer is true.
attendees include only Megan and Christie.
The status property of each attendee instance indicates any response from the
attendee:
Megan's response is none .
Christie's response is tentativelyAccepted .
organizer is Alex.
No property in the returned event indicates the delegate, Adele.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/calendars('AQMkADAw7QAAAJfygAAAA%3D%3D')/events/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAAX8xuhA==\"",
"id": "AAMkADJXJGu0AABf02qwAAA=",
"createdDateTime": "2019-12-21T04:59:01.4435895Z",
"lastModifiedDateTime": "2019-12-21T05:16:54.689345Z",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAAX8xuhA==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"iCalUId": "040000008200FEFE0BA532444B5FD89BDE22BA103",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Christmas dinner",
"bodyPreview": "Happy holidays!",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": true,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "busy",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADJXJGu0AABf02qwAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"recurrence": null,
"responseStatus": {
"response": "organizer",
"time": "0001-01-01T00:00:00Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nHappy
holidays!\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-12-26T02:00:00.0000000",
"timeZone": "UTC"
},
"end": {
"dateTime": "2019-12-26T06:00:00.0000000",
"timeZone": "UTC"
},
"location": {
"displayName": "Alex' home",
"locationType": "default",
"uniqueId": "Alex' home",
"uniqueIdType": "private"
},
"locations": [
{
"displayName": "Alex' home",
"locationType": "default",
"uniqueId": "Alex' home",
"uniqueIdType": "private"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Megan Bowen",
"address": "[email protected]"
}
},
{
"type": "required",
"status": {
"response": "tentativelyAccepted",
"time": "2019-12-21T05:16:48.8931825Z"
},
"emailAddress": {
"name": "Christie Cline",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
}
Next steps
Find out more about:
Using the Microsoft Graph API, you can attach files up to 150 MB to an Outlook
message or event item. Depending on the file size, choose one of two ways to attach
the file:
If the file size is under 3 MB, do a single POST on the attachments navigation
property of the Outlook item; see how to do this for a message or for an event.
The successful POST response includes the ID of the file attachment.
If the file size is between 3 MB and 150 MB, create an upload session, and
iteratively use PUT to upload ranges of bytes of the file until you have uploaded
the entire file. A header in the final successful PUT response includes a URL with
the attachment ID.
To attach multiple files to a message, choose the approach for each file based on its file
size and attach the files individually.
This article illustrates the second approach step by step, creating and using an upload
session to add a large file attachment (of size over 3 MB) to an Outlook item. Each step
shows the corresponding code for a message and for an event. Upon successfully
uploading the entire file, the article shows getting a response header that contains an ID
for the file attachment, and then using that attachment ID to get the raw attachment
content or attachment metadata.
) Important
A successful operation returns HTTP 201 Created and a new uploadSession instance,
which contains an opaque URL that you can use in subsequent PUT operations to
upload portions of the file. The uploadSession provides a temporary storage location
where the bytes of the file are saved until you have uploaded the complete file.
Permissions
Make sure to request Mail.ReadWrite permission to create the uploadSession for a
message, and Calendars.ReadWrite for an event.
The opaque URL, returned in the uploadUrl property of the new uploadSession, is pre-
authenticated and contains the appropriate authorization token for subsequent PUT
queries in the https://outlook.office.com domain. That token expires by
expirationDateTime. Do not customize this URL for the PUT operations.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/me/messages/AAMkADI5MAAIT3drCAAA=/attac
hments/createUploadSession
Content-type: application/json
{
"AttachmentItem": {
"attachmentType": "file",
"name": "flower",
"size": 3483322
}
}
Response
The following example response shows the uploadSession resource returned for the
message.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
"uploadUrl": "https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-
95c1-b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?
authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI",
"expirationDateTime": "2019-09-25T01:09:30.7671707Z",
"nextExpectedRanges": [
"0-"
]
}
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/me/events/AAMkADU5CCmSAAA=/attachments/
createUploadSession
Content-type: application/json
{
"AttachmentItem": {
"attachmentType": "file",
"name": "flower",
"size": 3483322
}
}
Response
The following example response shows the uploadSession resource returned for the
event.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
"uploadUrl": "https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-
441d-b7dc-c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJ
lCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw",
"expirationDateTime": "2020-02-22T02:46:56.7410786Z",
"nextExpectedRanges": [
"0-"
]
}
Request headers
Content- Int32 The number of bytes being uploaded in this operation. For better
Length performance, keep the upper limit of the number of bytes for each PUT
operation to 4 MB. Required.
Content- String The 0-based byte range of the file being uploaded in this operation,
Range expressed in the format bytes {start}-{end}/{total} . Required.
Do not specify an Authorization request header. The PUT query uses a pre-
authenticated URL from the uploadUrl property, that allows access to the
https://outlook.office.com domain.
Request body
Specify the actual bytes of the file to be attached, that are in the location range
specified by the Content-Range request header.
Response
A successful upload returns HTTP 200 OK and an uploadSession object. Note the
following in the response object:
The expirationDateTime property indicates the expiration date/time for the auth
token embedded in the uploadUrl property value. This expiration date/time
remains the same as returned by the initial uploadSession in step 1.
The nextExpectedRanges specifies the next byte location to start uploading from,
for example, "nextExpectedRanges":["2097152"] . You must upload bytes in a file in
order.
The uploadUrl property is not explicitly returned, because all PUT operations of an
upload session use the same URL returned when creating the session (step 1).
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
Content-Type: application/octet-stream
Content-Length: 2097152
Content-Range: bytes 0-2097151/3483322
{
<bytes 0-2097151 of the file to be attached, in binary format>
}
Response
The following example response shows in the nextExpectedRanges property the start of
the next byte range that the server expects.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
"@odata.context":"https://outlook.office.com/api/v2.0/$metadata#Users('a8e8e
219-4931-95c1-b73d-62626fd79c32%4072aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA%3D')/AttachmentSessions/$entit
y",
"ExpirationDateTime":"2019-09-25T01:09:30.7671707Z",
"nextExpectedRanges":["2097152"]
}
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJ
lCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw
Content-Type: application/octet-stream
Content-Length: 2097152
Content-Range: bytes 0-2097151/3483322
{
<bytes 0-2097151 of the file to be attached, in binary format>
}
Response
The following example response shows in the nextExpectedRanges property the start of
the next byte range that the server expects.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://outlook.office.com/api/v2.0/$metadata#Users('d3b92
14b-dd8b-441d-b7dc-c446c9fa0e69%4098a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA%3D')/AttachmentSessions/$entity",
"ExpirationDateTime":"2020-02-22T02:46:56.7410786Z",
"nextExpectedRanges":["2097152"]
}
Once the last byte of the file has been successfully uploaded, the final PUT operation
returns HTTP 201 Created and a Location header that indicates the URL to the file
attachment in the https://outlook.office.com domain. You can get the attachment ID
from the URL and save it for later use. Depending on your scenario, you can use that ID
to get the metadata of the attachment, or remove the attachment from the Outlook
item using the Microsoft Graph endpoint.
The following examples show uploading the last byte range of the file to the message
and to the event in the preceding steps.
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
Content-Type: application/octet-stream
Content-Length: 1386170
Content-Range: bytes 2097152-3483321/3483322
{
<bytes 2097152-3483321 of the file to be attached, in binary format>
}
Response
The following example response shows a Location response header from which you can
save the attachment ID ( AAMkADI5MAAIT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0= ) for later
use.
HTTP
Location: https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-
b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/Attachments('AAMkADI5MAAIT3
drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=')
Content-Length: 0
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJ
lCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw
Content-Type: application/octet-stream
Content-Length: 1386170
Content-Range: bytes 2097152-3483321/3483322
{
<bytes 2097152-3483321 of the file to be attached, in binary format>
}
Response
The following example response shows a Location response header from which you can
save the attachment ID ( AAMkADU5CCmSAAANZAlYPeyQByv7Y= ) for later use.
HTTP
HTTP/1.1 201 Created
Location: https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-
b7dc-c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/Attachments('AAMkADU5CCmSAAANZAlYP
eyQByv7Y=')
Content-Length: 0
As an alternative to getting the attachment content in base64 format, you can get
the raw data of the file attachment.
To get the metadata of the file attachment, append a $select parameter to
include only those metadata properties you want, excluding the contentBytes
property which returns the file attachment in base64 format.
Permissions
Use the least privileged delegated or application permission, Calendars.Read , as
appropriate, for this operation. For more information, see calendar permissions.
Request
HTTP
GET https://graph.microsoft.com/v1.0/Users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/Attachments('AAMkADU5CCmSAAANZAlYP
eyQByv7Y=')/$value
Response
HTTP
HTTP/1.1 200 OK
content-length: 3483322
Content-type: image/jpeg
Permissions
Use the least privileged delegated or application permission, Mail.Read , as appropriate,
for this operation. For more information, see mail permissions.
Request
HTTP
GET https://graph.microsoft.com/api/v1.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/Attachments('AAMkADI5MAAIT3
drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=')?
$select=lastModifiedDateTime,name,contentType,size,isInline
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('a8e8e219-4931-95c1-b73d-
62626fd79c32%4072aa88bf-76f0-494f-91ab-
2d7cd730db47')/messages('AAMkADI5MAAIT3drCAAA%3D')/attachments/$entity",
"@odata.type": "#microsoft.graph.fileAttachment",
"@odata.mediaContentType": "image/jpeg",
"id": "AAMkADI5MAAIT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=",
"lastModifiedDateTime": "2019-09-24T23:27:43Z",
"name": "flower",
"contentType": "image/jpeg",
"size": 3640066,
"isInline": false
}
Permissions
Because the initial opaque URL is pre-authenticated and contains the appropriate
authorization token for subsequent queries for that upload session, do not specify an
Authorization request header for this operation.
Request
HTTP
DELETE https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
Response
HTTP
ErrorAttachmentSizeShouldNotBeLessThanMinimumSize
This error is returned when attempting to create an upload session to attach a file
smaller than 3 MB. If the file size is under 3 MB, you should do a single POST on the
attachments navigation property of the message or of the event. The successful POST
response includes the ID of the file attached to the message.
Obtain immutable identifiers for
Outlook resources
Article • 06/25/2022
Outlook items (messages, events, contacts, tasks) have an interesting behavior that
you've probably either never noticed or has caused you significant frustration: their IDs
change. It doesn't happen often, only if the item is moved, but it can cause real
problems for apps that store IDs offline for later use. Immutable identifiers (IDs) enable
your application to obtain an ID that does not change for the lifetime of the item.
7 Note
Immutable identifiers, like all identifiers in Microsoft Graph, are case-sensitive. Keep
this in mind if you are comparing IDs.
How it works
Immutable ID is an optional feature for Microsoft Graph. To opt in, your application
needs to send an additional HTTP header in your API requests:
HTTP
Prefer: IdType="ImmutableId"
This header only applies to the request it is included with. If you want to always use
immutable IDs, you must include this header with every API request.
Container types (mailFolder, calendar, etc.) do not support immutable ID, but their
regular IDs were already constant.
1. Create a draft message using the Prefer: IdType="ImmutableId" header and save
the id property of the message in the response.
2. Send the message using the ID from the previous step.
3. Get the message using the ID from the first step. This is the copy in Sent Items.
7 Note
Getting the message in Sent Items may not succeed immediately after sending the
message. The copy of the message is not created until the message successfully
sends, which may take time.
with both ID formats, so your application does not need to re-synchronize to take
advantage of immutable ID. You can use the header to get immutable IDs going
forward, and you can update your app's storage separately.
7 Note
Example
The following example translates a normal Microsoft Graph ID to an immutable
Microsoft Graph ID.
Request
HTTP
POST https://graph.microsoft.com/v1.0/me/translateExchangeIds
{
"inputIds" :
[
"AQMkAGM2…"
],
"targetIdType" : "restImmutableEntryId",
"sourceIdType" : "restId"
}
Response
HTTP
HTTP 200 OK
{
"value": [
{
"targetId": "AAkALgAA...",
"sourceId": "AQMkAGM2..."
}
]
}
Change notifications for Outlook
resources in Microsoft Graph
Article • 03/02/2023
The Microsoft Graph API lets you subscribe to changes to a resource—including creation,
update, or deletion of the resource—and receive notifications via webhooks. A subscription
specifies the desired types of changes to monitor for a specific resource, and includes a
URL for an endpoint to receive notifications of those changes.
Setting up a subscription reduces the overhead of otherwise having to query and compare
resources to deduce any changes. You can optionally specify in the subscription request to
encrypt and include as part of a notification the resource data that has changed, saving a
separate subsequent API call to get the resource payload.
There is a maximum limit of 1000 active subscriptions for Outlook resources per mailbox
for all applications. You can subscribe to changes in contacts, events, or messages in the
mailbox.
The following Outlook resources support subscriptions with or without resource data in the
change notification payload.
contact
event
message
Create a subscription
To create a subscription, specify the Outlook resource and the type of changes (creation,
update, or deletion) for which you want to receive notifications. See an example.
Request permissions
Creating and managing (getting, updating, and deleting) a subscription requires a read
scope to the resource. For example, to get change notifications on messages, your app
needs the Mail.Read permission. Outlook change notifications support delegated and
application permission scopes. Note the following limitations:
Depending on the resource, use the least privileged permission specified in the following
table to call this API.
Notifications with resource data for Outlook resources are currently available only in
the Microsoft Graph beta endpoint.
To have resource data included in a change notification, you must specify the following
properties, in addition to those you normally include when creating a subscription:
resource: This property specifies the resource URL. Make sure to use the $select
query parameter to explicitly specify the Outlook resource properties to include in the
notification payload.
7 Note
encryptionCertificate: This property contains only the public key that Microsoft Graph
uses to encrypt resource data. Keep the corresponding private key to decrypt the
content.
encryptionCertificateId: This property is your own identifier for the certificate. Use
this ID to match in each change notification which certificate to use for decryption.
See an example for subscribing to change notifications with resource data for the message
resource.
One common application of $filter is to get notified upon a change in a specific resource
property. For example, you can use $filter to subscribe to unread messages in a folder
(the isRead property is false ), and include all the change types:
If you lose the permission granted earlier for a subscription and the subscription expires
meanwhile, request permission again to create a new subscription.
{
"value": [
{
"subscriptionId": "dfd11b2f-8222-4189-9545-4205c95d6235",
"subscriptionExpirationDateTime": "2021-12-31T16:16:44.9907405+05:30",
"changeType": "created",
"resource": "Users('722effaf-0433-4272-9ac4-
d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"encryptedContent": {
"data": "<<--EncryptedContent-->>",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"dataSignature": "Qw/9ubWeUYJPWWXvNiGgct2FkNG2MXTRm/BLUpJM66k=",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"resourceData": {
"@odata.type": "#microsoft.graph.message",
"@odata.id": "Users('722effaf-0433-4272-9ac4-
d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUR8n\"",
"id": "AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA="
}
}
]
"validationTokens": ["<<--ValidationTokens-->>"]
}
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
JSON
{
"[email protected]":"#DateTimeOffset",
"receivedDateTime":"2021-12-30T10:53:35Z",
"subject":"TEST MESSAGE FOR RICH NOTIFICATIONS",
"bodyPreview":"Hello,\r\n\r\nWhat\u2019s up?\r\n\r\nThanks\r\nMegan",
"[email protected]":"#microsoft.graph.importance",
"importance":"normal",
"from": {
"@odata.type":"#microsoft.graph.recipient",
"emailAddress": {
"@odata.type":"#microsoft.graph.emailAddress",
"name":"Megan Brown",
"address":"[email protected]"
}
}
}
The next example shows the payload of a notification that corresponds to an Outlook
message resource. It includes the resource and resourceData properties, which represent
the resource that triggered the notification. Use the resource and @odata.id properties to
make calls to Microsoft Graph to get the payload of the resource.
7 Note
GET calls always return the current state of the resource. If the resource is changed
between the time the notification is sent and the time the resource is retrieved, the
operation returns the state of the resource on retrieval.
JSON
"value": [
{
"subscriptionId": "c6126aa3-0ed8-412f-a988-71e6cee627c4",
"subscriptionExpirationDateTime": "2022-01-02T03:12:18.2257768+05:30",
"changeType": "created",
"resource": "Users/622eaaff-0683-4862-9de4-
f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIxAAA=",
"resourceData": {
"@odata.type": "#Microsoft.Graph.Message",
"@odata.id": "Users/622eaaff-0683-4862-9de4-
f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIAAA=",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUUXn\"",
"id": "AAMkAGUwNjQ4ZjIxAAA="
},
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}
]
Examples
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"expirationDateTime": "2021-07-07T21:42:18.2257768+00:00",
"clientState": "secretClientState"
}
Response
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "5522bd62-7c96-4530-85b0-00b916f6151a",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientState",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T21:42:18.2257768Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": null,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": null,
"encryptionCertificateId": null,
"notificationUrlAppId": null
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?
$select=Subject,bodyPreview,importance,receivedDateTime,from",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "178eec5f-cf3c-4e7e-8a9c-8640deb5b5c5",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?
$select=Subject,bodyPreview,importance,receivedDateTime,from",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "me/mailfolders('Drafts')/messages?
$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance
eq 'High'",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "239dbc5f-cf3c-4e7e-8c9c-3340abc5b5c5",
"resource": "me/mailfolders('Drafts')/messages?
$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance eq
'High'",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-20T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}
See also
Microsoft Graph change notifications
Set up change notifications that include resource data
Outlook mail API overview
Outlook contacts API overview
Outlook calendar API overview
Set up notifications for changes in
resource data
Article • 04/20/2023
https://www.youtube-nocookie.com/embed/rC1bunenaq4
Basic notifications: Change notifications that don't contain resource data other
than the id of the resource that changed. All Microsoft Graph resources support
basic notifications. When an app receives a basic notification, the service can use
the id to query to changed object.
Rich notifications: Change notifications that include the resource data of the
object that changed. For more information about rich notifications, see Rich
notifications.
Lifecycle notifications: Notifications that alert the customer when they are at risk
of missing change notifications due to the lifecycle of their subscription. For more
information about lifecycle notifications, see Lifecycle notifications.
Supported resources
An app can subscribe to changes on the Microsoft Graph resources listed in the table,
which also indicates the limits that apply for subscriptions to the resources. When any
limit is exceeded, attempts to create a subscription will result in an 403 Forbidden error
response. The message property of the error response will explain the limit that has
been exceeded.
7 Note
Cloud printing Changes when there is a valid job in the queue (jobStarted -
printTaskDefinition event): /print/printtaskdefinition/{id}/tasks
Not
supported for
Azure AD
B2C tenants.
A known
issue for the
subscription
changeType.
Teams chatMessage Changes to chat messages in all channels in all teams: Maximum
/teams/getAllMessages subscription
quotas:
Changes to chat messages in a specific channel: Per app
/teams/{id}/channels/{id}/messages and channel
or chat
Changes to chat messages in all chats: /chats/getAllMessages combination:
1
Changes to chat messages in a specific chat: subscription.
/chats/{id}/messages Per user
(for
Changes to chat messages in all chats a particular user is part subscriptions
of: /users/{id}/chats/getAllMessages tracking chat
messages in
Changes to chat messages for all chats in an organization all chats the
where a particular Teams app is installed: user is part
/appCatalogs/teamsApps/{id}/installedToChats/getAllMessages of): 10
subscriptions.
Per
organization:
10,000 total
subscriptions.
Resource Supported resource paths Limitations
Not
supported for
personal
Microsoft
accounts like
outlook.com.
Not
supported for
Azure AD
B2C tenants.
A known
issue for the
subscription
changeType.
Some of these resources support rich notifications (notifications with resource data). For
more information about resources that support rich notifications, see Set up change
notifications that include resource data.
Subscription lifetime
Subscriptions have a limited lifetime. Apps need to renew their subscriptions before the
expiration time; Otherwise, they need to create a new subscription. Apps can also
unsubscribe at any time to stop getting change notifications.
The following table shows the maximum expiration times for subscriptions per resource
in Microsoft Graph.
Webhooks for this resource are only available in the global endpoint
and not in the national clouds.
Note: Existing applications and new applications should not exceed the supported
value. In the future, any requests to create or renew a subscription beyond the
maximum value will fail.
Managing subscriptions
Clients can create subscriptions, renew subscriptions, and delete subscriptions. Then
while the subscription is valid and when changes occur in the subscribed resource,
Microsoft Graph sends change notifications to the specified notification endpoint.
You manage the subscription using the subscription resource type and its related
methods. While the subscription is valid and changes occur in the subscribed resource,
Microsoft Graph sends a change notification in a structure defined in the
changeNotificationCollection resource type.
For more information about managing subscriptions for the different delivery channels
using Microsoft Graph, see the following articles.
Code samples
The following code samples are available on GitHub.
Microsoft Graph Training Module - Using Change Notifications and Track Changes
with Microsoft Graph
Microsoft Graph Webhooks Sample for Node.js
Microsoft Graph Webhooks Sample for ASP.NET Core
Microsoft Graph Webhooks Sample for Java Spring
Latency
The following table lists the latency to expect between an event happening in the
service and the delivery of the change notification.
Deployment resources
Get change notifications through webhooks
Get change notifications through Azure Event Hubs
Get change notifications through Azure Event Grid
Rich notifications (notifications with resource data)
Lifecycle notifications
Tutorials
Change notifications for cloud printing
Change notifications for Outlook resources
Change notifications for Microsoft Teams resources
See also
Training: Use change notifications and track changes with Microsoft Graph
Receive change notifications through
webhooks
Article • 03/24/2023
A webhook is a HTTP-based user-defined callback API that you can set up in your
infrastructure to receive change notifications and events from a service, such as
Microsoft Graph. You must configure the webhook using a well-known and accessible
HTTPS-secured endpoint.
The article guides you through the process of managing your Microsoft Graph
subscription and how to receive change notifications through webhooks.
Create a subscription
Before you can receive Microsoft Graph change notifications, you must first create a
subscription. The process to set up a valid subscription involves both the client app and
Microsoft Graph as follows:
3. When the client receives the notification URL validation request, the client
responds with the validation token in plain text as explained later in this article.
4. Microsoft Graph validates the client's validation token response and if the
validation token is valid, responds with a subscription ID.
Subscription request
The client app sends a POST request to the /subscriptions endpoint. The following
example shows a basic request to subscribe to changes to a specific mail folder on
behalf of the signed-in user. For more information about other Microsoft Graph
resources that support change notifications, see supported resources.
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/notificationClient",
"lifecycleNotificationUrl":
"https://webhook.azurewebsites.net/api/lifecycleNotifications",
"resource": "/me/mailfolders('inbox')/messages",
"expirationDateTime": "2016-03-20T11:00:00.0000000Z",
"clientState": "SecretClientState"
}
The clientState property is required. Setting this property allows your service to confirm
that change notifications you receive originate from Microsoft Graph. For this reason,
the value of the property should remain secret and known only to your application and
the Microsoft Graph service.
If successful, Microsoft Graph returns a 201 Created code and a subscription object in
the body.
Each subscription has a unique subscriptionId, even if you have multiple subscriptions
that monitor the same resource and use the same notification URL.
7 Note
notificationUrl validation
When you create a subscription to receive change notifications through webhooks,
Microsoft Graph first validates the notification endpoint that's provided in the
notificationUrl property of the subscription request. The validation process occurs as
follows:
HTTP
2. The client must properly decode the URL to get the plain text validation token
from Microsoft Graph.
Escaping any HTML or JavaScript is a good practice because malicious actors can
use the notification endpoint for cross-site scripting type of attacks. Microsoft
Graph never sends any value containing HTML or JavaScript code.
In general, treat the validation token value as opaque, as the token format can
change without notice.
3. The client must respond with the following characteristics within 10 seconds of
step 1:
) Important
The validation token must be returned in plain text. If the client returns an
encoded validation token, the validation fails.
4. If the endpoint validation fails, Microsoft Graph doesn't create the subscription.
Additionally, you can use the Microsoft Graph Postman collection to confirm that your
endpoint properly implements the validation request. The notificationUrl validation
request in the Misc folder provides unit tests that validate the response provided by
your endpoint.
Receive notifications
While the subscription is valid and there are changes to the resource that you
subscribed to, Microsoft Graph sends a POST request to the notificationUrl with details
of the changes. This payload is the change notification.
For most subscriptions, Microsoft Graph doesn't delay sending notifications but delivers
all notifications within the SLA unless the service is experiencing an incident.
A change notification payload sent to your app can contain a collection of change
notifications relating to your subscriptions.
When many changes occur, Microsoft Graph may send multiple notifications that
correspond to different subscriptions in the same POST request.
JSON
{
"value": [
{
"id": "lsgTZMr9KwAAA",
"subscriptionId":"{subscription_guid}",
"subscriptionExpirationDateTime":"2016-03-19T22:11:09.952Z",
"clientState":"secretClientValue",
"changeType":"created",
"resource":"users/{user_guid}@{tenant_guid}/messages/{long_id_string}",
"tenantId": "84bd8158-6d4d-4958-8b9f-9d6445542f95",
"resourceData":
{
"@odata.type":"#Microsoft.Graph.Message",
"@odata.id":"Users/{user_guid}@{tenant_guid}/Messages/{long_id_string}",
"@odata.etag":"W/\"CQAAABYAAADkrWGo7bouTKlsgTZMr9KwAAAUWRHf\"",
"id":"{long_id_string}"
}
}
]
}
1. After receiving the change notification, send a 2xx class code back to Microsoft
Graph. If Microsoft Graph doesn't receive a 2xx class code within 3 seconds, it tries
to resend the change notification multiple times, for up to 4 hours. If Microsoft
Graph still doesn't receive a 2xx code within the period, it discards the change
notification. If the client app consistently doesn't respond within 3 seconds, the
notifications might be subject to throttling.
If your service can take more than 3 seconds to process the change notification, it
should persist the notification, return a 202 - Accepted status code in the response
to Microsoft Graph, then process the notifications at its capacity. If the notification
isn't persisted, return a 5xx class code to indicate an error so that Microsoft Graph
can retry the notification.
If your service is expected to take less than 3 seconds, it should process the
notifications and return a 200 - OK status code to Microsoft Graph. If the
notification isn't processed correctly, return a 5xx class code to indicate an error so
that Microsoft Graph can retry the notification.
2. Validate the clientState property. It must match the value originally submitted
with the subscription creation request.
If there's a mismatch, don't consider the change notification as valid. It's possible
that the change notification hasn't originated from Microsoft Graph and may have
been sent by a rogue actor. You should also investigate where the change
notification comes from and take appropriate action.
When you subscribe to lifecycle notifications, Microsoft Graph alerts you when a
subscription is almost expiring and should be renewed. If you don't subscribe to lifecycle
notifications, you can use the subscriptionExpirationDateTime to monitor when your
app should send a subscription renewal request.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/subscriptions/{id}
Content-Type: application/json
{
"expirationDateTime": "2016-03-22T11:00:00.0000000Z"
}
Delete a subscription
If the client app no longer wants change notifications, it can delete the subscription
using its subscriptionId as follows:
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/subscriptions/{id}
If successful, Microsoft Graph returns a 204 No Content code.
Throttling
If a subscription notification URL is slow or fails to respond, and Microsoft Graph doesn't
receive a 2xx class code within 3 seconds, Microsoft Graph tries to resend the change
notification multiple times, for up to 4 hours. In this case Microsoft Graph might throttle
notifications for the notification endpoint that's associated with the subscription.
1. If the publishing time is greater than 2900 ms, the response is considered slow.
2. The change notification service then calculates the percentage of slow responses
after the endpoint receives 100 notifications.
3. If the percentage of slow responses reaches 10%, the endpoint associated with the
notification URL is flagged as a slow endpoint. All notifications for all subscriptions
associated with the endpoint are subjected to throttling.
4. The evaluation continues in real time and the accumulation of responses is flushed
every 10 minutes.
Firewall configuration
You can configure the firewall that protects your notification URL to allow inbound
connections only from Microsoft Graph, reducing further exposure to invalid change
notifications. For a complete list of IP addresses used by Microsoft Graph to deliver
change notifications, see additional endpoints for Microsoft 365.
7 Note
The listed IP addresses that are used to deliver change notifications can be updated
at any time without notice.
Summary
In this article, you learned how to receive change notifications through webhooks.
See also
Training module: Use change notifications and track changes with Microsoft Graph
subscription resource type
changeNotificationCollection resource type
Lifecycle notifications
Receive change notifications through
Azure Event Hubs
Article • 03/30/2023
Webhooks may not be suitable for receiving change notifications in high throughput
scenarios or when the receiver cannot expose a publicly available notification URL. As an
alternative, you can use Azure Event Hubs.
The article guides you through the process of managing your Microsoft Graph
subscription and how to receive change notifications through Azure Event Hubs.
You don't rely on publicly exposed notification URLs. The Event Hubs SDK will relay
the notifications to your application.
You don't need to reply to the notification URL validation. You can ignore the
validation message that you receive.
You'll need to provision an Azure Event Hub.
You'll need to provision an Azure Key Vault.
Azure CLI
# --------------
# TODO: update the following values
#sets the name of the resource group
resourcegroup=rg-graphevents-dev
#sets the location of the resources
location='uk south'
#sets the name of the Azure Event Hubs namespace
evhamespacename=evh-graphevents-dev
#sets the name of the hub under the namespace
evhhubname=graphevents
#sets the name of the access policy to the hub
evhpolicyname=grapheventspolicy
#sets the name of the Azure KeyVault
keyvaultname=kv-graphevents
#sets the name of the secret in Azure KeyVault that will contain the
connection string to the hub
keyvaultsecretname=grapheventsconnectionstring
# --------------
az group create --location $location --name $resourcegroup
az eventhubs namespace create --name $evhamespacename --resource-group
$resourcegroup --sku Basic --location $location
az eventhubs eventhub create --name $evhhubname --namespace-name
$evhamespacename --resource-group $resourcegroup --partition-count 2 --
message-retention 1
az eventhubs eventhub authorization-rule create --name $evhpolicyname --
eventhub-name $evhhubname --namespace-name $evhamespacename --resource-
group $resourcegroup --rights Send
evhprimaryconnectionstring=`az eventhubs eventhub authorization-rule
keys list --name $evhpolicyname --eventhub-name $evhhubname --namespace-
name $evhamespacename --resource-group $resourcegroup --query
"primaryConnectionString" --output tsv`
az keyvault create --name $keyvaultname --resource-group $resourcegroup
--location $location --enable-soft-delete true --sku standard --
retention-days 90
az keyvault secret set --name $keyvaultsecretname --value
$evhprimaryconnectionstring --vault-name $keyvaultname --output none
graphspn=`az ad sp list --display-name 'Microsoft Graph Change Tracking'
--query "[].appId" --output tsv`
az keyvault set-policy --name $keyvaultname --resource-group
$resourcegroup --secret-permissions get --spn $graphspn --output none
keyvaulturi=`az keyvault show --name $keyvaultname --resource-group
$resourcegroup --query "properties.vaultUri" --output tsv`
domainname=`az ad signed-in-user show --query 'userPrincipalName' | cut
-d '@' -f 2 | sed 's/\"//'`
notificationUrl="EventHub:${keyvaulturi}secrets/${keyvaultsecretname}?
tenantId=${domainname}"
echo "Notification Url:\n${notificationUrl}"
Note: The script provided here is compatible with Linux based shells, Windows
WSL, and Azure Cloud Shell. It will require some updates to run in Windows
shells.
The main difference during subscription creation will be the notificationUrl. You must
set it to EventHub:https://<azurekeyvaultname>.vault.azure.net/secrets/<secretname>?
tenantId=<domainname> , with the following values:
azurekeyvaultname - The name you gave to the key vault when you created it. Can
be found in the DNS name.
secretname - The name you gave to the secret when you created it. Can be found
on the Azure Key Vault Secrets page.
domainname - The name of your tenant; for example, consto.onmicrosoft.com or
contoso.com. Because this domain will be used to access the Azure Key Vault, it is
important that it matches the domain used by the Azure subscription that holds
the Azure Key Vault. To get this information, you can go to the overview page of
the Azure Key Vault you created and click the subscription. The domain name is
displayed under the Directory field.
Receiving notifications
Events will be now delivered to your application by Event Hubs. For details, see receiving
events in the Event Hubs documentation.
Before you can receive the notifications in your application, you'll need to create
another shared access policy with a "Listen" permission and obtain the connection
string, similar to the steps listed in Configuring the Azure Event Hub.
Note: Create a separate policy for the application that listens to Event Hubs
messages instead of reusing the same connection string you set in Azure KeyVault.
This ensures that each component of the solution has only the permissions it needs
and follows the least permissions security principle.
JSON
{
"value":[
{
"subscriptionId":"NA",
"subscriptionExpirationDateTime":"NA",
"clientState":"NA",
"changeType":"Validation: Testing client application
reachability for subscription Request-Id: 522a8e7e-096a-494c-aaf1-
ac0dcfca45b7",
"resource":"NA",
"resourceData":{
"@odata.type":"NA",
"@odata.id":"NA",
"id":"NA"
}
}
]
}
HTTP
POST https://graph.microsoft.com/v1.0/servicePrincipals
{
"appId": "0bf30f3b-4a52-48df-9a82-234910c4a086"
}
Note: You can get an access denied running this query. In this case, select the gear
icon next to your account name in the top left corner. Then select Select
Permissions and search for Application.ReadWrite.All. Check the permission and
select Consent. After consenting to this new permission, run the request again.
Note: This API only works with a school or work account, not with a personal
account. Make sure that you are signed in with an account on your domain.
PowerShell
Next steps
See the following Azure Event Hubs quick starts:
.NET Core
Java
Python
JavaScript
Receive Microsoft Graph change
notifications through Azure Event Grid
(preview)
Article • 03/15/2023
This article describes steps to subscribe to events published by Microsoft Graph API. The
following table lists the resources for which events are available through Graph API. For
every resource, events for create, update and delete state changes are supported.
) Important
Microsoft Graph API's ability to send events to Azure Event Grid is currently in
private preview. If you have questions or need support, please email us mailto:ask-
[email protected]?subject=Support Request.
) Important
If you aren't familiar with the Partner Events feature, see Partner Events overview.
You're developing an event-driven solution that requires events from Azure Active
Directory, Outlook, Teams, etc. to react to resource changes. You require the robust
eventing model and publish-subscribe capabilities that Event Grid provides. For an
overview of Event Grid, see Event Grid concepts.
You want to use Event Grid to route events to multiple destinations using a single
Graph API subscription and you want to avoid managing multiple Graph API
subscriptions.
You require to route events to different downstream applications, webhooks or
Azure services depending on some of the properties in the event. For example, you
may want to route event types such as Microsoft.Graph.UserCreated and
Microsoft.Graph.UserDeleted to a specialized application that processes users'
High-level steps
1. Register the Event Grid resource provider with your Azure subscription.
2. Authorize partner to create a partner topic in your resource group.
3. Enable events to flow to a partner topic
4. Activate partner topic so that your events start flowing to your partner topic.
5. Subscribe to events.
2. Select the subscription you want to use for Event Grid from the subscription list.
3. On the Subscription page, select Resource providers under Settings on the left
menu.
) Important
For a greater security stance, specify the minimum expiration time that offers the
partner enough time to configure your events to flow to Event Grid and to
provision your partner topic. Your partner won't be able to create resources
(partner topics) in your Azure subscription after the authorization expiration time.
7 Note
Event Grid started enforcing authorization checks to create partner topics around
June 30th, 2022.
2. In the search bar at the top, enter Partner Configurations, and select Event Grid
Partner Configurations under Services in the results.
3. On the Event Grid Partner Configurations page, select Create Event Grid partner
configuration button on the page (or) select + Create on the command bar.
5. On the Add partner authorization to create resources page, you see a list of
verified partners. A verified partner is a partner whose identity has been validated
by Microsoft. Follow these steps to authorize Auth0 to create a partner topic.
a. Select the verified partner (Auth0, SAP, Tribal Group, or Microsoft Graph API)
from the list of verified partners.
) Important
6. Back on the Create Partner Configuration page, verify that the partner is added to
the partner authorization list at the bottom.
8. On the Review page, review all settings, and then select Create to create the
partner registration.
Enable Graph API events to flow to your
partner topic
You request Microsoft Graph API to send events by creating a Graph API subscription.
When you create a Graph API subscription, the http request should look like the
following sample:
JSON
POST to https://graph.microsoft.com/beta/subscriptions
x-ms-enable-features: EventGrid
Body:
{
"changeType": "Updated,Deleted,Created",
"notificationUrl": "EventGrid:?azuresubscriptionid=8A8A8A8A-4B4B-4C4C-
4D4D-
12E12E12E12E&resourcegroup=yourResourceGroup&partnertopic=youPartnerTopic&lo
cation=theNameOfAzureRegionFortheTopic",
"resource": "users",
"expirationDateTime": "2022-04-30T00:00:00Z",
"clientState": "mysecret"
}
preview capability to send events to Azure Event Grid. Its value must be EventGrid .
This header must be included with the request when creating a Microsoft Graph
API subscription.
changeType : the kind of resource changes for which you want to receive events.
Valid values: Updated , Deleted , and Created . You can specify one or more of these
values separated by commas.
notificationUrl : a URI that conforms to the following pattern: EventGrid:?
azuresubscriptionid=<you-azure-subscription-id>&resourcegroup=<your-resource-
group-name>&partnertopic=<the-name-for-your-partner-topic>&location=<the-
Azure CLI
az account list-locations
7 Note
Microsoft Graph API's capability to send events to Event Grid is only available in a
specific Graph API environment. You will need to update your code so that it uses
the following Graph API endpoint https://graph.microsoft.com/beta . For example,
this is the way you can set the endpoint on your graph client
( com.microsoft.graph.requests.GraphServiceClient ) using the Graph API Java SDK:
Java
graphClient.setServiceRoot("https://graph.microsoft.com/beta");
You can create a Microsoft Graph API subscription by following the instructions in the
Microsoft Graph API webhook samples that include code samples for NodeJS , Java
(Spring Boot) , and .NET Core . There are no samples available for Python, Go and
other languages yet, but the Graph SDK supports creating Graph API subscriptions using
those programming languages.
7 Note
Partner topic names must be unique within the same Azure region. Each
tenant-application ID combination can create up to 10 unique partner topics.
Be mindful of certain Graph API resources' service limits when developing
your solution.
For quick tests and to get to know the API, you could use the Graph Explorer. For
anything else beyond casuals tests or learning, you should use the Microsoft Graph
SDKs.
2. On the Event Grid Partner Topics page, select the partner topic in the list.
3. Review the activate message, and select Activate on the page or on the command
bar to activate the partner topic before the expiration time mentioned on the
page.
4. Confirm that the activation status is set to Activated and then create event
subscriptions for the partner topic by selecting + Event Subscription on the
command bar.
Subscribe to events
First, create an event handler that will handle events from the partner. For example,
create an event hub, Service Bus queue or topic, or an Azure function. Then, create an
event subscription for the partner topic using the event handler you created.
1. In the Azure portal, type Event Grid Partner Topics in the search box, and select
Event Grid Partner Topics.
2. On the Event Grid Partner Topics page, select the partner topic in the list.
3. On the Event Grid Partner Topic page for the partner topic, select + Event
Subscription on the command bar.
b. For Filter to Event Types, select types of events that your subscription will
receive.
c. For Endpoint Type, select an Azure service (Azure Function, Storage Queues,
Event Hubs, Service Bus Queue, Service Bus Topic, Hybrid Connections. etc.), or
webhook.
d. Click the Select an endpoint link. In this example, let's use Azure Event Hubs
destination or endpoint.
e. On the Select Event Hub page, select configurations for the endpoint, and then
select Confirm Selection.
reauthorizationRequired notifications
Subscription removed notifications
missed notifications
If you ignore these events, it might break the change notification flow; you can handle
the events by implementing logic in your app to resume a continuous change
notification flow.
This article introduces lifecycle notifications in Microsoft Graph change notifications and
provides guidance for handling the notifications.
The following subscription creation request defines both the notificationUrl and
lifecycleNotificationUrl endpoints.
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"lifecycleNotificationUrl":
"https://webhook.azurewebsites.net/api/lifecycleNotifications",
"resource": "/users/{id}/messages",
"expirationDateTime": "2020-03-20T11:00:00.0000000Z",
"clientState": "<secretClientState>"
}
When using the webhooks delivery channel, you must validate both endpoints.
JSON
{
"value": [
{
"subscriptionId":"<subscription_guid>",
"subscriptionExpirationDateTime":"2019-03-20T11:00:00.0000000Z",
"tenantId": "<tenant_guid>",
"clientState":"<secretClientState>",
"lifecycleEvent": "subscriptionRemoved or missed or
reauthorizationRequired"
}
]
}
Responding to reauthorizationRequired
notifications
reauthorizationRequired lifecycle events alert you when Microsoft Graph requires the
Before any of these conditions become true, Microsoft Graph sends an authorization
challenge to the lifecycleNotificationUrl.
The following code sample illustrates how the Microsoft Graph change notifications
service can calculate the interval of these notifications.
C#
if((TokenTimeToExpirationInMinutes)<=180 &&
TokenTimeToExpirationInMinutes>60){
//Microsoft Graph will send reauthorizationRequired notification
TokenTimeToExpirationInMinutes=TokenTimeToExpirationInMinutes/2;
}
elseif(TokenTimeToExpirationInMinutes<60 &&
TokenTimeToExpirationInMinutes>=0){
//Microsoft Graph will send reauthorizationRequired notification
every 15 mins
TokenTimeToExpirationInMinutes=TokenTimeToExpirationInMinutes-
15;
} else {
//Microsoft Graph will stop sending reauthorizationRequired
notifications
}
The following steps represent the flow of an authorization challenge for an active
subscription:
The reasons may vary from resource to resource and may change over time. To
maintain the subscription, you must respond to a reauthorization event no matter
what caused it.
The flow of change notifications may continue for a while, giving you extra time to
respond. However, eventually change notification delivery pauses, until you take
the required action. Any notifications about resource changes that happen when
the change notification delivery pauses and the time when the app successfully
creates the subscription again would be lost. In such cases, the app should
separately fetch those changes, for example using the delta query.
Actions to take
1. Acknowledge receipt of the lifecycle notification by responding to the POST call
with 202 - Accepted response code.
3. Ensure that the app has a valid access token to take the next step.
4. Call either of the following two APIs. If the API call succeeds, the change
notification flow resumes.
HTTP
POST
https://graph.microsoft.com/beta/subscriptions/{id}/reauthorize
Perform a regular "renew" action to reauthorize and renew the subscription at
the same time.
HTTP
PATCH https://graph.microsoft.com/beta/subscriptions/{id}
Content-Type: application/json
{
"expirationDateTime": "2019-09-21T11:00:00.0000000Z"
}
You may retry these actions later, at any time, and succeed if the conditions
of access change.
Additional information
Authorization challenges don't replace the need to renew a subscription before it
expires.
While you can choose to renew a subscription when you receive an authorization
challenge, Microsoft Graph may not challenge all of your subscriptions. For
example, a subscription that doesn't have any activity and has no change
notifications pending delivery may not signal any reauthorization challenges to
your app. Make sure to renew subscriptions before they expire.
Responding to subscriptionRemoved
notifications
subscriptionRemoved lifecycle events alert you when Microsoft Graph has removed a
subscription. In such cases, if you want to continue receiving change notifications for the
related resource, you need to recreate the subscription.
Even if you have a long-lived subscription, the conditions of access to the resource data
might change over time. For example, an event in the service might occur that requires
the app to reauthenticate the user. In such a case, Microsoft Graph sends you a
subscriptionRemoved notification.
1. The service detects that a subscription needs to be removed from Microsoft Graph.
There's no set cadence for these events. They might occur frequently for some
resources, and almost never for others.
subscription successfully. The app needs to fetch those changes on its own.
Actions to take
1. Acknowledge receipt of the lifecycle notification by responding to the POST call
with 202 - Accepted response code.
3. Ensure that the app has a valid access token to take the next step.
This action might fail, because the authorization checks performed by the system
might deny the app access to the resource. It might be necessary for the app to
obtain a new access token to successfully reauthorize a subscription. You can retry
these actions later, at any time; for example, when the conditions of access have
changed.
5. After creating the new subscription, you can sync the resource data to identify any
missed change notifications; for example using the delta query.
Actions to take
1. Acknowledge receipt of the lifecycle notification by responding to the POST call
with 202 - Accepted response code.
2. Validate the authenticity of the lifecycle notification.
3. Perform a full data resync of the resource to identify the changes that weren't
delivered as notifications; for example, using the delta query.
See also
Subscription resource type
Set up change notifications that include
resource data
Article • 03/24/2023
Microsoft Graph allows apps to subscribe to change notifications for resources via
webhooks. You can set up subscriptions to include the changed resource data (such as
the content of a Microsoft Teams chat message or Microsoft Teams presence
information) in change notifications. Your app can then run its business logic without
having to make a separate API call to fetch the changed resource. As a result, the app
performs better by making fewer API calls, which is beneficial in large scale scenarios.
Including resource data as part of change notifications requires you to implement the
following additional logic to satisfy data access and security requirements:
Supported resources
The Microsoft Teams chatMessage, onlineMeetings, and presence resources support
change notifications with resource data. Outlook contact, event, and message resources
have similar support in preview. Specifically, you can set up a subscription for the
following use cases.
New or changed messages in all Teams chats a particular user is part of:
/users/{id}/chats/getAllMessages
Change notifications for contact, event, or message resources include only a subset of
properties for the resource, which must be specified in the corresponding subscription
request using a $select query parameter. For more information and an example for
subscribing to change notifications with resource data for the message resource, see
Change notifications for Outlook resources in Microsoft Graph.
The rest of this article walks through an example to subscribe to change notifications for
chatMessage resources in a Teams channel, with each change notification including the
full resource data of the changed chatMessage instance. For more details about
chatMessage subscriptions, see Get change notifications for chat and channel
messages.
Creating a subscription
To have resource data included in change notifications, you must specify the following
properties, in addition to those that are usually specified when creating a subscription:
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{id}/channels/{id}/messages",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Subscription response
HTTP
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{id}/channels/{id}/messages",
"includeResourceData": true,
"encryptionCertificateId": "{custom ID}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secret client state}"
}
Subscription lifecycle notifications
Certain events can interfere with change notification flow in an existing subscription.
Subscription lifecycle notifications inform you actions to take in order to maintain an
uninterrupted flow. Unlike a resource change notification which informs a change to a
resource instance, a lifecycle notification is about the subscription itself, and its current
state in the lifecycle.
For more information about how to receive and respond to lifecycle notifications, see
Reduce missing subscriptions and change notifications)
For basic change notifications that do not contain resource data, simply validate them
based on the clientState value as described in Processing the change notification. This is
acceptable, as you can make subsequent trusted Microsoft Graph calls to get access to
resource data, and therefore the impact of any spoofing attempts is limited.
For change notifications that deliver resource data, perform a more thorough validation
before processing the data.
In this section:
In the following example, the change notification contains two items for the same app,
and for two different tenants, therefore the validationTokens array contains two tokens
that need to be validated.
JSON
{
"value": [
{
"subscriptionId": "76619225-ff6b-4489-96ca-4ef547e78b22",
"tenantId": "84bd8158-6d4d-4958-8b9f-9d6445542f95",
"changeType": "created",
...
},
{
"subscriptionId": "e990d58f-fd93-40af-acf7-a7c907c5d8ea",
"tenantId": "46d9e3bd-6309-4177-a016-b256a411e30f",
"changeType": "created",
...
}
],
"validationTokens": [
"eyJ0eXAiOiJKV1QiLCJhb...",
"cGlkYWNyIjoiMiIsImlkc..."
]
}
Note: for a full description of the data sent when change notifications are delivered,
see changeNotificationCollection.
How to validate
If you're new to token validation, see Principles of Token Validation for an overview.
Use an SDK, such as the System.IdentityModel.Tokens.Jwt library for .NET, or a third-
party library for a different platform.
Make sure to always send an HTTP 202 Accepted status code as part of the
response to the change notification.
Respond before validating the change notification (for example, if you store
change notifications in queues for later processing) or after (if you process them
on the fly), even if validation failed.
Accepting a change notification prevents unnecessary delivery retries and it also
prevents any potential rogue actors from finding out if they passed or failed
validation. You can always choose to ignore an invalid change notification after you
have accepted it.
Use the following steps to validate tokens and apps that generate tokens:
2. Validate the token has not been tampered with and was issued by the expected
authority, Microsoft identity platform:
3. Validate that the token was issued for your app that is subscribing to change
notifications.
The following steps are part of standard validation logic in JWT token libraries and
can typically be executed as a single function call.
4. Critical: Validate that the app that generated the token represents the Microsoft
Graph change notification publisher.
Check that the appid property in the token matches the expected value of
0bf30f3b-4a52-48df-9a82-234910c4a086 .
This ensures that change notifications are not sent by a different app that is
not Microsoft Graph.
JSON
{
// aud is your app's id
"aud": "8e460676-ae3f-4b1e-8790-ee0fb5d6148f",
"iss": "https://sts.windows.net/84bd8158-6d4d-4958-8b9f-9d6445542f95/",
"iat": 1565046813,
"nbf": 1565046813,
// Expiration date
"exp": 1565075913,
"aio": "42FgYKhZ+uOZrHa7p+7tfruauq1HAA==",
// appid represents the notification publisher and must always be the same
value of 0bf30f3b-4a52-48df-9a82-234910c4a086
"appid": "0bf30f3b-4a52-48df-9a82-234910c4a086",
"appidacr": "2",
"idp": "https://sts.windows.net/84bd8158-6d4d-4958-8b9f-9d6445542f95/",
"tid": "84bd8158-6d4d-4958-8b9f-9d6445542f95",
"uti": "-KoJHevhgEGnN4kwuixpAA",
"ver": "1.0"
}
Java
JavaScript
For the Java sample to work, you will also need to implement the JwkKeyResolver .
Java
package com.example.restservice;
import com.auth0.jwk.JwkProvider;
import com.auth0.jwk.UrlJwkProvider;
import com.auth0.jwk.Jwk;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.SigningKeyResolverAdapter;
import java.security.Key;
import java.net.URI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
In this section:
You can self-sign the certificate, since Microsoft Graph does not verify the
certificate issuer, and uses the public key for only encryption.
Use Azure Key Vault as the solution to create, rotate, and securely manage
certificates. Make sure the keys satisfy the following criteria:
The key must be of type RSA
The key size must be between 2048 and 4096 bits
2. Export the certificate in base64-encoded X.509 format, and include only the public
key.
4. Manage the private key securely, so that your change notification processing code
can access the private key to decrypt resource data.
Rotating keys
To minimize the risk of a private key becoming compromised, periodically change your
asymmetric keys. Follow these steps to introduce a new pair of keys:
1. Obtain a new certificate with a new pair of asymmetric keys. Use it for all new
subscriptions being created.
For a period of time, the old certificate may still be used for encryption. Your
app must have access to both old and new certificates to be able to decrypt
content.
Use the encryptionCertificateId property in each change notification to
identify the correct key to use.
Discard of the old certificate only when you have seen no recent change
notifications referencing it.
It generates a single use symmetric key, and uses it to encrypt resource data.
It uses the public asymmetric key (that you provided when subscribing) to encrypt
the symmetric key and includes it in each change notification of that subscription.
Always assume that the symmetric key is different for each item in the change
notification.
To decrypt resource data, your app should perform the reverse steps, using the
properties under encryptedContent in each change notification:
3. Decrypt the symmetric key delivered in the dataKey property of each item in the
change notification.
Use Optimal Asymmetric Encryption Padding (OAEP) for the decryption algorithm.
4. Use the symmetric key to calculate the HMAC-SHA256 signature of the value in
data.
5. Use the symmetric key with an Advanced Encryption Standard (AES) (such as the
.NET AesCryptoServiceProvider) to decrypt the content in data.
Set the "initialization vector" by copying the first 16 bytes of the symmetric
key used for decryption.
6. The decrypted value is a JSON string that represents the resource instance in the
change notification.
JSON
{
"value": [
{
"subscriptionId": "76222963-cc7b-42d2-882d-8aaa69cb2ba3",
"changeType": "created",
// Other properties typical in a resource change notification
"resource": "teams('d29828b8-c04d-4e2a-b2f6-
07da6982f0f0')/channels('19:[email protected]')/
messages('1565045424600')/replies('1565047490246')",
"resourceData": {
"id": "1565293727947",
"@odata.type": "#Microsoft.Graph.ChatMessage",
"@odata.id": "teams('88cbc8fc-164b-44f0-b6a6-
b59b4a1559d3')/channels('19:[email protected]')/
messages('1565293727947')/replies('1565293727947')"
},
"encryptedContent": {
"data": "{encrypted data that produces a full resource}",
"dataSignature": "<HMAC-SHA256 hash>",
"dataKey": "{encrypted symmetric key from Microsoft Graph}",
"encryptionCertificateId": "MySelfSignedCert/DDC9651A-D7BC-
4D74-86BC-A8923584B0AB",
"encryptionCertificateThumbprint":
"07293748CC064953A3052FB978C735FB89E61C3D"
}
}
],
"validationTokens": [
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSU..."
]
}
Note: for a full description of the data sent when change notifications are delivered,
see changeNotificationCollection.
This section contains some useful code snippets that use C# and .NET for each stage of
decryption.
C#
Java
String storename = ""; //name/path of the jks store
String storepass = ""; //password used to open the jks store
String alias = ""; //alias of the certificate when store in the jks store,
should be passed as encryptionCertificateId when subscribing and retrieved
from the notification
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(storename), storepass.toCharArray());
Key asymmetricKey = ks.getKey(alias, storepass.toCharArray());
byte[] encryptedSymetricKey = Base64.decodeBase64("<value from dataKey
property>");
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, asymmetricKey);
byte[] decryptedSymmetricKey = cipher.doFinal(encryptedSymetricKey);
// Can now use decryptedSymmetricKey with the AES algorithm.
JavaScript
C#
Java
byte[] decryptedSymmetricKey = "<the aes key decrypted in the previous
step>";
byte[] decodedEncryptedData = Base64.decodeBase64("data property from
encryptedContent object");
Mac mac = Mac.getInstance("HMACSHA256");
SecretKey skey = new SecretKeySpec(decryptedSymmetricKey, "HMACSHA256");
mac.init(skey);
byte[] hashedData = mac.doFinal(decodedEncryptedData);
String encodedHashedData = new String(Base64.encodeBase64(hashedData));
if (comparisonSignature.equals(encodedHashedData))
{
// Continue with decryption of the encryptedPayload.
}
else
{
// Do not attempt to decrypt encryptedPayload. Assume notification
payload has been tampered with and investigate.
}
JavaScript
C#
string decryptedResourceData;
// Decrypt the resource data content.
using (var decryptor = aesProvider.CreateDecryptor())
{
using (MemoryStream msDecrypt = new MemoryStream(encryptedPayload))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor,
CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
decryptedResourceData = srDecrypt.ReadToEnd();
}
}
}
}
Java
JavaScript
See also
Set up notifications for changes in user data
Subscription resource type
Get subscription
Create subscription
Update subscription
Change notifications for Outlook resources in Microsoft Graph
Change notifications for online meetings in Microsoft Graph
Meeting notification C# sample
Meeting notification Node.js sample
Subscribe to change notifications from
cloud printing APIs using Microsoft
Graph
Article • 03/24/2023
Universal Print helps customers move their print infrastructure to the cloud, and is part
of a robust ecosystem of partner solutions that offer advanced print functionality. These
solutions can become even more powerful when you use the cloud printing APIs in
Microsoft Graph to integrate with Universal Print.
Many partner solutions need to process print jobs in real time as they're sent from users'
devices to printers, which means they need to be notified when print jobs are available
for processing. Universal Print provides hooks for print vendor solutions to be notified
as jobs move through the cloud, and APIs that enable management of printers and print
jobs.
This article describes how to subscribe to notifications for various print job events.
JobFetchable: After the job has started, third-party print applications or Universal
Print might do some processing (like converting XPS payload to PDF for a PDF
printer). After processing is complete and the payload is ready to be downloaded
by a printer, a JobFetchable event is raised for the corresponding print job.
7 Note
Permission scopes
To subscribe to notifications for print jobs, applications must have the following
permission scopes approved in the customer’s Azure AD tenant:
Applications must generate and use the Azure AD security token in the Microsoft Graph
API request header. The security token contains the claims as per the scopes approved
for the customer’s Azure AD tenant by its administrator.
A printTaskTrigger for each of the printer queues for which the partner wants to
receive a notification when a new print job starts. The printTaskTrigger needs to be
bound to the printTaskDefinition.
7 Note
One printer can be associated with only one printTaskTrigger and one
printTaskTrigger can be associated with only one printTaskDefinition. However,
one printTaskDefinition can have one or more printTaskTriggers associated with it.
With the printTaskDefinition that exists for customer’s Azure AD tenant, the application
can create a subscription for a printTask triggered (JobStarted) event using the
printTaskDefinition. While creating the subscription:
Request
The following is an example of the request.
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType":"created",
"resource":"print/taskDefinitions/{printTaskDefinition ID}/tasks",
"clientState":"secret",
"notificationUrl":"{URL for receiving the event – e.g.
https://webhookappexample.azurewebsites.net/api/notifications}",
"expirationDateTime":"2020-01-30T22:42:09Z"
}
Response
The following example shows the response.
HTTP
7 Note
Print jobs can't be modified when they enter the JobFetchable state. A
JobFetchable notification needs to be created for each printer queue. While
creating the subscription:
The expirationDateTime field needs to be less than the maximum expiration time.
For more details, see Subscription resource type properties.
Request
The following is an example of the request.
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType":"updated",
"resource":"print/printers/{printer id}/jobs",
"notificationQueryOptions": "$filter = isFetchable eq true",
"notificationUrl":"{URL for receiving the event – e.g.
https://webhookappexample.azurewebsites.net/api/notifications}",
"expirationDateTime":"2020-12-30T22:42:09Z",
"clientState":"mysecret"
}
Response
The following example shows the response.
HTTP
FAQs
See also
To learn more about the cloud printing API in Microsoft Graph, see Universal Print
cloud printing API overview.
For suggestions or feedback about the cloud printing API in Microsoft Graph, visit
the Universal Print tech community .
Change notifications for Microsoft
Teams resources
Article • 10/04/2022
Change notifications for Microsoft Teams resources using Microsoft Graph enable you to
subscribe to changes (create, update, and delete) to a resource. Change notifications
provide a low latency model by allowing you to maintain a subscription. You can also
get the resource data in the notifications and therefore avoid calling the API to get the
payload.
7 Note
Change notification to track all changes related to a resource across the tenant:
For example, you can subscribe to changes in messages in any channel across the
tenant and get notified whenever a message is created, updated, or deleted in any
channel in the tenant. These notifications may have licensing and payment
requirements, such as change notifications for messages and membership.
Change notification to track all changes for a specific resource: For example, you
can subscribe to changes in messages in a particular channel and get notified
whenever a message is created, updated, or deleted in that channel.
For details about which resources support which types of change notifications, see
Microsoft Graph change notifications.
Supported resources
The following table lists the Microsoft Teams resources that support change notifications
and their corresponding resource paths. Apply the resource path for your scenario as
specified when creating a subscription. The type of the resource path payload is the type
under the "Resource" column, or a collection of that type.
Resource Supported resource paths Resource
data can be
included in
notifications
Teams chatMessage Changes to chat messages in all channels in all teams: Yes
/teams/getAllMessages
Changes to chat messages in a specific channel:
/teams/{id}/channels/{id}/messages
Changes to chat messages in all chats:
/chats/getAllMessages
Changes to chat messages in a specific chat:
/chats/{id}/messages
Changes to chat messages in all chats a particular user is part
of:
/users/{id}/chats/getAllMessages
Changes to chat messages in all the chats in the tenant where
a particular Teams app is installed:
/appCatalogs/teamsApps/{id}/installedToChats/getAllMessages
Notification payloads
Depending on your subscription, you can either get the notification with resource data,
or without resource data. Subscribing with resource data allows you to get the message
payload along with the notification, which removes the need to call back and get the
content.
JSON
{
"value": [{
"subscriptionId": "10493aa0-4d29-4df5-bc0c-ef742cc6cd7f",
"changeType": "created",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-02-02T10:30:34.9097561-
08:00",
"resource": "chats('19:8ea0e38b-efb3-4757-924a-
5f94061cf8c2_97f62344-57dc-409c-88ad-
[email protected]')/messages('1612289765949')",
"resourceData": {
"id": "1612289765949",
"@odata.type": "#Microsoft.Graph.chatMessage",
"@odata.id": "chats('19:8ea0e38b-efb3-4757-924a-
5f94061cf8c2_97f62344-57dc-409c-88ad-
[email protected]')/messages('1612289765949')"
},
"encryptedContent": {
"data": "<<--EncryptedContent-->",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}],
"validationTokens": ["<<--ValidationTokens-->>"]
}
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
The decrypted notification payload looks like the following. The decrypted payload for
the previous example conforms to the chatMessage schema. The payload is similar to
that returned by GET operations.
JSON
{
"id": "1612289992105",
"replyToId": null,
"etag": "1612289992105",
"messageType": "message",
"createdDateTime": "2021-02-02T18:19:52Z",
"lastModifiedDateTime": "2021-02-02T18:19:52.105Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:8ea0e38b-efb3-4757-924a-5f94061cf8c2_97f62344-57dc-409c-
[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"from": {
"application": null,
"device": null,
"user": {
"id": "8ea0e38b-efb3-4757-924a-5f94061cf8c2",
"displayName": "Ramjot Singh",
"userIdentityType": "aadUser"
},
"conversation": null
},
"body": {
"contentType": "text",
"content": "test"
},
"channelIdentity": null,
"attachments": [],
"mentions": [],
"policyViolation": null,
"reactions": [],
"replies": [],
"hostedContents": []
}
The payload looks like the following. This payload is for a message sent in a channel.
JSON
{
"subscriptionId": "9f9d1ed0-c9cc-42e7-8d80-a7fc4b0cda3c",
"changeType": "created",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-02-02T11:26:41.0537895-08:00",
"resource": "teams('fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b')/channels('19:[email protected]')/
messages('1612293113399')",
"resourceData": {
"id": "1612293113399",
"@odata.type": "#Microsoft.Graph.chatMessage",
"@odata.id": "teams('fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b')/channels('19:[email protected]')/
messages('1612293113399')"
}
}
7 Note
GET calls always return the current state of the resource. If the resource is changed
between when the notification is sent and when the resource is retrieved, the
operation returns the updated resource.
See also
Microsoft Graph change notifications
Get change notifications for teams and channels using Microsoft Graph
Get change notifications for membership changes in teams and channels using
Microsoft Graph
Get change notifications for messages in Teams channels and chats using
Microsoft Graph
Get change notifications for chats using Microsoft Graph
Get change notifications for chat membership using Microsoft Graph
Microsoft Teams API overview
Get change notifications for teams and
channels using Microsoft Graph
Article • 06/02/2023
Change notifications enable you to subscribe to changes (create, update, and delete) to
teams and channels. You can get notified whenever a team or channel is created,
updated, or deleted. You can also get the resource data in the notifications and
therefore avoid calling the API to get the payload.
Continue with this article about scenarios for the team or channel resource. Or, find out
about change notifications for other Microsoft Teams resources.
Permissions
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,deleted,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Permissions
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "deleted,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{team-id}",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Continue with this article about scenarios for the channel or chat context. Or, find out
about change notifications for other Microsoft Teams resources.
Permissions
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,deleted,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/getAllChannels",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Subscribe to changes in any channel of a
particular team
To get change notifications for all changes related to any channel in a particular team,
subscribe to /teams/{team-id}/channels . This resource supports including resource data
in the notification.
Note: Change notifications for private and shared channels in delegated context are
only supported in beta. This is not currently available in v1.0. When you call the v1.0
endpoint, a subscriber to this resource in delegated context will receive notifications
only for standard channels under a particular team, not for private and shared
channels.
Permissions
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,deleted,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{team-id}/channels",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
JSON
{
"value": [{
"subscriptionId": "10493aa0-4d29-4df5-bc0c-ef742cc6cd7f",
"changeType": "created",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-02-02T10:30:34.9097561-
08:00",
"resource": "teams('fb82c19a-0f6d-41ed-90f0-cbb29a476ede')",
"resourceData": {
"id": "1612289765949",
"@odata.type": "#Microsoft.Graph.Team",
"@odata.id": "teams('fb82c19a-0f6d-41ed-90f0-cbb29a476ede')"
},
"encryptedContent": {
"data": "<<--EncryptedContent-->",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}],
"validationTokens": ["<<--ValidationTokens-->>"]
}
The decrypted notification payload looks like the following. The payload conforms to
the teams schema. The payload is similar to that returned by GET operations.
JSON
{
"id": "4c533ad3-e1dd-4277-a672-92ab64ed225c",
"createdDateTime": "2021-03-18T10:31:14.597Z",
"displayName": "Sample name",
"description": "Sample description",
"internalId": "19:[email protected]",
"specialization": "none",
"visibility": "public",
"webUrl":
"https://teams.microsoft.com/l/team/19:2077546f724a42c1ba71236f4df79aa2%40th
read.tacv2/conversations?groupId=4c533ad3-e1dd-4277-a672-
92ab64ed225c&tenantId=0f2e8f59-862a-483b-9ca8-82a10665e17d",
"isArchived": false,
"isMembershipLimitedToOwners": false,
"memberSettings": {
"allowCreateUpdateChannels": true,
"allowCreatePrivateChannels": true,
"allowDeleteChannels": true,
"allowAddRemoveApps": true,
"allowCreateUpdateRemoveTabs": true,
"allowCreateUpdateRemoveConnectors": true
},
"guestSettings": {
"allowCreateUpdateChannels": false,
"allowDeleteChannels": false
},
"messagingSettings": {
"allowUserEditMessages": true,
"allowUserDeleteMessages": true,
"allowOwnerDeleteMessages": true,
"allowTeamMentions": true,
"allowChannelMentions": true
},
"funSettings": {
"allowGiphy": true,
"giphyContentRating": "moderate",
"allowStickersAndMemes": true,
"allowCustomMemes": true
}
}
For notifications with resource data, the payload looks like the following. This payload is
for a property change in a channel.
JSON
{
"value": [{
"subscriptionId": "10493aa0-4d29-4df5-bc0c-ef742cc6cd7f",
"changeType": "created",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-02-02T10:30:34.9097561-
08:00",
"resource": "teams('fb82c19a-0f6d-41ed-90f0-
cbb29a476ede')/channels('19:[email protected]')"
,
"resourceData": {
"id": "19:[email protected]",
"@odata.type": "#Microsoft.Graph.Channel",
"@odata.id": "teams('fb82c19a-0f6d-41ed-90f0-
cbb29a476ede')/channels('19:[email protected]')"
},
"encryptedContent": {
"data": "<<--EncryptedContent-->",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}],
"validationTokens": ["<<--ValidationTokens-->>"]
}
The decrypted notification payload looks like the following. The payload conforms to
the channel schema. The payload is similar to that returned by GET operations.
JSON
{
"id": "19:[email protected]",
"createdDateTime": "2020-02-14T01:10:03.592Z",
"displayName": "General",
"description": "Sample Channel description",
"isFavoriteByDefault": true,
"email": "",
"webUrl":
"https://teams.microsoft.com/l/channel/19%3Aa3f841d969cd4ae0a7cbe847fc10b371
%40thread.tacv2/General?groupId=7ed9bdab-9c7d-4c10-a25d-
3f4ff0e34577&tenantId=0f2d8f49-862a-493b-9ca8-82a10637e17d",
"membershipType": "standard",
"moderationSettings": null
}
For notifications without resource data, the payload looks like the following. This
payload is for a property change in a team.
JSON
{
"subscriptionId": "9f9d1ed0-c9cc-42e7-8d80-a7fc4b0cda3c",
"changeType": "created",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-02-02T11:26:41.0537895-08:00",
"resource": "teams('fbe2bf47-16c8-47cf-b4a5-4b9b187c508b')",
"resourceData": {
"id": "1612293113399",
"@odata.type": "#Microsoft.Graph.Teams",
"@odata.id": "teams('fbe2bf47-16c8-47cf-b4a5-4b9b187c508b')"
}
}
The resource and @odata.id properties can be used to make calls to Microsoft Graph to
get the payload for the message. GET calls will always return the current state of the
message. If the message is changed between when the notification is sent and when the
message is retrieved, the operation will return the updated message.
For notifications without resource data, the payload looks like the following. This
payload is for a property change in a team.
JSON
{
"id": "19:[email protected]",
"createdDateTime": "2020-02-14T01:10:03.592Z",
"displayName": "General",
"description": "Sample Channel description",
"isFavoriteByDefault": true,
"email": "",
"webUrl":
"https://teams.microsoft.com/l/channel/19%3Aa3f841d969cd4ae0a7cbe847fc10b371
%40thread.tacv2/General?groupId=7ed9bdab-9c7d-4c10-a25d-
3f4ff0e34577&tenantId=0f2d8f49-862a-493b-9ca8-82a10637e17d",
"membershipType": "standard",
"moderationSettings": null
}
See also
Microsoft Graph change notifications
Get change notifications for membership changes in teams and channels using
Microsoft Graph
Get change notifications for messages in Teams channels and chats using
Microsoft Graph
Get change notifications for chats using Microsoft Graph
Get change notifications for chat membership using Microsoft Graph
Microsoft Teams API overview
Change notifications team or channel C# sample
Change notifications team or channel Node.js sample
Get change notifications for
membership changes in teams and
channels using Microsoft Graph
Article • 10/04/2022
Continue with this article about scenarios for the conversationMember resource in the
team or channel context. Or, find out about change notifications for other Microsoft
Teams resources.
Permissions
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,deleted,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{team-id}/members",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Permissions
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,deleted,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/getAllMembers",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2022-08-10T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Permissions
Application ChannelMember.Read.All,
ChannelMember.ReadWrite.All
Example
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-Type: application/json
{
"changeType": "created,deleted,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/getAllChannels/getAllMembers",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2022-08-10T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Subscribe to membership changes in all private
and shared channels of a particular team
To get change notifications for membership changes in all the private and shared
channels in a particular team, subscribe to /teams/{team-id}/channels/getAllMembers .
This resource supports including resource data in the notification.
Note: This API has licensing and payment requirements. It supports both model=A
and model=B query parameters. If no model is specified, evaluation mode will be
used.
Permissions
Application ChannelMember.Read.All
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,deleted,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{team-id}/channels/getAllMembers",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
JSON
{
"value": [{
"subscriptionId": "10493aa0-4d29-4df5-bc0c-ef742cc6cd7f",
"changeType": "created",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-02-02T10:30:34.9097561-
08:00",
"resource": "teams('ee0f5ae2-8bc6-4ae5-8466-
7daeebbfa062')/members('ZWUwZjVhZTItOGJjNi00YWU1LTg0NjYtN2RhZWViYmZhMDYyIyM3
Mzc2MWYwNi0yYWM5LTQ2OWMtOWYxMC0yNzlhOGNjMjY3Zjk=')",
"resourceData": {
"id":
"ZWUwZjVhZTItOGJjNi00YWU1LTg0NjYtN2RhZWViYmZhMDYyIyM3Mzc2MWYwNi0yYWM5LTQ2OWM
tOWYxMC0yNzlhOGNjMjY3Zjk=",
"@odata.type": "#Microsoft.Graph.aadUserConversationMember",
"@odata.id": "teams('ee0f5ae2-8bc6-4ae5-8466-
7daeebbfa062')/members('ZWUwZjVhZTItOGJjNi00YWU1LTg0NjYtN2RhZWViYmZhMDYyIyM3
Mzc2MWYwNi0yYWM5LTQ2OWMtOWYxMC0yNzlhOGNjMjY3Zjk=')"
},
"encryptedContent": {
"data": "<<--EncryptedContent-->",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}],
"validationTokens": ["<<--ValidationTokens-->>"]
}
The payload for the channel membership events is similar to the previous payload
except that the resource property points to a channel member instead of a team
member.
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
The decrypted notification payload looks like the following. The payload conforms to
the aaduserconversationmember schema. The payload is similar to that returned by GET
operations.
JSON
{
"id":
"/ZWUwZjVhZTItOGJjNi00YWU1LTg0NjYtN2RhZWViYmZhMDYyIyM3Mzc2MWYwNi0yYWM5LTQ2OW
MtOWYxMC0yNzlhOGNjMjY3Zjk=",
"roles": [
"owner"
],
"displayName": "John Doe",
"userId": "8b081ef6-4792-4def-b2c9-c363a1bf41d5",
"email": null
}
For notifications without resource data, the payload looks like the following. This
payload is for a membership change in a team.
JSON
{
"subscriptionId": "9f9d1ed0-c9cc-42e7-8d80-a7fc4b0cda3c",
"changeType": "created",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-02-02T11:26:41.0537895-08:00",
"resource": "teams('ee0f5ae2-8bc6-4ae5-8466-
7daeebbfa062')/members('ZWUwZjVhZTItOGJjNi00YWU1LTg0NjYtN2RhZWViYmZhMDYyIyM3
Mzc2MWYwNi0yYWM5LTQ2OWMtOWYxMC0yNzlhOGNjMjY3Zjk=')",
"resourceData": {
"id":
"ZWUwZjVhZTItOGJjNi00YWU1LTg0NjYtN2RhZWViYmZhMDYyIyM3Mzc2MWYwNi0yYWM5LTQ2OWM
tOWYxMC0yNzlhOGNjMjY3Zjk",
"@odata.type": "#Microsoft.Graph.aadUserConversationMember",
"@odata.id": "teams('ee0f5ae2-8bc6-4ae5-8466-
7daeebbfa062')/members('ZWUwZjVhZTItOGJjNi00YWU1LTg0NjYtN2RhZWViYmZhMDYyIyM3
Mzc2MWYwNi0yYWM5LTQ2OWMtOWYxMC0yNzlhOGNjMjY3Zjk=')"
}
}
The payload for the channel membership events is similar to the previous payload
except that the resource property points to a channel member instead of a team
member.
The resource and @odata.id properties can be used to make calls to Microsoft Graph to
get the payload for the message. GET calls will always return the current state of the
message. If the message is changed between when the notification is sent and when the
message is retrieved, the operation will return the updated message.
See also
Microsoft Graph change notifications
Get change notifications for teams and channels using Microsoft Graph
Get change notifications for messages in Teams channels and chats using
Microsoft Graph
Get change notifications for chats using Microsoft Graph
Get change notifications for chat membership using Microsoft Graph
Microsoft Teams API overview
Get change notifications for messages
in Teams channels and chats using
Microsoft Graph
Article • 09/10/2022
Change notifications enable you to subscribe to changes (create, update, and delete) to
messages in a channel or chat. Change notifications provide a low latency model by
allowing you to maintain a subscription. You can also get the resource data in the
notifications and therefore avoid calling the API to get the payload.
Continue with this article about scenarios for the chatMessage resource in the channel
or chat context. Or, find out about change notifications for other Microsoft Teams
resources.
Note: This API has licensing and payment requirements. It supports both model=A
and model=B query parameters. If no model is specified, evaluation mode will be
used.
Permissions
Application ChannelMessage.Read.All
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/getAllMessages",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Note: This API has licensing and payment requirements. It supports both model=A
and model=B query parameters. If no model is specified, evaluation mode will be
used.
Permissions
Application Chat.Read.All
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated,deleted",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/chats/getAllMessages",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Channel-level subscriptions also support keyword-based search via the $search query
parameter.
Permissions
Application ChannelMessage.Read.Group*,
ChannelMessage.Read.All
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{team-id}/channels/{channel-id}/messages",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{team-id}/channels/{channel-id}/messages?
$search=Hello",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{team-id}/channels/{channel-id}/messages",
"includeResourceData": false,
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/teams/{team-id}/channels/{channel-id}/messages?
$filter=mentions/any(u: u/mentioned/user/id eq '9a6eb4d1-826b-48b1-9627-
b50836c8fee9')",
"includeResourceData": false,
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Chat-level subscriptions also support keyword-based search via the $search query
parameter.
Permissions
Permission type Permissions (from least to most privileged)
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/chats/{chat-id}/messages",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/chats/{chat-id}/messages?$search=Hello",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/chats/{chat-id}/messages",
"includeResourceData": false,
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/chats/{chat-id}/messages?$filter=mentions/any(u:
u/mentioned/user/id eq '9a6eb4d1-826b-48b1-9627-b50836c8fee9')",
"includeResourceData": false,
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
User-level chat messaging subscriptions also support keyword-based search via the
$search query parameter.
Note: This API has licensing and payment requirements. It supports the model=B
query parameter. If no model is specified, evaluation mode will be used.
Permissions
POST https://graph.microsoft.com/beta/subscriptions
Content-Type: application/json
{
"changeType": "created,updated,deleted",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/users/{user-id}/chats/getAllMessages",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
the notification.
Note: This API has licensing and payment requirements. It supports the model=B
query parameter. If no model is specified, evaluation mode will be used.
Permissions
Application Chat.Read.WhereInstalled,
Chat.ReadWrite.WhereInstalled
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/appCatalogs/teamsApps/386bbcdb-1e1c-4f3f-b7d0-
ad7b9ea6cf7c/installedToChats/getAllMessages",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Notification payloads
Depending on your subscription, you can either get the notification with resource data,
or without it. Subscribing with resource data allows you to get the message payload
along with the notification, removing the need to call back and get the content.
Notifications with resource data
For notifications with resource data, the payload looks like the following. This payload is
for a message sent in a chat.
JSON
{
"value": [{
"subscriptionId": "10493aa0-4d29-4df5-bc0c-ef742cc6cd7f",
"changeType": "created",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-02-02T10:30:34.9097561-
08:00",
"resource": "chats('19:8ea0e38b-efb3-4757-924a-
5f94061cf8c2_97f62344-57dc-409c-88ad-
[email protected]')/messages('1612289765949')",
"resourceData": {
"id": "1612289765949",
"@odata.type": "#Microsoft.Graph.chatMessage",
"@odata.id": "chats('19:8ea0e38b-efb3-4757-924a-
5f94061cf8c2_97f62344-57dc-409c-88ad-
[email protected]')/messages('1612289765949')"
},
"encryptedContent": {
"data": "<<--EncryptedContent-->",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}],
"validationTokens": ["<<--ValidationTokens-->>"]
}
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
The decrypted notification payload looks like the following. The payload conforms to
the chatMessage schema. The payload is similar to that returned by GET operations.
JSON
{
"id": "1612289992105",
"replyToId": null,
"etag": "1612289992105",
"messageType": "message",
"createdDateTime": "2021-02-02T18:19:52Z",
"lastModifiedDateTime": "2021-02-02T18:19:52.105Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:8ea0e38b-efb3-4757-924a-5f94061cf8c2_97f62344-57dc-409c-
[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"from": {
"application": null,
"device": null,
"user": {
"id": "8ea0e38b-efb3-4757-924a-5f94061cf8c2",
"displayName": "Ramjot Singh",
"userIdentityType": "aadUser"
},
"conversation": null
},
"body": {
"contentType": "text",
"content": "test"
},
"channelIdentity": null,
"attachments": [],
"mentions": [],
"policyViolation": null,
"reactions": [],
"replies": [],
"hostedContents": []
}
The payload looks like the following. This payload is for a message sent in a channel.
JSON
{
"subscriptionId": "9f9d1ed0-c9cc-42e7-8d80-a7fc4b0cda3c",
"changeType": "created",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-02-02T11:26:41.0537895-08:00",
"resource": "teams('fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b')/channels('19:[email protected]')/
messages('1612293113399')",
"resourceData": {
"id": "1612293113399",
"@odata.type": "#Microsoft.Graph.chatMessage",
"@odata.id": "teams('fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b')/channels('19:[email protected]')/
messages('1612293113399')"
}
}
The resource and @odata.id properties can be used to make calls to Microsoft Graph to
get the payload for the message. GET calls will always return the current state of the
message. If the message is changed between when the notification is sent and when the
message is retrieved, the operation will return the updated message.
See also
Microsoft Graph change notifications
Get change notifications for teams and channels using Microsoft Graph
Get change notifications for membership changes in teams and channels using
Microsoft Graph
Get change notifications for chats using Microsoft Graph
Get change notifications for chat membership using Microsoft Graph
Microsoft Teams API overview
Get change notifications for chats using
Microsoft Graph
Article • 03/01/2023
Change notifications enable you to subscribe to changes (create and update) to chats.
You can get notified whenever a chat is created or updated. You can also get the
resource data in the notifications and therefore avoid calling the API to get the payload.
Continue with this article about scenarios for the chat resource. Or, find out about
change notifications for other Microsoft Teams resources.
Permissions
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/chats",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Permissions
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/chats/{id}",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
JSON
{
"value": [{
"subscriptionId": "352887e3-9be0-4b6f-a4e6-dec118d857db",
"changeType": "Created",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-06-
03T09:50:37.719033+00:00",
"resource": "chats('19:1273a016-201d-4f95-8083-
[email protected]')",
"resourceData": {
"id": "19:1273a016-201d-4f95-8083-1b7f99b3edeb_976f4b31-fd01-
[email protected]",
"@odata.type": "#microsoft.graph.chat",
"@odata.id": "chats('19:1273a016-201d-4f95-8083-
[email protected]')"
},
"EncryptedContent": {
"data": "<<--EncryptedContent-->>",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
}
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}],
"validationTokens": ["<<--ValidationTokens-->>"]
}
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
The decrypted notification payload looks like the following. The payload conforms to
the chats schema. The payload is similar to that returned by GET operations.
JSON
{
"id": "19:1273a016-201d-4f95-8083-1b7f99b3edeb_976f4b31-fd01-4e0b-9178-
[email protected]",
"topic": null,
"createdDateTime": "2021-06-03T14:25:04+05:30",
"lastUpdatedDateTime": "2021-06-03T14:25:04.387Z",
"chatType": "oneOnOne",
"members": [
{
"userId": "976f4b31-fd01-4e0b-9178-29cc40c14438",
"email": null,
"tenantId": "2432b57b-0abd-43db-aa7b-16eadd115d34",
"id":
"MCMjMjQzMmI1N2ItMGFiZC00M2RiLWFhN2ItMTZlYWRkMTE1ZDM0IyMxOToxMjczYTAxNi0yMDF
kLTRmOTUtODA4My0xYjdmOTliM2VkZWJfOTc2ZjRiMzEtZmQwMS00ZTBiLTkxNzgtMjljYzQwYzE
0NDM4QHVucS5nYmwuc3BhY2VzIyM5NzZmNGIzMS1mZDAxLTRlMGItOTE3OC0yOWNjNDBjMTQ0Mzg
=",
"roles": [],
"displayName": null,
"visibleHistoryStartDateTime": "1970-01-01T00:00:00Z",
"user": null
},
{
"userId": "ee723d3d-22d0-4394-9c32-5764d68f4672",
"email": null,
"tenantId": "2432b57b-0abd-43db-aa7b-16eadd115d34",
"id":
"MCMjMjQzMmI1N2ItMGFiZC00M2RiLWFhN2ItMTZlYWRkMTE1ZDM0IyMxOToxMjczYTAxNi0yMDF
kLTRmOTUtODA4My0xYjdmOTliM2VkZWJfOTc2ZjRiMzEtZmQwMS00ZTBiLTkxNzgtMjljYzQwYzE
0NDM4QHVucS5nYmwuc3BhY2VzIyNlZTcyM2QzZC0yMmQwLTQzOTQtOWMzMi01NzY0ZDY4ZjQ2NzI
=",
"roles": [],
"displayName": null,
"visibleHistoryStartDateTime": "1970-01-01T00:00:00Z",
"user": null
}
],
"messages": [],
"installedApps": [],
"tabs": [],
"permissionGrants": [],
"operations": []
}
Note: This API has licensing and payment requirements. It supports the model=B
query parameter. If no model is specified, evaluation mode will be used.
Permissions
Permission type Permissions (from least to most privileged)
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/appCatalogs/teamsApps/386bbcdb-1e1c-4f3f-b7d0-
ad7b9ea6cf7c/installedToChats",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
JSON
{
"subscriptionId": "8d85051d-779d-45bc-be92-e433f0a5d8ac",
"changeType": "Created",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-06-03T10:26:09.8959595+00:00",
"resource": "chats('19:1273a016-201d-4f95-8083-1b7f99b3edeb_976f4b31-fd01-
[email protected]')",
"resourceData": {
"id": "19:1273a016-201d-4f95-8083-1b7f99b3edeb_976f4b31-fd01-4e0b-9178-
[email protected]",
"@odata.type": "#microsoft.graph.chat",
"@odata.id": "chats('19:1273a016-201d-4f95-8083-1b7f99b3edeb_976f4b31-
[email protected]')"
}
}
The resource and @odata.id properties can be used to make calls to Microsoft Graph to
get the payload for the chat details. GET calls will always return the current state of the
chat details. If the chat details were updated between when the notification is sent and
when the chat details were retrieved, the operation will return the updated chat details.
See also
Microsoft Graph change notifications
Get change notifications for teams and channels using Microsoft Graph
Get change notifications for membership changes in teams and channels using
Microsoft Graph
Get change notifications for messages in Teams channels and chats using
Microsoft Graph
Get change notifications for chat membership using Microsoft Graph
Microsoft Teams API overview
Change notifications team or channel C# sample
Change notifications team or channel Node.js sample
Get change notifications for chat
membership using Microsoft Graph
Article • 09/10/2022
Change notifications enable you to subscribe to changes (create and delete) in chats
membership. You can get notified whenever a conversationMember resource is added
or removed from a chat. You can also get the resource data in the notifications and
therefore avoid calling the API to get the payload.
Continue with this article about scenarios for the conversationMember resource in the
chat context. Or, find out about change notifications for other Microsoft Teams
resources.
Note: This API has licensing and payment requirements. It supports both model=A
and model=B query parameters. If no model is specified, evaluation mode will be
used.
Permissions
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,deleted",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/chats/getAllMembers",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
Permissions
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,deleted",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/chats/{id}/members",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
in the notification.
Note: This API has licensing and payment requirements. It supports the model=B
query parameter. If no model is specified, evaluation mode will be used.
Permissions
Example
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/appCatalogs/teamsApps/386bbcdb-1e1c-4f3f-b7d0-
ad7b9ea6cf7c/installedToChats/getAllMembers",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
JSON
{
"value": [{
"subscriptionId": "c0125ef2-7a87-4e94-aa71-b995510f369b",
"changeType": "Created",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-06-
03T11:04:58.5537601+00:00",
"resource": "chats('19:1273a016-201d-4f95-8083-
1b7f99b3edeb_976f4b31-fd01-4e0b-9178-
[email protected]')/members('MCMjMjQzMmI1N2ItMGFiZC00M2RiLWFhN2ItM
TZlYWRkMTE1ZDM0IyMxOToxMjczYTAxNi0yMDFkLTRmOTUtODA4My0xYjdmOTliM2VkZWJfOTc2Z
jRiMzEtZmQwMS00ZTBiLTkxNzgtMjljYzQwYzE0NDM4QHVucS5nYmwuc3BhY2VzIyMyZmM2MDY2M
y0xOWEyLTRhYTQtODUyYy1mN2JhNGU5MGFkYTI=')",
"resourceData": {
"id":
"MCMjMjQzMmI1N2ItMGFiZC00M2RiLWFhN2ItMTZlYWRkMTE1ZDM0IyMxOToxMjczYTAxNi0yMDF
kLTRmOTUtODA4My0xYjdmOTliM2VkZWJfOTc2ZjRiMzEtZmQwMS00ZTBiLTkxNzgtMjljYzQwYzE
0NDM4QHVucS5nYmwuc3BhY2VzIyMyZmM2MDY2My0xOWEyLTRhYTQtODUyYy1mN2JhNGU5MGFkYTI
=",
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"@odata.id": "chats('19:1273a016-201d-4f95-8083-
1b7f99b3edeb_976f4b31-fd01-4e0b-9178-
[email protected]')/members('MCMjMjQzMmI1N2ItMGFiZC00M2RiLWFhN2ItM
TZlYWRkMTE1ZDM0IyMxOToxMjczYTAxNi0yMDFkLTRmOTUtODA4My0xYjdmOTliM2VkZWJfOTc2Z
jRiMzEtZmQwMS00ZTBiLTkxNzgtMjljYzQwYzE0NDM4QHVucS5nYmwuc3BhY2VzIyMyZmM2MDY2M
y0xOWEyLTRhYTQtODUyYy1mN2JhNGU5MGFkYTI=')"
},
"EncryptedContent": {
"data": "<<--EncryptedContent-->>",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}],
"validationTokens": ["<<--ValidationTokens-->>"]
}
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
The decrypted notification payload looks like the following. The payload conforms to
the aaduserconversationmember schema. The payload is similar to that returned by GET
operations.
JSON
{
"userId": "2fc60663-19a2-4aa4-852c-f7ba4e90ada2",
"email": null,
"tenantId": "2432b57b-0abd-43db-aa7b-16eadd115d34",
"id":
"MCMjMjQzMmI1N2ItMGFiZC00M2RiLWFhN2ItMTZlYWRkMTE1ZDM0IyMxOToxMjczYTAxNi0yMDF
kLTRmOTUtODA4My0xYjdmOTliM2VkZWJfOTc2ZjRiMzEtZmQwMS00ZTBiLTkxNzgtMjljYzQwYzE
0NDM4QHVucS5nYmwuc3BhY2VzIyMyZmM2MDY2My0xOWEyLTRhYTQtODUyYy1mN2JhNGU5MGFkYTI
=",
"roles": [
"Owner"
],
"displayName": null,
"visibleHistoryStartDateTime": "1970-01-01T00:00:00Z",
"user": null
}
JSON
{
"subscriptionId": "cae901f1-ad1d-41b1-95b7-37029ed327bf",
"changeType": "Created",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-06-03T10:58:54.7656077+00:00",
"resource": "chats('19:1273a016-201d-4f95-8083-1b7f99b3edeb_976f4b31-
fd01-4e0b-9178-
[email protected]')/members('MCMjMjQzMmI1N2ItMGFiZC00M2RiLWFhN2ItM
TZlYWRkMTE1ZDM0IyMxOToxMjczYTAxNi0yMDFkLTRmOTUtODA4My0xYjdmOTliM2VkZWJfOTc2Z
jRiMzEtZmQwMS00ZTBiLTkxNzgtMjljYzQwYzE0NDM4QHVucS5nYmwuc3BhY2VzIyMyZmM2MDY2M
y0xOWEyLTRhYTQtODUyYy1mN2JhNGU5MGFkYTI=')",
"resourceData": {
"id":
"MCMjMjQzMmI1N2ItMGFiZC00M2RiLWFhN2ItMTZlYWRkMTE1ZDM0IyMxOToxMjczYTAxNi0yMDF
kLTRmOTUtODA4My0xYjdmOTliM2VkZWJfOTc2ZjRiMzEtZmQwMS00ZTBiLTkxNzgtMjljYzQwYzE
0NDM4QHVucS5nYmwuc3BhY2VzIyMyZmM2MDY2My0xOWEyLTRhYTQtODUyYy1mN2JhNGU5MGFkYTI
=",
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"@odata.id": "chats('19:1273a016-201d-4f95-8083-
1b7f99b3edeb_976f4b31-fd01-4e0b-9178-
[email protected]')/members('MCMjMjQzMmI1N2ItMGFiZC00M2RiLWFhN2ItM
TZlYWRkMTE1ZDM0IyMxOToxMjczYTAxNi0yMDFkLTRmOTUtODA4My0xYjdmOTliM2VkZWJfOTc2Z
jRiMzEtZmQwMS00ZTBiLTkxNzgtMjljYzQwYzE0NDM4QHVucS5nYmwuc3BhY2VzIyMyZmM2MDY2M
y0xOWEyLTRhYTQtODUyYy1mN2JhNGU5MGFkYTI=')"
}
}
The resource and @odata.id properties can be used to make calls to Microsoft Graph to
get the payload for the chat member details. GET calls will always return the current
state of the chat member details. If the chat member details has changed between when
the notification is sent and when the chat member details were retrieved, the operation
will return the updated chat member details.
See also
Microsoft Graph change notifications
Get change notifications for teams and channels using Microsoft Graph
Get change notifications for membership changes in teams and channels using
Microsoft Graph
Get change notifications for messages in Teams channels and chats using
Microsoft Graph
Get change notifications for chats using Microsoft Graph
Microsoft Teams API overview
Change notifications for Outlook
resources in Microsoft Graph
Article • 03/02/2023
The Microsoft Graph API lets you subscribe to changes to a resource—including creation,
update, or deletion of the resource—and receive notifications via webhooks. A subscription
specifies the desired types of changes to monitor for a specific resource, and includes a
URL for an endpoint to receive notifications of those changes.
Setting up a subscription reduces the overhead of otherwise having to query and compare
resources to deduce any changes. You can optionally specify in the subscription request to
encrypt and include as part of a notification the resource data that has changed, saving a
separate subsequent API call to get the resource payload.
There is a maximum limit of 1000 active subscriptions for Outlook resources per mailbox
for all applications. You can subscribe to changes in contacts, events, or messages in the
mailbox.
The following Outlook resources support subscriptions with or without resource data in the
change notification payload.
contact
event
message
Create a subscription
To create a subscription, specify the Outlook resource and the type of changes (creation,
update, or deletion) for which you want to receive notifications. See an example.
Request permissions
Creating and managing (getting, updating, and deleting) a subscription requires a read
scope to the resource. For example, to get change notifications on messages, your app
needs the Mail.Read permission. Outlook change notifications support delegated and
application permission scopes. Note the following limitations:
Depending on the resource, use the least privileged permission specified in the following
table to call this API.
Notifications with resource data for Outlook resources are currently available only in
the Microsoft Graph beta endpoint.
To have resource data included in a change notification, you must specify the following
properties, in addition to those you normally include when creating a subscription:
resource: This property specifies the resource URL. Make sure to use the $select
query parameter to explicitly specify the Outlook resource properties to include in the
notification payload.
7 Note
encryptionCertificate: This property contains only the public key that Microsoft Graph
uses to encrypt resource data. Keep the corresponding private key to decrypt the
content.
encryptionCertificateId: This property is your own identifier for the certificate. Use
this ID to match in each change notification which certificate to use for decryption.
See an example for subscribing to change notifications with resource data for the message
resource.
One common application of $filter is to get notified upon a change in a specific resource
property. For example, you can use $filter to subscribe to unread messages in a folder
(the isRead property is false ), and include all the change types:
If you lose the permission granted earlier for a subscription and the subscription expires
meanwhile, request permission again to create a new subscription.
{
"value": [
{
"subscriptionId": "dfd11b2f-8222-4189-9545-4205c95d6235",
"subscriptionExpirationDateTime": "2021-12-31T16:16:44.9907405+05:30",
"changeType": "created",
"resource": "Users('722effaf-0433-4272-9ac4-
d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"encryptedContent": {
"data": "<<--EncryptedContent-->>",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"dataSignature": "Qw/9ubWeUYJPWWXvNiGgct2FkNG2MXTRm/BLUpJM66k=",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"resourceData": {
"@odata.type": "#microsoft.graph.message",
"@odata.id": "Users('722effaf-0433-4272-9ac4-
d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUR8n\"",
"id": "AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA="
}
}
]
"validationTokens": ["<<--ValidationTokens-->>"]
}
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
JSON
{
"[email protected]":"#DateTimeOffset",
"receivedDateTime":"2021-12-30T10:53:35Z",
"subject":"TEST MESSAGE FOR RICH NOTIFICATIONS",
"bodyPreview":"Hello,\r\n\r\nWhat\u2019s up?\r\n\r\nThanks\r\nMegan",
"[email protected]":"#microsoft.graph.importance",
"importance":"normal",
"from": {
"@odata.type":"#microsoft.graph.recipient",
"emailAddress": {
"@odata.type":"#microsoft.graph.emailAddress",
"name":"Megan Brown",
"address":"[email protected]"
}
}
}
The next example shows the payload of a notification that corresponds to an Outlook
message resource. It includes the resource and resourceData properties, which represent
the resource that triggered the notification. Use the resource and @odata.id properties to
make calls to Microsoft Graph to get the payload of the resource.
7 Note
GET calls always return the current state of the resource. If the resource is changed
between the time the notification is sent and the time the resource is retrieved, the
operation returns the state of the resource on retrieval.
JSON
"value": [
{
"subscriptionId": "c6126aa3-0ed8-412f-a988-71e6cee627c4",
"subscriptionExpirationDateTime": "2022-01-02T03:12:18.2257768+05:30",
"changeType": "created",
"resource": "Users/622eaaff-0683-4862-9de4-
f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIxAAA=",
"resourceData": {
"@odata.type": "#Microsoft.Graph.Message",
"@odata.id": "Users/622eaaff-0683-4862-9de4-
f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIAAA=",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUUXn\"",
"id": "AAMkAGUwNjQ4ZjIxAAA="
},
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}
]
Examples
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"expirationDateTime": "2021-07-07T21:42:18.2257768+00:00",
"clientState": "secretClientState"
}
Response
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "5522bd62-7c96-4530-85b0-00b916f6151a",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientState",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T21:42:18.2257768Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": null,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": null,
"encryptionCertificateId": null,
"notificationUrlAppId": null
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?
$select=Subject,bodyPreview,importance,receivedDateTime,from",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "178eec5f-cf3c-4e7e-8a9c-8640deb5b5c5",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?
$select=Subject,bodyPreview,importance,receivedDateTime,from",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "me/mailfolders('Drafts')/messages?
$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance
eq 'High'",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "239dbc5f-cf3c-4e7e-8c9c-3340abc5b5c5",
"resource": "me/mailfolders('Drafts')/messages?
$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance eq
'High'",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-20T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}
See also
Microsoft Graph change notifications
Set up change notifications that include resource data
Outlook mail API overview
Outlook contacts API overview
Outlook calendar API overview
Use delta query to track changes in
Microsoft Graph data
Article • 03/15/2023
Delta query enables applications to discover newly created, updated, or deleted entities
without performing a full read of the target resource with every request. Microsoft
Graph applications can use delta query to efficiently synchronize changes with a local
data store.
1. The application begins by calling a GET request with the delta function on the
desired resource.
2. Microsoft Graph sends a response containing the requested resource and a state
token.
3. When the application needs to learn about changes to the resource, it makes a
new request using the @odata.deltaLink URL received in step 2. This request may
be made immediately after completing step 2 or when the application checks for
changes.
4. Microsoft Graph returns a response describing changes to the resource since the
previous request, and either a @odata.nextLink URL or a @odata.deltaLink URL.
7 Note
Resources stored in Azure Active Directory (such as users and groups) support
"sync from now" scenarios. This allows you to skip steps 1 and 2 (if you're not
interested in retrieving the full state of the resource) and ask for the latest
@odata.deltaLink instead. Append $deltaToken=latest to the delta function
Graph SDKs.
The initial request to the delta query function (no $deltaToken or $skipToken )
will return the resources that currently exist in the collection. Resources that
have been created and deleted prior to the initial delta query won't be
returned. Updates made before the initial request are summarized on the
resource returned as its latest state.
Note that $select and $deltaLink query parameters will be supported for
Azure Active Directory (Azure AD) resources so that customers can change the
properties they want to track for an existing @odata.deltaLink . Delta queries
with both $select and $skipToken will not be supported.
State tokens
A delta query GET response always includes a URL specified in a @odata.nextLink or
@odata.deltaLink response header. The @odata.nextLink URL includes a $skipToken ,
These tokens are opaque to the client. The following details are what you need to know
about them:
Each token reflects the state and represents a snapshot of the resource in that
round of change tracking.
The state tokens also encode and include other query parameters (such as
$select ) specified in the initial delta query request. Therefore, it's not required to
repeat them in subsequent delta query requests.
When carrying out delta query, you can copy and apply the @odata.nextLink or
@odata.deltaLink URL to the next delta function call without having to inspect the
contents of the URL, including its state token.
Note the general limited support of the following optional query parameters:
$orderby
Do not assume a specific sequence of the responses returned from a delta query.
Assume that the same item can show up anywhere in the @odata.nextLink
sequence and handle that in your merge logic.
$top
The number of objects in each page can vary depending on the resource type and
the type of changes made to the resource.
For the message resource, see details for query parameters support in a delta query.
For the user and group resources, there are restrictions on using some query
parameters:
If a $select query parameter is used, the parameter indicates that the client
prefers to only track changes on the properties or relationships specified in the
$select statement. If a change occurs to a property that is not selected, the
resource for which that property changed does not appear in the delta response
after a subsequent request.
$select also supports manager and members navigation properties for users and
Scoping filters allow you to track changes to one or more specific users or groups,
filtering only by object ID. For example, the following request returns changes for
the groups matching the IDs specified in the query filter.
HTTP
https://graph.microsoft.com/beta/groups/delta/?$filter=id eq '477e9fc6-5de7-
4406-bb2a-7e5c83c9ae5f' or id eq '004d6a07-fe70-4b92-add5-e6e37b8acd8e'
Updated instances are represented by their id with at least the properties that have
been updated, but additional properties may be included.
changed indicates the item was deleted and can be restored from deletedItems.
The @removed object can be returned in the initial delta query response and in tracked
(deltaLink) responses. Clients using delta query requests should be designed to handle
these objects in the responses.
7 Note
It's possible that a single entity will be contained multiple times in the response, if
that entity was changed multiple times and under certain conditions. Delta queries
enable your application to list all the changes, but can't ensure that entities are
unified in a single response.
Supported resources
Delta query is currently supported for the following resources. Note that some resources
which are available in v1.0 have their corresponding delta functions still in preview
status, as indicated.
Events in a calendar view (date range) of the delta function of the event resource
primary calendar
* The usage pattern for OneDrive and SharePoint resources is similar to the other
supported resources with some minor syntax differences. Delta query for drives and
lists will be updated in the future to be consistent with other resource types. For
more detail about the current syntax, see driveItem: delta and listItem: delta.
** The usage pattern for Planner resources is similar to other supported resources
with a few differences. For details, see planner: delta.
Limitations
To verify that a property can be used in delta query, try to perform a regular GET
operation on the resource collection, and select the property you're interested in. For
example, you can try the skills property on the users collection.
HTTP
GET https://graph.microsoft.com/v1.0/users/?$select=skills
Because the skills property is stored outside of Azure AD, the following is the response.
HTTP
{
"error": {
"code": "NotImplemented",
"message": "This operation target is not yet supported.",
"innerError": {
"request-id": "...",
"date": "2019-09-20T21:47:50"
}
}
}
This tells you that the skills property is not supported for delta query on the user
resource.
Navigation properties
Navigation properties are not supported. For example, you cannot track changes to the
users collection that would include changes to their photo property; photo is a
navigation property stored outside of the user entity, and changes to it do not cause the
user object to be included in the delta response.
Processing delays
Expect varying delays between the time a change is made to a resource instance, which
can be through an app interface or API, and the time the tracked change is reflected in a
delta query response.
Sometimes the changes that have occurred to the object might not be indicated when
you select the @odata.nextLink or the @odata.deltaLink . This is because some requests
might have replication delays for objects that were recently created, updated, or
deleted. Retry the @odata.nextLink or @odata.deltaLink after some time to retrieve the
latest changes.
National clouds
Delta queries are available for customers hosted on the public cloud and Microsoft
Graph China operated by 21Vianet only.
Replays
Your application must be prepared for replays, which occur when the same change
appears in subsequent responses. While delta query makes a best effort to reduce
replays, they are still possible.
Synchronization reset
Delta query can return a response code of 410 (gone) and a Location header containing
a request URL with an empty $deltaToken (same as the initial query). This is an
indication that the application must restart with a full synchronization of the target
tenant. This usually happens to prevent data inconsistency due to internal maintenance
or migration of the target tenant.
Token duration
Delta tokens are only valid for a specific period before the client application needs to
run a full synchronization again.
In case of an expired token, the service should respond with a 40X-series error with error
codes such as syncStateNotFound . For more information, see Error codes in Microsoft
Graph.
Prerequisites
The same permissions that are required to read a specific resource are also required to
perform delta query on that resource.
By using delta query, you can get new, updated, or deleted events in a specified
calendar or within a defined collection of events (as a calendar view) in the calendar.
This article describes the latter: getting such incremental changes to events in a calendar
view.
7 Note
Delta query supports both full synchronization that retrieves all the events in the
specified calendar view, and incremental synchronization that retrieves those events that
have changed in the calendar view since the last synchronization. Typically, you would
do an initial full synchronization, and subsequently get incremental changes to that
calendar view periodically.
Tracking event changes in a calendar view typically is a round of one or more GET
requests with the delta function. The initial GET request is very much like the way you list
a calendarView except that you include the delta function. The following is the initial
GET delta request of a calendar view in the signed-in user's default calendar:
GET /me/calendarView/delta?startDateTime={start_datetime}&endDateTime=
{end_datetime}
These tokens are state tokens which encode the startDateTime and endDateTime
parameters, and any other query parameter in your initial delta query GET request. You
do not need to include these parameters in subsequent requests as they are encoded in
the tokens.
State tokens are completely opaque to the client. To proceed with a round of change
tracking, simply copy and apply the @odata.nextLink or @odata.deltaLink URL returned
from the last GET request to the next delta function call for that same calendar view. A
@odata.deltaLink returned in a response signifies that the current round of change
tracking is complete. You can save and use the @odata.deltaLink URL when you begin
the next round.
See the example to learn how to use these @odata.nextLink and @odata.deltaLink
URLs.
For brevity, the sample responses show only a subset of the properties for an event. In
an actual call, most event properties are returned.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/calendarView/delta?
startdatetime=2016-12-01T00:00:00Z&enddatetime=2016-12-30T00:00:00Z
HTTP/1.1
Prefer: odata.maxpagesize=2
view to get.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(even
t)",
"@odata.nextLink":"https://graph.microsoft.com/v1.0/me/calendarView/delta?
$skiptoken=R0usmcCM996atia_s",
"value":[
{
"@odata.type":"#microsoft.graph.event",
"@odata.etag":"W/\"EZ9r3czxY0m2jz8c45czkwAAFXcvIQ==\"",
"subject":"Plan shopping list",
"body":{
"contentType":"html",
"content":""
},
"start":{
"dateTime":"2016-12-09T20:30:00.0000000",
"timeZone":"UTC"
},
"end":{
"dateTime":"2016-12-09T22:00:00.0000000",
"timeZone":"UTC"
},
"attendees":[
],
"organizer":{
"emailAddress":{
"name":"Samantha Booth",
"address":"[email protected]"
}
},
"id":"AAMkADNVxRAAA="
},
{
"@odata.type":"#microsoft.graph.event",
"@odata.etag":"W/\"EZ9r3czxY0m2jz8c45czkwAAFXcvIg==\"",
"subject":"Pick up car",
"body":{
"contentType":"html",
"content":""
},
"start":{
"dateTime":"2016-12-10T01:00:00.0000000",
"timeZone":"UTC"
},
"end":{
"dateTime":"2016-12-10T02:00:00.0000000",
"timeZone":"UTC"
},
"attendees":[
],
"organizer":{
"emailAddress":{
"name":"Samantha Booth",
"address":"[email protected]"
}
},
"id":"AAMkADVxSAAA="
}
]
}
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/calendarView/delta?
$skiptoken=R0usmcCM996atia_s HTTP/1.1
Prefer: odata.maxpagesize=2
HTTP
HTTP/1.1 200 OK
Content-type: application/json
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(even
t)",
"@odata.nextLink":"https://graph.microsoft.com/v1.0/me/calendarView/delta?
$skiptoken=R0usmci39OQxqJrxK4",
"value":[
{
"@odata.type":"#microsoft.graph.event",
"@odata.etag":"W/\"EZ9r3czxY0m2jz8c45czkwAAFXcvIw==\"",
"subject":"Get food",
"body":{
"contentType":"html",
"content":""
},
"start":{
"dateTime":"2016-12-10T19:30:00.0000000",
"timeZone":"UTC"
},
"end":{
"dateTime":"2016-12-10T21:30:00.0000000",
"timeZone":"UTC"
},
"attendees":[
],
"organizer":{
"emailAddress":{
"name":"Samantha Booth",
"address":"[email protected]"
}
},
"id":"AAMkADVxTAAA="
},
{
"@odata.type":"#microsoft.graph.event",
"@odata.etag":"W/\"EZ9r3czxY0m2jz8c45czkwAAFXcvJA==\"",
"subject":"Prepare food",
"body":{
"contentType":"html",
"content":""
},
"start":{
"dateTime":"2016-12-10T22:00:00.0000000",
"timeZone":"UTC"
},
"end":{
"dateTime":"2016-12-11T00:00:00.0000000",
"timeZone":"UTC"
},
"attendees":[
],
"organizer":{
"emailAddress":{
"name":"Samantha Booth",
"address":"[email protected]"
}
},
"id":"AAMkADVxUAAA="
}
]
}
Step 3: sample third request
The third request continues to use the latest @odata.nextLink returned from the last
sync request.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/calendarView/delta?
$skiptoken=R0usmci39OQxqJrxK4 HTTP/1.1
Prefer: odata.maxpagesize=2
view. Save and use the @odata.deltaLink URL to synchronize that calendar view in the
next round.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(even
t)",
"@odata.deltaLink":"https://graph.microsoft.com/v1.0/me/calendarView/delta?
$deltatoken=R0usmcMDNGg0J1E",
"value":[
{
"@odata.type":"#microsoft.graph.event",
"@odata.etag":"W/\"EZ9r3czxY0m2jz8c45czkwAALZu97g==\"",
"subject":"Rest!",
"body":{
"contentType":"html",
"content":""
},
"start":{
"dateTime":"2016-12-12T02:00:00.0000000",
"timeZone":"UTC"
},
"end":{
"dateTime":"2016-12-12T07:30:00.0000000",
"timeZone":"UTC"
},
"location":{
"displayName":"Home"
},
"attendees":[
],
"organizer":{
"emailAddress":{
"name":"Samantha Booth",
"address":"[email protected]"
}
},
"id":"AAMkADj1HuAAA="
}
]
}
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/calendarView/delta?
$deltatoken=R0usmcMDNGg0J1E HTTP/1.1
Prefer: odata.maxpagesize=2
HTTP/1.1 200 OK
Content-type: application/json
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(even
t)",
"@odata.deltaLink":"https://graph.microsoft.com/v1.0/me/calendarView/delta?
$deltatoken=R0usmcFuQtZdtpk4",
"value":[
{
"@odata.type": "#microsoft.graph.event",
"id":
"AAMkADk0MGFkODE3LWE4MmYtNDRhOS04OGQLkRkXbBznTvAADb6ytyAAA=",
"@removed": {
"reason": "deleted"
}
},
{
"@odata.type":"#microsoft.graph.event",
"@odata.etag":"W/\"EZ9r3czxY0m2jz8c45czkwAALZu97w==\"",
"subject":"Attend service",
"body":{
"contentType":"html",
"content":""
},
"start":{
"dateTime":"2016-12-25T06:00:00.0000000",
"timeZone":"UTC"
},
"end":{
"dateTime":"2016-12-25T07:30:00.0000000",
"timeZone":"UTC"
},
"location":{
"displayName":"Chapel of Saint Ignatius",
"address":{
"street":"900 Broadway",
"city":"Seattle",
"state":"WA",
"countryOrRegion":"United States",
"postalCode":""
},
"coordinates":{
"latitude":47.6105,
"longitude":-122.321
}
},
"attendees":[
],
"organizer":{
"emailAddress":{
"name":"Samantha Booth",
"address":"[email protected]"
}
},
"id":"AAMkADj1HvAAA="
}
]
}
See also
Microsoft Graph delta query
Get incremental changes to messages
Get incremental changes to groups
Get incremental changes to users
Get incremental changes for groups
Article • 03/02/2023
The delta query in Microsoft Graph lets you query for additions, deletions, or updates to
supported resources. It's enabled through a series of delta requests. For groups, the
delta query enables you to discover changes without fetching the entire set of groups to
compare changes.
Clients that synchronize groups with a local profile store can use the delta query for
both their initial full synchronization along with subsequent incremental
synchronizations. Typically, a client would do an initial full synchronization of all the
groups in a tenant, and then, get incremental changes to groups periodically.
When a group is deleted (Microsoft 365 groups), the item contains an annotation:
@removed with value of "reason": "changed" .
When the group is permanently deleted (a security group or permanently deleting
a Microsoft 365 group), the item contains an annotation: @removed with value of
"reason": "deleted" .
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/groups/delta?
$select=displayName,description,members
Initial response
If successful, this method returns 200 OK response code and group collection object in
the response body. If the entire set of groups is too large to fit in one response, a
@odata.nextLink containing a state token will also be included.
In this example, a @odata.nextLink was included; the original $select query parameter
is encoded in the state token.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups(displayN
ame,description)",
"@odata.nextLink":"https://graph.microsoft.com/v1.0/groups/delta?
$skiptoken=pqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjvB7XnF_yllFsCrZJ",
"value": [
{
"displayName":"All Company",
"description":"This is the default group for everyone in the network",
"id":"c2f798fd-f95d-4623-8824-63aec21fffff",
"members@delta": [
{
"@odata.type": "#microsoft.graph.user",
"id": "693acd06-2877-4339-8ade-b704261fe7a0"
},
{
"@odata.type": "#microsoft.graph.user",
"id": "49320844-be99-4164-8167-87ff5d047ace"
}
]
},
{
"displayName":"sg-HR",
"description":"All HR personnel",
"id":"ec22655c-8eb2-432a-b4ea-8b8a254bffff"
}
]
}
7 Note
The members@delta property is included in the first group object - All Company -
and contains the two current members of the group. sg-HR does not contain that
property because the group does not have any members.
nextLink request
The second request uses the @odata.nextLink from the previous response, which
contains the skipToken . Notice the $select parameter isn't visibly present as it's
encoded and included in the token.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/groups/delta?
$skiptoken=pqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjvB7XnF_yllFsCrZJ
nextLink response
The response contains another @odata.nextLink with a new skipToken value, which
indicates that more changes that were tracked for groups are available. Use the
@odata.nextLink URL in more requests until a @odata.deltaLink URL (in an
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
"@odata.nextLink":"https://graph.microsoft.com/v1.0/groups/delta?
$skiptoken=pqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjtQ5LOhVoS7qQG_wdVCHHlbQ
pga7",
"value": [
{
"displayName":"Mark 8 Project Team",
"description":"Mark 8 Project Team",
"id":"2e5807ce-58f3-4a94-9b37-ffff2e085957",
"members@delta": [
{
"@odata.type": "#microsoft.graph.user",
"id": "632f6bb2-3ec8-4c1f-9073-0027a8c68593"
}
]
},
{
"displayName":"Sales and Marketing",
"description":"Sales and Marketing",
"id":"421e797f-9406-4934-b778-4908421e3505",
"members@delta": [
{
"@odata.type": "#microsoft.graph.user",
"id": "3c8ac7c4-d365-4df9-abfa-356a9dd7763c"
},
{
"@odata.type": "#microsoft.graph.user",
"id": "49320844-be99-4164-8167-87ff5d047ace"
}
]
}
]
}
HTTP
GET https://graph.microsoft.com/v1.0/groups/delta?
$skiptoken=ppqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjtQ5LOhVoS7qQG_wdVC
HHlbQpga7
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
"@odata.deltaLink":"https://graph.microsoft.com/v1.0/groups/delta?
$deltatoken=sZwAFZibx-
LQOdZIo1hHhmmDhHzCY0Hs6snoIHJCSIfCHdqKdWNZ2VX3kErpyna9GygROwBk-
rqWWMFxJC3pw",
"value": [
{
"displayName":"All Employees",
"id":"bed7f0d4-750e-4e7e-ffff-169002d06fc9"
},
{
"displayName":"Remote living",
"description":"Remote living",
"id":"421e797f-9406-ffff-b778-4908421e3505"
}
]
}
deltaLink request
Using the @odata.deltaLink from the last response, you'll get changes (additions,
deletions, or updates) to groups since the last request. Changes include:
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/groups/delta?$deltatoken=sZwAFZibx-
LQOdZIo1hHhmmDhHzCY0Hs6snoIHJCSIfCHdqKdWNZ2VX3kErpyna9GygROwBk-
rqWWMFxJC3pw
deltaLink response
If no changes have occurred, a @odata.deltaLink is returned with no results - the value
property is an empty array. Make sure to replace the previous link in the application with
the new one for use in future calls.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
"@odata.deltaLink":"https://graph.microsoft.com/v1.0/groups/delta?
$deltatoken=sZwAFZibx-
LQOdZIo1hHhmmDhHzCY0Hs6snoIHJCSIfCHdqKdWNZ2VX3kErpyna9GygROwBk-
rqWWMFxJC3pw",
"value": []
}
If changes have occurred, a collection of changed groups is included. The response also
contains either a @odata.nextLink - in case there are multiple pages of changes to
retrieve - or a @odata.deltaLink . Implement the same pattern of following the
@odata.nextLink and persist the final @odata.deltaLink for future calls.
7 Note
This request might have replication delays for groups that were recently created,
updated, or deleted. Retry the @odata.nextLink or @odata.deltaLink after some
time to retrieve the latest changes.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
"@odata.deltaLink":"https://graph.microsoft.com/v1.0/groups/delta?
$deltatoken=sZwAFZibx-
LQOdZIo1hHhmmDhHzCY0Hs6snoIHJCSIfCHdqKdWNZ2VX3kErpyna9GygROwBk-
rqWWMFxJC3pw",
"value": [
{
"displayName": "TestGroup3",
"description": "A test group for change tracking",
"id": "2e5807ce-58f3-4a94-9b37-ffff2e085957",
"members@delta": [
{
"@odata.type": "#microsoft.graph.user",
"id": "632f6bb2-3ec8-4c1f-9073-0027a8c6859",
"@removed": {
"reason": "deleted"
}
},
{
"@odata.type": "#microsoft.graph.user",
"id": "37de1ae3-408f-4702-8636-20824abda004"
}
]
}
]
}
The objects are returned with the same set of properties originally specified via the
$select query parameter.
Both changed and unchanged properties are included. In the example above, the
description property has a new value, while the displayName property hasn't
changed.
The first user in the list has been removed from the group - either by removing
the membership or by deleting the user object itself. The @removed property
describes that. Only users that have been permanently deleted are removed
from groups. Users that have been temporary deleted keep their group
memberships and won't appear in the delta result until they're permanently
deleted. For details, see directory (deleted items).
7 Note
This pattern applies to both the initial retrieval of group state as well as to
subsequent calls to get delta changes.
Let's assume you're running the following delta query - either to capture the initial full
state of groups, or later on to get delta changes:
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/groups/delta?
$select=displayName,description,members
1. Microsoft Graph may return a response that contains just one group object, with a
large list of members in the members@delta property:
First page
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
"@odata.nextLink":"https://graph.microsoft.com/v1.0/groups/delta?
$skiptoken=<...>",
"value": [
{
"displayName":"LargeGroup",
"description":"A group containing thousands of users",
"id":"2e5807ce-58f3-4a94-9b37-ffff2e085957",
"members@delta": [
{
"@odata.type": "#microsoft.graph.user",
"id": "632f6bb2-3ec8-4c1f-9073-0027a8c6859",
"@removed": {
"reason": "deleted"
}
},
{
"@odata.type": "#microsoft.graph.user",
"id": "37de1ae3-408f-4702-8636-20824abda004"
},
<...more users here...>
]
}
<...no more groups included - this group filled out the entire
response...>
]
}
2. When you follow the @odata.nextLink , you may receive a response containing the
same group object. The same property values will be returned but the
members@delta property now contains a different list of users.
Second page
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
"@odata.nextLink":"https://graph.microsoft.com/v1.0/groups/delta?
$skiptoken=<...>",
"value": [
{
"displayName":"LargeGroup",
"description":"A group containing thousands of users",
"id":"2e5807ce-58f3-4a94-9b37-ffff2e085957",
"members@delta": [
{
"@odata.type": "#microsoft.graph.user",
"id": "c08a463b-7b8a-40a4-aa31-f9bf690b9551",
"@removed": {
"reason": "deleted"
}
},
{
"@odata.type": "#microsoft.graph.user",
"id": "23423fa6-821e-44b2-aae4-d039d33884c2"
},
<...more users here...>
]
}
<...no more groups included - this group filled out the entire
response...>
]
}
3. Eventually, the entire member list will be returned in this fashion, and other groups
will start showing up in the response.
Always follow @odata.nextLink and locally merge each group's state: as you
receive responses related to the same group, use them to build the full
membership list in your application.
Don't assume a specific sequence of the responses. Assume that the same group
could show up anywhere in the @odata.nextLink sequence and handle that in your
merge logic.
See also
Microsoft Graph delta query overview.
Get incremental changes to messages in
a folder
Article • 01/27/2023
Delta query lets you query for additions, deletions, or updates to messages in a folder
by way of a series of delta function calls. Delta data enables you to maintain and
synchronize a local store of a user's messages without having to fetch the entire set of
the user's messages from the server every time.
Synchronizing message items in a local store can use the delta query for the initial full
synchronization as well as subsequent incremental synchronizations. Typically, you
would do an initial full synchronization of all the messages in a folder (for example, the
user's Inbox), and then, get incremental changes to that folder periodically.
To get incremental changes of only a certain type - messages that are created, updated,
or deleted since the initial sync - do an initial round of synchronization of all the
messages in the folder, and then get incremental changes of a specific desired type in
subsequent rounds. Specify the desired change type as a query option in the initial delta
request; Microsoft Graph automatically encodes any OData and custom query options
into the @odata.nextLink or @odata.deltaLink provided in the response.
Tracking message changes in a mail folder typically is a round of one or more GET
requests with the delta function. The initial GET request is very much like the way you
get messages, except that you include the delta function:
HTTP
GET https://graph.microsoft.com/v1.0/me/mailFolders/{id}/messages/delta
A @odata.nextLink (that contains a URL with a delta function call and a skipToken),
or
A @odata.deltaLink (that contains a URL with a delta function call and deltaToken).
These tokens are state tokens that are completely opaque to the client. To proceed with
a round of change tracking, simply copy and apply the URL returned from the last GET
request to the next delta function call for the same folder. A @odata.deltaLink returned
in a response signifies that the current round of change tracking is complete. You can
save and use the @odata.deltaLink URL when you begin the next round.
Additionally, to return only certain type of changes (created, updated or deleted) in the
delta query's response, you can optionally filter the desired type of change using a
custom query option changeType . Possible values are created , updated or deleted .
HTTP
GET /me/mailfolders/{id}/messages/delta?changeType=created
GET /me/mailfolders/{id}/messages/delta?changeType=updated
GET /me/mailfolders/{id}/messages/delta?changeType=deleted
The first round involves a series of 3 requests to synchronize all 5 messages in the
folder:
After the first round, one of the messages is deleted, and another is marked as read. The
second round of synchronization returns only the delta (the deletion and update),
without returning the other messages that have remained the same.
A $select parameter to return the subject , sender , and isRead properties for
each message in the response.
The optional request header, odata.maxpagesize, returning 2 messages at a time.
HTTP
GET
https://graph.microsoft.com/v1.0/me/mailfolders/AQMkADNkNAAAgEMAAAA/messages
/delta?$select=subject,sender,isRead HTTP/1.1
Prefer: odata.maxpagesize=2
JSON
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(message)",
"@odata.nextLink":
"https://graph.microsoft.com/v1.0/me/mailfolders('AQMkADNkNAAAgEMAAAA')/mess
ages/delta?$skiptoken=GwcBoTmPuoTQWfcsAbkYM",
"value": [
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAAARn2vdzPFjSbaPPxzjlzOTAAASsKZz\"",
"subject": "Holiday hours update",
"isRead": false,
"sender": {
"emailAddress": {
"name": "Dana Swope",
"address": "[email protected]"
}
},
"id": "AAMkADNkNAAASq35xAAA="
},
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAAARn2vdzPFjSbaPPxzjlzOTAAAEfYB/\"",
"subject": "Holiday promotion sale",
"isRead": true,
"sender": {
"emailAddress": {
"name": "Samantha Booth",
"address": "[email protected]"
}
},
"id": "AQMkADNkNAAAVRMKAAAAA=="
}
]
}
HTTP
GET
https://graph.microsoft.com/v1.0/me/mailfolders/AQMkADNkNAAAgEMAAAA/messages
/delta?$skiptoken=GwcBoTmPuoTQWfcsAbkYM HTTP/1.1
Prefer: odata.maxpagesize=2
JSON
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(message)",
"@odata.nextLink":
"https://graph.microsoft.com/v1.0/me/mailfolders('AQMkADNkNAAAgEMAAAA')/mess
ages/delta?$skiptoken=GwcBoTmPKILK4jLH7mAd1lLU",
"value": [
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAAARn2vdzPFjSbaPPxzjlqfdAAAEfYB+\"",
"subject": "Microsoft Virtual Academy at Contoso",
"isRead": true,
"sender": {
"emailAddress": {
"name": "Elliot Hyde",
"address": "[email protected]"
}
},
"id": "AQMkADNkNAAAgWkAAAA"
},
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAAARn2vdzPFjSbaPPxzjlzOTAAAEfYB+\"",
"subject": "New or modified user account information",
"isRead": true,
"sender": {
"emailAddress": {
"name": "Randi Welch",
"address": "[email protected]"
}
},
"id": "AQMkADNkNAAAgWJAAAA"
}
]
}
GET
https://graph.microsoft.com/v1.0/me/mailFolders/AQMkADNkNAAAgEMAAAA/messages
/delta?$skiptoken=GwcBoTmPKILK4jLH7mAd1lLU HTTP/1.1
Prefer: odata.maxpagesize=2
for this folder. Save and use the @odata.deltaLink URL to synchronize the same folder in
the next round.
JSON
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(message)",
"@odata.deltaLink":
"https://graph.microsoft.com/v1.0/me/mailfolders('AQMkADNkNAAAgEMAAAA')/mess
ages/delta?$deltatoken=GwcBoTmPuoGNlgXgF1nyUNMXY",
"value": [
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAAARn2vdzFPjSbaPPxzjlzOTAAAEfYB+\"",
"subject": "Fabric CDN now available",
"isRead": true,
"sender": {
"emailAddress": {
"name": "Jodie Sharp",
"address": "[email protected]"
}
},
"id": "AAMkADk0MGFkODE3LWEAAA="
}
]
}
HTTP
GET
https://graph.microsoft.com/v1.0/me/mailfolders/AQMkADNkNAAAgEMAAAA/messages
/delta?$deltatoken=GwcBoTmPuoGNlgXgF1nyUNMXY HTTP/1.1
Prefer: odata.maxpagesize=2
The response contains a @odata.deltaLink . This indicates that all changes in the remote
mail folder are now synchronized. One message was deleted and the other message was
changed.
JSON
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(message)",
"@odata.deltaLink":
"https://graph.microsoft.com/v1.0/me/mailfolders('AQMkADNkNAAAgEMAAAA')/mess
ages/delta?$deltatoken=GwcBoTmPuoGNlgXgF1nyUNMXY",
"value": [
{
"@odata.type": "#microsoft.graph.message",
"id": "AAMkADk0MGFkODE3LWE4MmYtNDRhOS0Dh_6qB-
pB2Sa2pUum19a6YAAKnLuxoAAA=",
"@removed": {
"reason": "deleted"
}
},
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAAARn2vdzPFjSbaPPxzjlzOTAAASsKZz\"",
"subject": "Holiday hours update",
"isRead": "true",
"sender": {
"emailAddress": {
"name": "Dana Swope",
"address": "[email protected]"
}
},
"id": "AAMkADNkNAAASq35xAAA="
}
]
}
The first round involves a series of 2 requests to synchronize all 4 messages in the
folder:
After the first round, two more messages are created, one message is deleted, and
another is marked as read.
The second round of synchronization returns only the changes in the folder of the
created change type (the two new messages created), without returning the other
messages that have remained the same, deleted, or updated since the last sync.
HTTP
GET
https://graph.microsoft.com/v1.0/me/mailFolders/AAMkAGUwNc4LTMzAAA=/messages
/delta?changeType=created&$select=subject,sender,isRead HTTP/1.1
Prefer: odata.maxpagesize=2
JSON
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(message)",
"@odata.nextLink":
"https://graph.microsoft.com/v1.0/me/mailFolders/AAMkAGUwNc4LTMzAAA=/message
s/delta?$skiptoken=P4lmXpjPRrjB6haAQzSkpK89jYTVD2kVtOeXNRnfYzPbCs",
"value": [
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAId0MBP\"",
"subject": "Inline Attachments Again",
"isRead": true,
"id":
"AAMkAGUwNjQ4ZjIxLTQ3Y2YtNDViMi1iZjc4LT2fKdhq8oSKEDSVrdi3lRAAIei5gdAAA=",
"sender": {
"emailAddress": {
"name": "Megan Brown",
"address": "[email protected]"
}
}
},
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAId0MBR\"",
"subject": "RE: Test Outlook TimeZone",
"isRead": true,
"id":
"AAMkAGUwNjQ4ZjIxLTQ3Y2YtNDViMi1iZjc4LTMKdhq8oSKEDSVrdi3lRAAIei5geAAA=",
"sender": {
"emailAddress": {
"name": "Megan Brown",
"address": "[email protected]"
}
}
}
]
}
HTTP
GET
https://graph.microsoft.com/v1.0/me/mailFolders/AAMkAGUwNc4LTMzAAA=/messages
/delta?$skiptoken=P4lmXpjPRrjB6haAQzSkpK89jYTVD2kVtOeXNRnfYzPbCs HTTP/1.1
Prefer: odata.maxpagesize=2
JSON
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(message)",
"@odata.deltaLink":
"https://graph.microsoft.com/v1.0/me/mailFolders/AAMkAGUwNc4LTMzAAA=/message
s/delta?$deltatoken=P4lmXpjPRrjB6haAQ_37roqIbjXe66KoV7SMlLH--Jgi8",
"value": [
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAId0MBu\"",
"subject": "Your preview of the new Briefing email",
"isRead": true,
"id":
"AAMkAGUwNjQ4ZjIxLTQ3Y2YtNDViMi1iZjc4LTMzNjMwNWM0ZGE2YQBGAAAAAADbrwBIJ",
"sender": {
"emailAddress": {
"name": "Cortana",
"address": "[email protected]"
}
}
},
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAId0MBw\"",
"subject": "Char Coding HTML",
"isRead": true,
"id":
"AAMkAGUwNjQ4ZjIxLTQ3Y2YtNDViMi1iZjc4LTMzNjMwNWM0ZGE2YQBGAAAAAADbrwBA=",
"sender": {
"emailAddress": {
"name": "John Doe",
"address": "[email protected]"
}
}
}
]
}
Synchronize messages in the same folder in the next
round based on specified change type
Using the @odata.deltaLink from the last response in the last round, you will be able to
get only those messages that have been added in that folder since then. Your first
request in the next round will look like the following, assuming you prefer to keep the
same maximum page size in the response:
HTTP
GET
https://graph.microsoft.com/v1.0/me/mailFolders/AAMkAGUwNc4LTMzAAA=/messages
/delta?$deltatoken=P4lmXpjPRrjB6haAQ_37roqIbjXe66KoV7SMlLH--Jgi8 HTTP/1.1
Prefer: odata.maxpagesize=2
The response contains a @odata.deltaLink . This indicates that all changes in the remote
mail folder are now synchronized. Two messages were added since the last sync. The
messages updated & deleted since the last sync are not returned in this delta response.
JSON
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(message)",
"@odata.deltaLink":
"https://graph.microsoft.com/v1.0/me/mailFolders/AAMkAGUwNc4LTMzAAA=/message
s/delta?$skiptoken=EPuhZPRDHo-r3EBfscYE444fuGSBRV1eXex3JZkLzT9fRM",
"value": [
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAId0MCP\"",
"subject": "Nested Attachment",
"isRead": true,
"id":
"AAMkAGUwNjQ4ZjIxLTQ3Y2YtNDViMi1iZjc4LTMzNjMwNWM0ZGE2YQBGAAAAAADbrwBIJ",
"sender": {
"emailAddress": {
"name": "Patti Fernandez",
"address": "[email protected]"
}
}
},
{
"@odata.type": "#microsoft.graph.message",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAId0MCN\"",
"subject": "Attachment Testing",
"isRead": true,
"id":
"AAMkAGUwNjQ4ZjIxLTQ3Y2YtNDViMi1iZjc4LTMzNjMwNWM0ZGE2YQBGAAAAAADbrwZA=",
"sender": {
"emailAddress": {
"name": "Patti Fernandez",
"address": "[email protected]"
}
}
}
]
}
See also
Microsoft Graph delta query
Get incremental changes to events in a calendar view
Get incremental changes to groups
Get incremental changes to users
Get incremental changes for users
Article • 03/02/2023
The delta query in Microsoft Graph lets you query for additions, deletions, or updates to
supported resources. It is enabled through a series of delta requests. For users, the delta
query enables you to discover changes without fetching the entire set of users to
compare changes.
Clients that synchronize users with a local profile store can use the delta query for both
their initial full synchronization along with subsequent incremental synchronizations.
Typically, a client would do an initial full synchronization of all the users in a tenant, and
then, get incremental changes to users periodically.
When the user is deleted, the item contains an annotation: @removed with value of
"reason": "changed" .
When the user is permanently deleted, the item contains an annotation: @removed
with value of "reason": "deleted" .
When the user is created, or restored, there's no annotation.
Initial request
To track changes in the user resource, make a request and include the delta function as
a URL segment.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users/delta?
$select=displayName,givenName,surname
Initial response
If successful, this method returns 200 OK response code and user collection object in the
response body. Assuming the entire set of users is too large, the response will also
include a @odata.nextLink state token in an @odata.nextLink parameter.
In this example, a @odata.nextLink URL is returned indicating there are more pages of
data to be retrieved in the session. The $select query parameter from the initial request
is encoded into the @odata.nextLink URL.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users(displayNa
me,givenName,surname)",
"@odata.nextLink":"https://graph.microsoft.com/v1.0/users/delta?
$skiptoken=oEBwdSP6uehIAxQOWq_3Ksh_TLol6KIm3stvdc6hGhZRi1hQ7Spe__dpvm3U4zReE
4CYXC2zOtaKdi7KHlUtC2CbRiBIUwOxPKLa",
"value": [
{
"displayName":"Cameron White",
"givenName":"Cameron",
"surname":"White",
"id":"ffff7b1a-13b6-477b-8c0c-380905cd99f7"
},
{
"displayName":"Delia Dennis",
"givenName":"Delia",
"surname":"Dennis",
"id":"605d1257-ffff-40b6-8e6f-528a53f5dc55"
},
{
"id": "86462606-fde0-4fc4-9e0c-a20eb73e54c6",
"@removed": {
"reason": "deleted"
}
},
{
"displayName": "Conf Room Adams",
"id": "6ea91a8d-e32e-41a1-b7bd-d2d185eed0e0"
}
]
}
nextLink request
The second request specifies the skipToken returned from the previous response. Notice
the $select parameter is encoded and included in the skipToken .
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users/delta?
$skiptoken=oEBwdSP6uehIAxQOWq_3Ksh_TLol6KIm3stvdc6hGhZRi1hQ7Spe__dpvm3U4
zReE4CYXC2zOtaKdi7KHlUtC2CbRiBIUwOxPKLa
nextLink response
The response contains another @odata.nextLink with a new skipToken value, which
indicates that more changes that were tracked for users are available. Use the
@odata.nextLink URL in more requests until a @odata.deltaLink URL (in an
empty array.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users",
"@odata.nextLink":"https://graph.microsoft.com/v1.0/users/delta?
$skiptoken=pqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjtQ5LOhVoS7qQG_wdVCHHlbQ
pga7",
"value": [
{
"displayName":"Mallory Cortez",
"givenName":"Mallory",
"surname":"Cortez",
"id":"d8c37826-ffff-4cae-b348-e2725b1e814b"
},
{
"displayName":"Diego Sicilian",
"givenName":"Diego",
"surname":"Sicilian",
"id":"8b1ee412-cd8f-4d59-ffff-24010edb9f1f"
}
]
}
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users/delta?
$skiptoken=pqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjtQ5LOhVoS7qQG_wdVCH
HlbQpga7
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users",
"@odata.deltaLink":"https://graph.microsoft.com/v1.0/users/delta?
$deltatoken=oEcOySpF_hWYmTIUZBOIfPzcwisr_rPe8o9M54L45qEXQGmvQC6T2dbL-9O7nSU-
njKhFiGlAZqewNAThmCVnNxqPu5gOBegrm1CaVZ-ZtFZ2tPOAO98OD9y0ao460",
"value": [
{
"displayName":"Lidia Holloway",
"givenName":"Lidia",
"surname":"Holloway",
"id":"25dcffff-959e-4ece-9973-e5d9b800e8cc"
},
{
"displayName":"Patti Fernandez",
"givenName":"Patti",
"surname":"Fernandez",
"id":"f6ede700-27d0-4c42-bfb9-4dffff43c74a"
}
]
}
deltaLink request
Using the deltaToken from the last response, you'll get changes (additions, deletions, or
updates) to users since the last request.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users/delta?
$deltatoken=oEcOySpF_hWYmTIUZBOIfPzcwisr_rPe8o9M54L45qEXQGmvQC6T2dbL-
9O7nSU-njKhFiGlAZqewNAThmCVnNxqPu5gOBegrm1CaVZ-ZtFZ2tPOAO98OD9y0ao460
deltaLink response
If no changes have occurred, a @odata.deltaLink is returned with no results - the value
property is an empty array.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users",
"@odata.deltaLink":"https://graph.microsoft.com/v1.0/users/delta?
$deltatoken=MF1LuFYbK6Lw4DtZ4o9PDrcGekRP65WEJfDmM0H26l4v9zILCPFiPwSAAeRBghxg
iwsXEfywcVQ9R8VEWuYAB50Yw3KvJ-8Z1zamVotGX2b_AHVS_Z-3b0NAtmGpod",
"value": []
}
If changes have occurred, a collection of changed user objects is included. The response
also contains either a @odata.nextLink - in case there are multiple pages of changes to
retrieve - or a @odata.deltaLink . Implement the same pattern of following the
@odata.nextLink and persist the final @odata.deltaLink for future calls.
7 Note
This request might have replication delays for users that were recently created,
updated, or deleted. Retry the @odata.nextLink or @odata.deltaLink after some
time to retrieve the latest changes.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users",
"@odata.deltaLink":"https://graph.microsoft.com/v1.0/users/delta?
$deltatoken=MF1LuFYbK6Lw4DtZ4o9PDrcGekRP65WEJfDmM0H26l4v9zILCPFiPwSAAeRBghxg
iwsXEfywcVQ9R8VEWuYAB50Yw3KvJ-8Z1zamVotGX2b_AHVS_Z-3b0NAtmGpod",
"value": [
{
"displayName":"MOD Administrator",
"givenName":"MOD",
"surname":"Administrator",
"id":"25dcffff-959e-4ece-9973-e5d9b800e8cc"
},
{
"id":"8ffff70c-1c63-4860-b963-e34ec660931d",
"@removed": {
"reason": "changed"
}
}
]
}
See also
Microsoft Graph delta query overview.
Overview of compliance and privacy
APIs in Microsoft Graph
Article • 06/24/2022
The Microsoft Graph APIs for compliance and privacy provide functionality for
organizations to automate repetitive tasks and integrate with their existing compliance
tools to build predictable workflows that are often required to meet industry
regulations.
The compliance and privacy APIs are intended to help deliver on the vision of helping
organizations adapt and extend Microsoft 365 Compliance to their own specific
requirements, enable integration for existing custom or third-party solutions, and
accelerate and support the use of Microsoft 365 solutions across the enterprise digital
estate.
In many organizations, eDiscovery workflows are frequent, critical, and high volume. In
the cases where there are common repeated tasks or a high volume of activities, the
APIs will help provide a scalable way to repeat processes consistently and effectively.
Depending on the current systems and processes in place, organizations might have
various priorities for automation and integration, from upstream processes such as case
creation, to downstream such as collection, review set queries, or export. Supporting
workflows with APIs throughout the advanced eDiscovery workflow provides flexibility
and options.
Create custom reporting to track case load and progress from individual cases.
The Microsoft Graph APIs for subject rights request provide functionality for
organizations to automate repetitive tasks and integrate with existing data subject
request tools, to enable building repeatable workflows that can be incorporated to their
business processes. You can use the subject rights request APIs to help you automate
and scale your organization's ability to perform subject rights requests searches in
Microsoft 365 and help meet industry regulations more efficiently.
API reference
Looking for the API reference for these services?
Next steps
Explore your own data from the user resource in the Graph Explorer.
Explore the Microsoft Graph compliance APIs.
Explore Microsoft Graph samples and SDKs.
Microsoft Graph connectors overview
Article • 08/27/2022
Although most information workers spend much of their work time within productivity
applications such as Microsoft 365, they also need a way to integrate that environment
with the enterprise applications and other on-premises and SaaS cloud software and
services that they use. Examples include enterprise resource planning (ERP) applications,
customer resource management (CRM) applications, intranet applications, wikis, blogs,
and social networking sites.
Microsoft Graph connectors offer an intuitive way to bring content from external
services into Microsoft Graph, enabling external data to power Microsoft 365 intelligent
experiences such as Microsoft Search (currently GA).
Today, with Microsoft Graph connectors, the data you bring in from your organization
can appear in Microsoft Search results. This feature expands the types of content
sources that are searchable in your Microsoft 365 productivity apps and the broader
Microsoft ecosystem. Soon, connectors will power many other Microsoft 365 intelligent
experiences, such as Viva Topics.
To learn more about the existing Microsoft Graph connectors, visit the Microsoft Graph
connectors gallery .
Next steps
Work with the Microsoft Graph connectors API
Use Postman with the Microsoft Graph connectors API
Work with the Microsoft Graph
connectors API
Article • 06/15/2022
Microsoft Graph connectors bring external data into Microsoft Graph and enhance
Microsoft 365 intelligent experiences. You might want to build a custom connector to
integrate with services that aren't available as connectors built by Microsoft. To build
custom connectors, you use the Microsoft Graph connectors REST API.
To learn more, see Create, update, and delete connections in Microsoft Graph.
To learn more, see Register and update schema for the Microsoft Graph connection.
To learn more, see Create, update, and delete items added by your application via
Microsoft Graph connectors.
You can use the external group API to set permissions on external items ingested into
Microsoft Graph. An externalGroup represents a non-Azure Active Directory group or
group-like construct (such as business units, teams, and so on) and determines
permissions on the content in your external data source.
To learn more, see Use external groups to manage permissions to Microsoft Graph
connectors data sources.
Next steps
Build a custom connector
Use Postman with the Microsoft Graph
connectors API
Article • 01/25/2023
Postman is an API platform for building and using APIs. Postman simplifies each step of
the API lifecycle and streamlines collaboration so that you can create better APIs faster.
This article describes how you can use the Microsoft Graph connectors API with
Postman.
Prerequisites
Either a Microsoft account or work or school account.
Access to a Microsoft 365 developer tenant. If you don't have one, you can sign up
for the Microsoft 365 Developer Program to get a free developer subscription.
1. Go to Postman and sign up. If you already have a Postman account, you can sign
in .
3. Select the three dots to the right, and then select Create a fork.
4. In the dialog that opens, enter a label to identify your fork. In the Workspace
dropdown menu, select My Workspace, and then select Fork Collection.
5. Go to Workspaces > My Workspace to see the fork that you created. You can find
the Microsoft Graph connectors folder under Application.
Step 2: Download the Postman Agent (optional
- Postman web browser only)
To use this Postman collection in your web browser, download the Postman Desktop
Agent .
You can't use Postman for the web without this due to CORS restrictions in the web
browser: "The maximum number of connection resources per Microsoft 365 tenant."
You don't need the agent if you're using the Postman for Windows app. If you open
Postman for Windows, you see this collection in your workspace.
2. In the Variables section, provide the required information by using the information
from step 3:
Set the current value of tenant to the directory (tenant) ID value from step
3.15.
Set the current value of client_id to the application (client) ID value from step
3.15.
Set the current value of client_secret to the client secret value from step 3.17.
Set the current value of userName to [email protected] .
Set the current value of password to tenant admin password.
3. Select Save / Update.
The following example shows how to get an access token with a shared secret:
HTML
client_id={{client_id}}
&scope=https%3A%2F%2Fptop.only.wip.la%3A443%2Fhttps%2Fgraph.microsoft.com%2F.default
&client_secret={{client_secret}}
&grant_type=client_credentials
{
"token_type": "Bearer",
"expires_in": 3599,
"ext_expires_in": 3599,
"access_token": "eyJ0eXAiOiJKV1QiLCJu… "
}
7 Note
You are using the client credential flow here. Be sure to get an app access token
and not a user access token.
HTTP
POST /external/connections
HTTP
POST https://graph.microsoft.com/beta/external/connections
Content-type: application/json
{
"id": "contosotasks",
"name": "Contoso Tasks",
"description": "Connection to index Contoso task management system"
}
HTTP
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#connection
s/$entity",
"id": "contosotasks",
"name": "Contoso Tasks",
"description": "Connection to index Contoso task management system",
"state": null,
"configuration": {
"authorizedApps": [
"a47b35b7-6271-4e6d-9e27-2450a8b9c6b6"
]
}
}
HTTP
POST /external/connections/{id}/schema
The following is an example of the request.
HTTP
POST
https://graph.microsoft.com/beta/external/connections/contosotasks/schema
Content-type: application/json
Prefer: respond-async
{
"baseType": "microsoft.graph.externalItem",
"properties": [
{
"name": "title",
"type": "String",
"isSearchable": "true",
"isQueryable": "true",
"isRetrievable": "true",
"labels": [
"title"
]
},
{
"aliases": "creator",
"name": "createdBy",
"type": "String",
"isSearchable": "true",
"isQueryable": "true",
"isRetrievable": "false",
"isRefinable": "false",
"labels": [
"createdBy"
]
},
{
"aliases": "editedDate",
"name": "lastEditedDate",
"type": "DateTime",
"isSearchable": "false",
"isQueryable": "true",
"isRetrievable": "true",
"isRefinable": "true",
"labels": [
"lastModifiedDateTime"
]
}
]
}
7 Note
HTTP
GET /external/connections/contosotasks/operations/616bfeed-666f-4ce0-
8cd9-058939010bfc
HTTP
Request
GET
https://graph.microsoft.com/beta/external/connections/operations/616bfeed-
666f-4ce0-8cd9-058939010bfc
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
@odata.context":"https://graph.microsoft.com/beta/$metadata#external/con
nections('coursecatalog')/operations/$entity",
"id": "aa9186d2-893c-4361-ca51-431d88fa45d8",
"name": "Contoso Tasks",
"status": "inprogress",
"error": null
}
After the connection state changes from draft to ready, you can ingest items into the
current connection.
External groups (along with Azure Active Directory users and groups) are used to set
permissions on externalItems added to a Microsoft Graph connection. For details, see
externalGroup.
HTTP
POST
https://graph.microsoft.com/beta/external/connections/contosotasks/groups/31
bea3d537902000/members
Content-Type: application/json
{
"@odata.type": "#microsoft.graph.externalGroupMember",
"id": "1431b9c38ee647f6a",
"type": "group",
"identitySource": "external"
}
HTTP
HTTP/1.1 201 Created
Content-Type: application/json
{
"@odata.type": "#microsoft.graph.externalGroupMember",
"id": "14m1b9c38qe647f6a",
"type": "group",
"identitySource": "external"
}
If you have binary files, you must parse to get the metadata and a text version of the
content. If you have non-text content such as a PDF or BMP file, you must use object
character recognition to convert content to text.
You are responsible for converting your source permissions to grant or deny . Deny
takes higher precedence over grant .
HTTP
PUT
https://graph.microsoft.com/beta/external/connections/contosohr/items/TSP228
082938
Content-type: application/json
{
"@odata.type": "microsoft.graph.externalItem",
"acl": [
{
"type": "user",
"value": "e811976d-83df-4cbd-8b9b-5215b18aa874",
"accessType": "grant",
"identitySource": "azureActiveDirectory"
},
{
"type": "group",
"value": "14m1b9c38qe647f6a",
"accessType": "deny",
"identitySource": "external"
}
],
"properties": {
"ticketID": "1158",
"priority": 1,
"title": "Filter design",
},
"content": {
"value": "Build filtering capability by...",
"type": "text"
}
}
HTTP
HTTP/1.1 200 OK
Error handling
For details about how to resolve errors, see Resolve Microsoft Graph authorization
errors.
See also
Use Postman with the Microsoft Graph API
Build your first custom Microsoft Graph
connector
Article • 03/16/2023
Microsoft Graph connectors enable you to add your own data into Microsoft Graph and
have it power various Microsoft 365 experiences. The following set of articles show you
how to use the Microsoft Graph connectors SDK to create a custom connector in C# and
use it to power Microsoft Search. This custom connector uses a sample data appliance
parts inventory in a CSV file for the Contoso Appliance Repair organization.
7 Note
If you want to use a language other than C# to build your connector, see Build a
connector using other languages.
This article describes how to use the Microsoft Graph connector SDK to build a custom
connector in C#.
Prerequisites
1. Download, install, and complete the setup for the Microsoft Graph connector
agent.
2. Install Visual Studio 2019 or later with the .NET 7.0 SDK .
3. Download the ApplianceParts.csv file from the custom connector sample repo .
4. Go to File > New > Project and search for GraphConnectorsTemplate. Select the
template and choose Next.
5. Provide a name for the project and choose Next.
6. Choose .NET Core 3.1, name the connector CustomConnector, and choose Create.
.NET CLI
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace CustomConnector.Models
{
public class AppliancePart
{
[Key]
public int PartNumber { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Price { get; set; }
public int Inventory { get; set; }
public List<string> Appliances { get; set; }
}
}
Update ConnectionManagementServiceImpl.cs
You will implement three methods in ConnectionManagementServiceImpl.cs.
ValidateAuthentication
The ValidateAuthentication method is used to validate the credentials and the data
source URL provided. You need to connect to the data source URL using the credentials
provided and return success if the connection succeeds or auth failure status if the
connection fails.
C#
using CsvHelper;
using CsvHelper.Configuration;
using CsvHelper.TypeConversion;
using CustomConnector.Models;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
namespace CustomConnector.Data
{
public static class CsvDataLoader
{
public static void ReadRecordFromCsv(string filePath)
{
using (var reader = new StreamReader(filePath))
using (var csv = new CsvReader(reader,
CultureInfo.InvariantCulture))
{
csv.Context.RegisterClassMap<AppliancePartMap>();
csv.Read();
}
}
}
The ReadRecordFromCsv method will open the CSV file and read the first record
from the file. We can Use this method to validate that the provided data source
URL (path of the CSV file) is valid. This connector is using anonymous auth;
therefore, credentials are not validated. If the connector uses any other auth type,
the connection to the data source must be made using the credentials provided to
validate the authentication.
using CustomConnector.Data;
C#
CsvDataLoader.ReadRecordFromCsv(request.AuthenticationData.DatasourceUr
l);
return this.BuildAuthValidationResponse(true);
}
catch (Exception ex)
{
Log.Error(ex.ToString());
return this.BuildAuthValidationResponse(false, "Could
not read the provided CSV file with the provided credentials");
}
}
ValidateCustomConfiguration
C#
return Task.FromResult(response);
}
GetDataSourceSchema
The GetDataSourceSchema method is used to fetch the schema for the connector.
C#
using Microsoft.Graph.Connectors.Contracts.Grpc;
using static
Microsoft.Graph.Connectors.Contracts.Grpc.SourcePropertyDefinition.Type
s;
C#
schema.PropertyList.Add(
new SourcePropertyDefinition
{
Name = nameof(Name),
Type = SourcePropertyType.String,
DefaultSearchAnnotations = (uint)
(SearchAnnotations.IsSearchable | SearchAnnotations.IsRetrievable),
RequiredSearchAnnotations = (uint)
(SearchAnnotations.IsSearchable | SearchAnnotations.IsRetrievable),
});
schema.PropertyList.Add(
new SourcePropertyDefinition
{
Name = nameof(Price),
Type = SourcePropertyType.Double,
DefaultSearchAnnotations = (uint)
(SearchAnnotations.IsRetrievable),
RequiredSearchAnnotations = (uint)
(SearchAnnotations.IsRetrievable),
});
schema.PropertyList.Add(
new SourcePropertyDefinition
{
Name = nameof(Inventory),
Type = SourcePropertyType.Int64,
DefaultSearchAnnotations = (uint)
(SearchAnnotations.IsQueryable | SearchAnnotations.IsRetrievable),
RequiredSearchAnnotations = (uint)
(SearchAnnotations.IsQueryable | SearchAnnotations.IsRetrievable),
});
schema.PropertyList.Add(
new SourcePropertyDefinition
{
Name = nameof(Appliances),
Type = SourcePropertyType.StringCollection,
DefaultSearchAnnotations = (uint)
(SearchAnnotations.IsSearchable | SearchAnnotations.IsRetrievable),
RequiredSearchAnnotations = (uint)
(SearchAnnotations.IsSearchable | SearchAnnotations.IsRetrievable),
});
schema.PropertyList.Add(
new SourcePropertyDefinition
{
Name = nameof(Description),
Type = SourcePropertyType.String,
DefaultSearchAnnotations = (uint)
(SearchAnnotations.IsSearchable | SearchAnnotations.IsRetrievable),
RequiredSearchAnnotations = (uint)
(SearchAnnotations.IsSearchable | SearchAnnotations.IsRetrievable),
});
return schema;
}
C#
using CustomConnector.Models;
C#
return Task.FromResult(response);
}
Update ConnectorCrawlerServiceImpl.cs
This class has the methods that will be called by the platform during the crawls.
The GetCrawlStream method will be called during the full or periodic full crawls.
C#
using System.Globalization;
C#
accessControlList.Entries.Add(this.GetAllowEveryoneAccessControlEntry()
);
return accessControlList;
}
sourcePropertyValueMap.Values.Add(
nameof(this.PartNumber),
new GenericType
{
IntValue = this.PartNumber,
});
sourcePropertyValueMap.Values.Add(
nameof(this.Name),
new GenericType
{
StringValue = this.Name,
});
sourcePropertyValueMap.Values.Add(
nameof(this.Price),
new GenericType
{
DoubleValue = this.Price,
});
sourcePropertyValueMap.Values.Add(
nameof(this.Inventory),
new GenericType
{
IntValue = this.Inventory,
});
return sourcePropertyValueMap;
}
C#
using Microsoft.Graph.Connectors.Contracts.Grpc;
C#
C#
using CustomConnector.Data;
C#
Now the connector is created and you can build and run the project.
Next steps
Test your connector
Test your Microsoft Graph connector
Article • 03/16/2023
You can use the TestApp utility to test your Microsoft Graph connector. This is a console
application that is used to test connector before deployment. It will not create any
connections or ingest any data.
1. Update the ConnectionInfo.json file with the connector ID and data source path,
and set AuthenticationKind to null . This file is located in the following folder:
C:\Program Files\Graph connector agent\TestApp\Config.
b. The datasource path is the path where you downloaded the ApplianceParts.csv
file.
JSON
{
// All these configs are only required to test locally
"id": "TestGrpcConnector", // ConnectionId. Must be unique for a
tenant. Change this for each crawlTest
"name": "TestGrpcConnector", // name of connection
"description": "\<Connection description>",
"configuration": {
"providerId": "a1c127ed-29ce-47fb-ad4a-8836871922ea", //Enter your
ConnectorUniqueId
"scheduleSetting": {
"fullSyncInterval": 30 // the value is in seconds. Decrease this
to run consecutive tests on the same connectionId
},
"CredentialData": {
"Path": "D:\\ApplianceParts.csv",
"AuthenticationKind": "Anonymous", // Authentication kind which
connector supports eg: basic, windows, anonymous,
oauth2.client_credentials
"CredentialDetails": null // If AuthenticationKind is set to
something different, use { "loginId": "", "loginSecret": "" } here
},
"ProviderParameters": null // This parameter will have the
data/configuration given during connection creation time. Will be
present in JSON serialized format
}
}
JSON
{
"a1c127ed-29ce-47fb-ad4a-8836871922ea": "30303" //Update your
ConnectorUniqueId and Port information
}
JSON
{
// This is your unique connector ID/provider ID.
"connectorId": "a1c127ed-29ce-47fb-ad4a-8836871922ea", //Update your
ConnectorUniqueId here
// This is a list of all supported auth types. Remove the ones that the
connector does not support.
"authTypes": [ "Anonymous" ]
}
Next steps
Deploy your connector
Host a Microsoft Graph connector as a
Windows service
Article • 12/10/2022
This article describes how to host your Microsoft Graph connector as a Windows service
so that it will run continuously.
The connector executable must be always running so that the connector platform can
make requests to it during crawls or to perform any connection management
operations. The executable won't be actively consuming any resources except for the
times when the connector is being crawled. The rest of the time, the connector
executable will just be idle.
One way to make the connector executable run continuously is to host it as a Windows
service. If the executable is registered as a Windows service, the operating system will
take care of starting the process, and restarting it if the system crashes.
1. Right-click the solution that contains the custom connector project and select Add
> New project.
2. Search for the Worker service template, select it, and then choose Next.
.NET CLI
7. Right-click the worker service project and select Add > Project Reference.
9. Replace the code in the Worker.cs file with the following code.
C#
using CustomConnector.Server;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;
namespace CustomConnectorWorkerService
{
public class Worker : BackgroundService
{
public Worker(ILogger<Worker> logger)
{
var server = new ConnectorServer();
server.StartLogger();
server.Start();
}
10. Replace the code in the Program.cs file with the following code.
C#
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace CustomConnectorWorkerService
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
12. Run the following script to register and start the custom connector as Windows
service.
PowerShell
$ServiceName = "CustomConnector"
$ExePath = "<Full path of CustomConnectorWorkerService.exe from above
build>"
# Create a service with the given executable. This just creates an
entry for this service.
sc.exe create $ServiceName binPath="$ExePath" start="delayed-auto"
# Set the service to run under a virtual account NT Service\
<ServiceName>. Optionally skip this step to run the service under LOCAL
SYSTEM account
sc.exe config $ServiceName obj="NT Service\$ServiceName"
# Restarts service after 5 minutes on first, second and third failures
and resets error after 1 day
sc.exe failureflag $ServiceName 1
sc.exe failure $ServiceName reset= 86400 actions=
restart/300000/restart/300000/restart/300000
sc.exe start $ServiceName
7 Note
For any issues with hosting the connector, see Troubleshooting errors.
Next steps
Publish a connection for your custom connector
Publish your custom Microsoft Graph
connector
Article • 03/16/2023
Ths article describes how to publish your custom Microsoft Graph connector to the
Microsoft 365 admin center.
3. Choose Custom Connector and use the manifest file validated from the test
application for your sample connector with your updated connectorId.
4. Provide a connection name, connection ID, and description (optional), select the
checkbox, and choose Next.
5. Provide the URL of the location where you've downloaded the CSV file to be
indexed and choose the Microsoft Microsoft Graph connector agent that you
installed. Choose Test connection to validate the information provided, and then
choose Next.
Next steps
Surface the data in search
Surface the data in Microsoft Search
Article • 03/16/2023
To make it easier for users to find information that they have permission to see, you can
create search verticals and result types to customize the search results in Microsoft
SharePoint, Microsoft Office, and Microsoft Search in Bing.
To create and enable a search vertical at the organization level, sign in to the Microsoft
365 admin center by using the global administrator role, and do the following:
Content source: The custom connector created with the sample code (Parts
Inventory).
Add a query: Leave blank.
Content source: The custom connector created with the sample code.
Rules: None
2. Using the search box at the top of the page, search for hinge.
3. When the search completes with 0 results, select the Appliance Parts tab. Results
from the connector are displayed.
See also
Best practices
Troubleshooting issues
Create, update, and delete connections
in Microsoft Graph
Article • 03/02/2023
The Microsoft Graph connectors platform offers an intuitive way to add your external
data into Microsoft Graph. A connection is a logical container for your external data that
an administrator can manage as a single unit.
After a connection has been created, you can add your content from any external data
source such as an on-premises content source or an external SaaS service. You can only
view and manage the connections that you created or were explicitly authorized to
manage. A search admin can view and manage all the connections in the tenant from
the Modern Admin Center.
You can model a connection any way you want, but creating one connection for every
instance of your connector is the most common model. For example, each time that you
set up the Microsoft Windows file share connector, a new connection is created. You can
also create a single connection to add all items from your data source. For example, you
can create a single connection to add all the tickets and incidents across multiple teams
from your helpdesk system.
State Description
Draft An empty connection is provisioned. The data source, schema, or any settings
have not been configured yet.
Ready The connection is provisioned with registered schema and is ready for ingestion.
Obsolete This occurs when a dependent feature, such as an API, has been deprecated.
Deleting the connection is the only valid operation.
LimitExceeded If you reach the maximum limit of a single connection or the tenant level quota
across all connections, you cannot add more items until you exit the state.
The following table specifies which operations are available in each state.
Create connection ❌ ✔️ ❌ ✔️
Read connection ✔️ ✔️ ✔️ ✔️
Update connection ✔️ ✔️ ❌ ✔️
Delete connection ✔️ ✔️ ✔️ ✔️
Create schema ✔️ ❌ ❌ ❌
Read schema ❌ ✔️ ✔️ ✔️
Update schema ❌ ❌ ❌ ❌
Delete schema ❌ ❌ ❌ ❌
Create item ❌ ✔️ ❌ ❌
Read item ❌ ✔️ ✔️ ✔️
Update item ❌ ✔️ ❌ ✔️
Delete item ❌ ✔️ ❌ ✔️
A connection allows your application to define a schema for items that will be indexed,
and it provides an endpoint for your service to add, update, or delete items from the
index.
The first step for an application to add items to the search index is to create a
connection.
Create a connection
Before an application can add items to the search index, it must create and configure a
connection:
Note: For information about updating the schema for an existing connection,
see Schema update capabilities.
enabledContentExperiences Description
value
The following example shows how to update a connection to enable both the search
and compliance content experiences.
HTTP
PATCH https://graph.microsoft.com/beta/external/connections/contosohelpdesk
Content-Type: application/json
{
"enabledContentExperiences": "search, compliance"
}
Connection settings
You can configure the default connection settings for each enabled content experience.
When enabled, these settings affect the content experiences.
Search settings
You can define how search results are displayed in the Microsoft Search results page by
supplying the default search display templates for your content. A set of search display
templates can be used to display distinct kinds of search results differently. A search
display template has a result layout built using Adaptive Cards and rules that specify
one or more conditions. When these conditions are met, the layout will be applied to
the search result and displayed on the results page.
Compliance settings
Similar to enterprise search settings, you need to define how to display advanced
eDiscovery search results by supplying result types for your content. This enables the
eDiscovery manager to visualize the content when reviewing the datasets. The following
example shows the results of an eDiscovery search review of an Azure DevOps item.
) Important
The Adaptive Card format is used to render results in eDiscovery. Unlike the search
experience, the eDiscovery experience only supports Adaptive Card elements up to
version 1.2.
When you configure the eDiscovery result template in the Adaptive Card Designer ,
select 1.2 as the target version.
Note that the following limitations apply to Adaptive Cards in the eDiscovery result
templates:
Activity settings
In activity settings, you can provide a way for Microsoft 365 apps to detect share
activity, which will enable your content to be recommended to users who interact with
that content the most. The way to do this is to add a urlToItemResolver, which will allow
a given URL detected within Microsoft 365 apps to be resolved to its respective item ID
on the externalItem.
The following image shows how your item might appear within recommendation
experiences across the Microsoft 365 suite.
Update a connection
To change the display name, description, or enabled content experiences for an existing
connection, you can update the connection.
Delete a connection
To remove all items that were indexed via a connection, you can delete a connection.
Next steps
Register the connection schema
Review the Microsoft Graph connectors API reference
Download the sample search connector from GitHub
Register and update schema for the Microsoft Graph
connection
Article • 12/02/2022
The connection schema determines how your content is used in various Microsoft Graph experiences. The schema is a
flat list of all the properties that you plan to add to the connection along with their attributes, labels, and aliases. You
must register the schema before adding items into the connection.
Example schema
The following table represents an example of a possible schema for a work ticket system connector.
ticketId String ✔️ ✔️ ID
assignedTo String ✔️ ✔️
priority Int64 ✔️
tags StringCollection ✔️ ✔️ ✔️ ✔️
status String ✔️ ✔️
resolved Boolean ✔️ ✔️
Property attributes
Searchable
If a property is searchable, its value is added to the full text index. When a user performs a search, we return results if
there is a search hit in one of the searchable fields or its content.
A search for "design" displaying results for hits against the property ( title ) and content.
Queryable
If a property is queryable, you can query against it using knowledge query language (KQL). KQL consists of one or
more free text keywords (words or phrases) or property restrictions. The property name must be included in the
query, either specified in the query itself or included in the query programmatically. You can use prefix matching with
the wildcard operator(*).
7 Note
A search for "search ba*" displaying results that match this prefix.
A search for "tags:design" scoping down results to items with "design" in the tags property.
Retrievable
If a property is retrievable, its value can be returned in search results. Any property that you want to add in the
display template or be returned from the query and be relevant in search results must be retrievable. Marking large
or too many properties as retrievable increases search latency. Be selective and choose relevant properties.
Refinable
If a property is refinable, an admin can configure it as a custom filter in the Microsoft Search results page. A
refinable property cannot be searchable .
Refine results by tags , a refinable property.
For example, the ticketId property is both queryable and specifies exact matching.
Querying ticketId:CTS-ce913b61 will return the item with a ticket ID property CTS-ce913b61.
Querying ticketId:CTS will NOT return the item with ticket ID CTS-ce913b61.
Querying tags:contoso will return any item with the tag contoso.
Querying tags:contoso will NOT return items with the tag contoso ticket.
For example, there might be a scenario where the item property is a GUID-formatted string. If this property must be
matched exactly for item queries, specify that isExactMatchRequired is true .
The title property does not specify exact matching. If nothing is specified, then isExactMatchRequired is false . The
title property will be tokenized based on the tokenization rules of the language of the item content.
Querying title:Contoso Title will return any item containing "Contoso" or "Title" in the title property.
Semantic labels
A semantic label is a well-known tag published by Microsoft that you can add against a property in your schema.
Adding a semantic label helps various Microsoft products understand the property and provide a better experience.
Semantic labels provide a domain-independent approach to assigning properties from different content domains to a
set of well-known classes. They find applications in many different content experiences, and provide automated
support for tasks such as:
You can assign semantic labels to your source properties on the Assign property labels page. Labels provide
semantic meaning, and let you integrate your connector data into Microsoft 365 experiences.
Label Description
title The title of the item that you want shown in search and other experiences.
createdBy The name of the person who created the item in the data source.
lastModifiedBy The name of the person who most recently edited the item in the data source.
authors The names of all the people who participated/collaborated on the item in the data source.
createdDateTime The date and time that the item was created in the data source.
lastModifiedDateTime The date and time that the item was last modified in the data source.
fileName In case of a file, the name of the file in the data source.
fileExtension In case of a file, the extension of the file in the data source.
For example, the connection property lastEditedBy has the same meaning as the Microsoft label lastModifiedBy.
Add as many labels as you can, but ensure that they are accurately mapped to properties. Do not add a label to a
property if it doesn't make sense. Incorrect mappings degrade the experience.
) Important
The label title is the most important label. Make sure that you assign a property to this label to allow your connection
to participate in the result cluster experience. Incorrectly mapping labels degrades the search experience. It's okay for
some labels to not have a property assigned to them.
Relevance
By applying as many accurately mapped labels as possible, you can also improve the discovery of your content
through search. We highly recommend defining as many of the following labels as possible, listed by potential impact
on discovery in descending order:
title
lastModifiedDateTime
lastModifiedBy
url
fileName
fileExtension
Your default result type provides a better experience when you define these labels, when applicable, listed by
ascending order:
title
url
lastModifiedBy
lastModifiedDateTime
fileName
fileExtension
The properties that you select to function as labels need to be marked retrievable.
The properties and their assigned labels must have the same datatype.
You can map exactly one label to exactly one property.
Aliases
Aliases are friendly names for properties that you assign. These are used in queries and selections in refinable
property filters.
7 Note
We recommend that you reingest items after an update to bring them to the latest schema. Without reingestion,
the behavior of the items will be inconsistent.
Add a property
You can add a property to your schema; doing so does not require reingestion, but we recommend it.
When you add a property, you can include all the search attributes that you need.
Add/remove an alias
You can add or remove aliases, and use them for your search queries.
Consider that you cannot remove the original alias of a refinable property that was autocreated by the system.
Next steps
Add items to the connection
Review the Microsoft Graph connectors API reference
Search custom types (externalItem)
Build your first custom Microsoft Graph connector
Create, update, and delete items added
by your application via Microsoft Graph
connectors
Article • 10/04/2022
Microsoft Graph connectors offer an intuitive way to bring external data into Microsoft
Graph. Items added by your application to the Microsoft Search service are represented
by the externalItem resource in Microsoft Graph.
After you create a connection, you can add your content. Each item from your data
source must be represented as an externalItem in Microsoft Graph with a unique item
ID. This ID is used to create, update, or delete the item from Microsoft Graph. You can
use the primary key from your data source as the item ID or derive it from one or more
fields.
Key components
An externalItem has three key components: access control list, properties, and content.
The accessType value deny takes precedence over grant . For example, in the item
shown earlier, while Everyone is granted access and a specific user is denied access, the
effective permission for this user is deny .
If your data source has non-Azure AD groups (such as teams within your helpdesk
system) that are used to set permissions for the item, you can create external groups in
Microsoft Graph by using the group sync APIs to replicate the allow or deny
permissions. Avoid expanding the membership of your external groups directly into the
ACLs of individual items because each group membership can lead to a high volume of
item updates.
External groups can consist of another external group, Azure AD users, and Azure AD
groups. If you have non-Azure AD users, you must translate them to Azure AD users in
your ACL.
Properties
The properties component is used to add item metadata that is useful in Microsoft
Graph experiences. You must register the schema for the connection before adding
items into it and convert datatypes into supported datatypes.
Content
The content component is used to add the bulk of the item that needs to be full text
indexed. Examples include a ticket description, parsed text from a file body, or a wiki
page body.
Content is one of the key fields influencing relevance across Microsoft experiences. The
content types text and html are supported. If your data source has other content
types, such as binary files, videos, or images, you can parse them to text before adding
them to Microsoft Graph. For example, you can use optical character recognition to
extract searchable text from images.
) Important
The compliance solution only supports text for the content type. If you enable the
connection for compliance by setting the enabledContentExperience property to
compliance , you should ingest content in plain text format and set the content type
to text .
Content cannot be directly added into a search result template, but you can use a
generated result snippet, which is a dynamically generated preview of the relevant
sections within content.
When content in your data source changes, you must sync it with your connection
items. You can either update the entire item or update one or more of its components.
After your content has been added to Microsoft Graph, you can search for it through the
Microsoft Search experience after setting up search verticals and result types or by using
the Microsoft Graph Search API.
Add an item
To add an item to the index, you create an externalItem. When you create an item, you
assign a unique identifier in the URL.
For example, your application may index helpdesk tickets by using the ticket number. If
a ticket has the ticket number SR00145 , the request might look like the following:
HTTP
PUT /external/connections/contosohelpdesk/items/SR00145
Content-Type: application/json
{
"title": "WiFi outage in Conference Room A",
"status": "New",
"assignee": "[email protected]"
}
7 Note
Before indexed items can be found in the Microsoft Search UI, an administrator
must customize the search results page for the corresponding connection.
Update an item
When an item is updated in the external service (the helpdesk ticket is reassigned or a
product description is updated), you can update its entry in the index by updating the
externalItem, using the unique identifier assigned to the item when you created it.
HTTP
PATCH /external/connections/contosohelpdesk/items/SR00145
Content-Type: application/json
{
"assignee": "[email protected]"
}
Delete an item
To remove items from the index, you delete the externalItem, using the unique identifier
assigned to the item when you created it.
HTTP
DELETE /external/connections/contosohelpdesk/items/SR00145
Next steps
Use external groups to manage permissions
Query using the Microsoft Search API
Review the Microsoft Graph connectors API reference
Search custom types (externalItem)
Download the sample search connector from GitHub
Use external groups to manage
permissions to Microsoft Graph
connectors data sources
Article • 06/15/2022
External groups let you manage permissions to view external items in a Microsoft Graph
connection and connect to data sources outside Azure Active Directory (Azure AD)
groups.
For data sources that rely on Azure AD users and groups, you set permissions on
external items by associating an access control list (ACL) with an Azure AD user and
group ID when creating or updating the external items.
However, for data sources that use non-Azure AD groups or group-like constructs such
as Salesforce Profiles, Dynamics Business Units, SharePoint groups, ServiceNow local
groups, or Confluence local groups, we recommend that you use external groups.
Microsoft Dynamics 365 allows customers to structure their CRMs with business units
and teams. The membership information for these business units and teams is not
stored in Azure AD.
The following image shows the structure of the business units and teams.
Salesforce uses profiles, roles, and permission sets for authorization. These are specific
to Salesforce, and the membership information is not available in Azure AD.
The following image shows the structure of the membership information in Salesforce.
1. For each non-Azure AD group, use the groups API to create an external group in
Microsoft Graph.
2. Use the external group when defining the ACL for your external items as necessary.
3. Keep the membership of the external groups up to date and in sync.
1. Use the groups API in Microsoft Graph, as shown in the following example.
7 Note
HTTP
POST /external/connections/{connectionId}/groups
{
"id": "contosoEscalations",
"displayName": "Contoso Escalations",
"description": "Tier-1 escalations within Contoso"
}
2. Provide either an identifier or a name in the ID field. Use this value to call the
external group in subsequent requests.
7 Note
The ID field allows you to use URL and filename-safe Base64 character sets. It
has a limit of 128 characters.
An Azure AD user.
An Azure AD group.
Another external group, including nested external groups.
3. After you create the group, you can add members to the group, as shown in the
following examples.
HTTP
POST
https://graph.microsoft.com/beta/external/connections/{connectionId}/gr
oups/{groupId}/members
{
"id": "contosoSupport",
"type": "group",
"identitySource": "external"
}
HTTP
POST
https://graph.microsoft.com/beta/external/connections/{connectionId}/gr
oups/{groupId}/members
{
"id": "25f143de-be82-4afb-8a57-e032b9315752",
"type": "user",
"identitySource": "azureActiveDirectory"
}
HTTP
POST
https://graph.microsoft.com/beta/external/connections/{connectionId}/gr
oups/{groupId}/members
{
"id": "99a3b3d6-71ee-4d21-b08b-4b6f22e3ae4b",
"type": "group",
"identitySource": "azureActiveDirectory"
}
HTTP
PUT https://graph.microsoft.com/beta/external/connections/{id}/items/{id}
Content-type: application/json
{
"@odata.type": "microsoft.graph.externalItem",
"acl": [
{
"type": "group",
"value": "contosEscalations",
"accessType": "grant",
"identitySource": "External"
},
{
"type": "user",
"value": "87e9089a-08d5-4d9e-9524-b7bd6be580d5",
"accessType": "grant",
"identitySource": "azureActiveDirectory"
},
{
"type": "group",
"value": "96fbeb4f-f71c-4405-9f0b-1d6988eda2d2",
"accessType": "deny",
"identitySource": "azureActiveDirectory"
}
],
"properties": {
"title": "Error in the payment gateway",
"priority": 1,
"assignee": "[email protected]"
},
"content": {
"value": "<h1>Error in payment gateway</h1><p>Error details...</p>",
"type": "html"
}
}
7 Note
You can use external groups in ACLs even before the groups are created.
Next steps
Learn about Microsoft Graph connectors API limits
Work with the Microsoft Graph connectors API
Use Postman with the Microsoft Graph connectors API
Microsoft Graph connectors API limits
Article • 05/10/2023
This article describes implementation and operational limits for Microsoft Graph
connectors. Keep these limits in mind when designing connectors.
Connection limits
Limit type Limit
Schema limits
Limit type Limit
Properties that can be defined in a schema, characterizing the data ingested through a 128
connection
Group limits
Limit type Limit
Requests allowed per second (requests/sec) in the group administration throttling 1,000
threshold
Item ingestion
Limit type Limit
Limit type Limit
Item size; this limit applies to the request body when ingesting and indexing an 4 MB
item
Throttling
When a throttling threshold is exceeded, Microsoft Graph limits any further requests
from that client for a period of time. When throttling occurs, Microsoft Graph returns
HTTP status code 429 (Too many requests), and the requests fail. A suggested wait time
is returned in the response header of the failed request.
Throttling behavior can depend on the type and number of requests. For example, if you
have a high volume of requests, all request types are throttled. Threshold limits vary
based on the request type. Therefore, you could encounter a scenario where writes are
throttled but reads are still permitted.
Cross-device experiences in Microsoft
Graph
Article • 06/23/2022
In today's multi-device world, the way consumers use devices spans different platforms
and form factors: they might read the morning news on their tablets, check email during
the morning commute on their phones, and use their desktop PCs when at work. At
night, they might watch movies on their home media consoles and use smart speakers
to catch up on news from the day. The average customer engages with multiple devices
and platforms throughout the day.
In the past, form factor drove distinct types of behavior differences among consumers.
However, today multi-device consumers conduct all their activities across all their
devices. The tasks performed on a daily basis (whether at home with family or at work
with colleagues) are not inherently device-centric, but rather human-centric. Consumers
want to be able to use whatever screen is available, independent of where the input
comes from. In reality, they often find that each device has a clear boundary and getting
things done across devices requires unnatural actions such as sending oneself an email
or using USB sticks. Customers see friction when moving between their devices, and
sometimes important tasks get lost because of this context switching. This is also a
challenge for developers because when customers feel friction using an app, customer
engagement with the app goes down.
Microsoft is building a platform for creating experiences that transcend a single device
so they can harmonize across devices—empowering you to create human-centric
scenarios that move with the user and blur the lines between their devices, regardless of
form factor or platform. Microsoft Graph provides a single unified endpoint to give you
access to data from Azure Active Directory and Microsoft 365. Now through Microsoft
Graph, you can also access the activities and devices that belong to your customers and
enable rich human-centric experiences that cross devices and platforms.
API reference
Looking for the API reference for these services?
Next steps
Learn more about the activity feed API in Microsoft Graph
Learn more about the device relay API in Microsoft Graph
Use the activity feed API in Microsoft
Graph to enable cross-device
experiences
Article • 06/23/2022
Activities make users more productive by helping them resume important tasks in your
app quickly across devices. Microsoft helps drive user productivity with your apps
through experiences like Windows Timeline, Windows Sets, Cortana Pick up Where I left
off, and Microsoft Launcher, which are all powered by the activity feed. When you use
activities, these Microsoft experiences can start driving engagement with your app. You
can also display activities in your apps to help users get back to what they were doing
on any device, on any platform, including Windows, Android, and iOS.
Each user activity represents a single destination within your app: a product page, TV
show, document, or current campaign in a game. All you need is a deep link to resume
the activity in your app. Use get recent activities to create a list of recently viewed
products for your shopping app or a current reading list for books and news articles.
See also
Cross-device experiences in Microsoft Graph
Use the activity feed API to resume a user's activity across devices
Publish activities and history items with one request using deep insert
Learn more about Project Rome
Device relay API in Microsoft Graph
(preview)
Article • 01/11/2023
Today, people interact with multiple devices on a daily basis. Users often start
productivity tasks and entertainment activities on one device and continue them on
another. To meet your customers' needs, your apps need to seamlessly span devices and
platforms.
You can use the device relay APIs to deliver seamless experiences to your users. You can
make it possible for them to actively transfer an experience from one device to another
or enhance it by using multiple devices at once. This is done via in-app actions (a button
or selection in your app) that call the device relay API to discover users' devices, and
enable them to launch and message your app on those other devices.
You can use the device relay API for companion devices, or remote control scenarios.
Use the messaging capabilities to create an app channel between two devices to send
and receive custom messages. For example, you can enable your customers to use their
phone to control playback on a TV. You could also provide a companion app in a
productivity scenario by displaying context-based commonly used actions on a phone
while your users work on the main view of your app in the PC.
Your customers can also actively transfer an experience from one device to another by
performing an action in your app. For example, a user might be watching a live
broadcast on her phone while on the bus, but when she gets home she wants to transfer
playback to the PC in her living room. Productivity scenarios are also supported by
device relay.
See also
Cross-device experiences in Microsoft Graph
Learn more about the device relay API
Learn more about Project Rome
Build cross-device apps powered by
Project Rome
Article • 06/23/2022
You can use Project Rome to build experiences that cross devices and platforms
seamlessly, reducing friction for users and helping to drive app engagement. For
applications to share data across devices and platforms using Project Rome APIs, you
need to configure a cross-device app that includes information about your platform-
specific apps.
Pick up where you left off across devices with the activity feed API
You can configure a cross-device app to associate your apps for Windows, iOS, Android,
and the web so that the app on each platform can read and write user activities that are
published by any app in the group.
For example, a user is finishing up a press release on her PC at work before dinner with
friends. At the restaurant, she gets a notification from her boss about a typo that needs
to be fixed asap. She opens the app on her Android phone and sees a card showing the
press release she was editing earlier. She taps the card to open it so she can fix the
release immediately and get back to her friends.
With this cross-device app configuration in place, the user's activity feed is synchronized
across devices and platforms effortlessly so you can build experiences that help users
pick up important tasks where they left off from any app surface.
Choose the right screen at the right time with the device relay API
You can configure a cross-device app with push notification credentials for each of the
platforms your app is available on so that a command or notification can be delivered to
you on any device where you use the app, regardless of platform.
For example, a user is watching a video on the bus ride home from work. When she
arrives home, she taps the app to launch the video on her Xbox One so she can
continue watching on the big screen.
When you associate push notification credentials for each of the platforms where your
app is available with your cross-device app, the user's app can send commands across
devices, so you can build experiences that cross multiple screens or transition a
workflow from one device to another in real time.
Read and write user activities from all platforms using the activity feed API
Write user activities from all platforms (Windows, iOS, Android, web) using the
Project Rome SDKs.
If you only access these capabilities, you can host your cross-device app configuration
externally on your domain as a JSON file.
For example, an app developer with a suite of game apps might use a separate
subdomain for each of these to ensure that each app is only subscribed to the user
activities it can resume when reading data across devices and platforms. On the other
hand, an app developer with a suite of productivity apps designed to work together
might use a single domain for all of these so that any app is able to launch a member of
the suite across devices.
To assert your domain ownership for your cross-device app, you'll need to add a DNS
TXT entry for your domain with a unique value provided to you in the Dev Center. This
value is unique per cross-device app. To find the unique value for your app, sign in to
the Windows Dev Center and choose Cross-device experiences from the left menu to
start configuring a new cross-device app. After you give your new cross-device app a
name, select Verify your cross-device app domain from the submenu. This page will
display instructions with a unique value inline (for example, MS=95ff4557-813f-45a5-
b2f6-1f94170b979f). Make sure to copy the entire value including 'MS='.
You'll need to collect each of the platform-specific application IDs in order to associate
them with your cross-device app identity. Using the Windows Dev Center, you'll be able
to select from Universal Windows Platform apps associated with your developer
account, but you'll need to manually provide application IDs for any of your win32, iOS,
or Android apps and identify the primary URL for any associated web apps. You can
associate up to 10 IDs per platform.
windows_universal - Provide an AUMID for each UWP app. For details, see Find
the Application User Model ID of an installed app (Industry 8.1) and Application.
windows_win32 - Provide an AUMID for each app. For win32 apps, you'll need to
use a script to retrieve this information. For details, see For details, see Find the
Application User Model ID of an installed app (Industry 8.1).
android - For details, see Change the package name .
ios - For details, see Bundle and Required, localizable, and editable properties .
msa – Sign in to the Application registration portal . You can view the App
ID/client ID for any of your apps. Both Live SDK (hex values) and Converged app
IDs (GUIDs) are supported.
You can find your existing app ID/client IDs or provision new ones by signing in to the
Application registration portal with your developer account. When you sign in to the
portal, you can view the App ID/client ID for any of your apps. Both Live SDK (hex
values) and converged app IDs (GUIDs) are supported.
If you're building an application that will support Azure AD users, and you do not use a
converged application ID issued through the Application registration portal , you will
need to provide the GUID for the application ID of your Azure app. To find the GUID for
your tenant:
) Important
Windows Notification Service - See Registering your app and receiving the
credentials for your cloud service and the Application registration portal .
Apple Push Notification Service -See APNs Overview .
Google Cloud Messaging - See Firebase Cloud Messaging .
7 Note
For example, an app developer with a suite of game apps might use a separate
subdomain for each to ensure that each app is only subscribed to the user activities it
can resume when reading data across devices and platforms. An app developer with a
suite of productivity apps designed to work together might use a single domain for all
of these so that any app is able to launch a member of the suite across devices.
If you're using an externally hosted JSON file to manage your cross-device app, you
assert domain ownership by including your Microsoft account or Azure AD app IDs in
the cross-platform-app-identifiers file. Your domain ownership will be verified as part of
the publish process when you use the activity feed API to create user activities.
The system will cache the contents of the JSON file to avoid generating frequent
requests on your domain. If configured, the service will respect HTTP cache headers
when evaluating when to refresh the cache. If not configured, the service will refresh
every 24 hours.
You'll need to collect each of the platform-specific application IDs in order to associate
them with your cross-device app identity. Using an externally hosted JSON file, you'll
need to collect app IDs for each of the platform-specific apps to configure as part of
your cross-device app and assemble them into the specified format. You can associate
up to 10 IDs per platform.
The JSON file itself must be named cross-platform-app-identifiers and hosted at root
of your HTTPS domain. The contents of the file are a JSON array of mappings between
your application's supported platforms and the application IDs on those platforms.
When constructing the file, include a JSON object for each application and platform that
will use Project Rome APIs. The file will allow for multiple JSON objects with the same
platform identifier. For example, an iPhone app and an iPad app should be listed as
separate JSON objects, each with a platform value of iOS. The web platform identifier is
shown in the following example. You don't need to include a JSON object for all
platforms. Only include JSON objects for platforms where your application is using
Project Rome APIs. For example, if you don't have an app client for the Android
platform, you don’t need an entry in the file for Android. The following example
includes all the valid platform identifiers currently accepted. JSON objects that include
an invalid platform value will be stripped out.
{"platform":"windows_universal",
"application":"Microsoft.Contoso_8wekyb3d8bbwe"},
{"platform":"windows_win32",
"application":"DefaultBrowser_NOPUBLISHERID!Microsoft.Contoso.Default"},
{"platform":"android","application":"com.example.myapp"},
{"platform":"ios", "application":"com.example.myapp"},
{"platform":"web", "application":"https://contoso.com"},
{"platform":"web", "application":"https://chat.contoso.com"},
{"platform":"msa", "application":"00000000603E0BF"},
{"platform":"msa", "application":"48932b46-98b1-4020-9be4-cc7a65643c9e"},
]
windows_universal - Provide an AUMID for each UWP app. For details, see Find
the Application User Model ID of an installed app (Industry 8.1) and Application.
windows_win32 - Provide an AUMID for each app. For win32 apps, you'll need to
use a script to retrieve this information. For details, see For details, see Find the
Application User Model ID of an installed app (Industry 8.1).
android - For details, see Change the package name .
ios - For details, see Bundle and Required, localizable, and editable properties .
msa – Sign in to the Application registration portal . You can view the App
ID/client ID for any of your apps. Both Live SDK (hex values) and Converged app
IDs (GUIDs) are supported.
{"platform":"windows_universal",
"application":"Microsoft.Contoso_8wekyb3d8bbwe"},
{"platform":"windows_win32",
"application":"DefaultBrowser_NOPUBLISHERID!Microsoft.Contoso.Default"},
{"platform":"android","application":"com.example.myapp"},
{"platform":"ios", "application":"com.example.myapp"},
{"platform":"web", "application":"https://contoso.com"},
{"platform":"web", "application":"https://chat.contoso.com"},
{"platform":"msa", "application":"00000000603E0BF"},
{"platform":"msa", "application":"48932b46-98b1-4020-9be4-cc7a65643c9e"},
]
You can find your existing app ID/client IDs or provision new ones by signing in to
the Application Registration Portal with your developer account. When you sign in,
you can view the App ID/client ID for any of your apps. Both Live SDK (hex values) and
converged app IDs (GUIDs) are supported. Use the platform type "msa" when you add
the IDs used to enable support for a Microsoft account or Azure AD, as shown in the
previous example.
7 Note
If you're building an application that supports Azure AD users, and you do not use
a converged application ID issued through the Application Registration Portal ,
you will need to provide the GUID for the application ID of your Azure app. This
type of ID should also be configured as platform type "msa".
If you're not seeing activities resume in the correct native applications across platforms,
or you're unable to read activities published by all members in the group, your JSON file
might not be getting parsed appropriately. When outputting this file, make sure you're
saving the cross-platform-app-identifiers file with "Unicode (UTF-8 without signature) -
Codepage 65001" encoding.
Troubleshooting
The following are some common issues that can occur with the activity feed API.
Activities are not available to read and write for all apps
in the cross-device app configuration
The activity feed API ingests the cross-device app configuration asynchronously, so
configuration errors might not be readily apparent when publishing user activities. In
the event the service fails to ingest the JSON file, either due to TLS or formatting error,
any activities that have been published will be attributed to the app ID that posted the
activity, only. In the case of activities published via Microsoft Graph, this is the Microsoft
account app ID used to authorize requests to Microsoft Graph. In the case of activities
published via client-side APIs, the activity.applicationId will record the ID of the
platform-specific app that posted the activity, only. This will prevent read and write
operations on activities from any other platform-specific apps identified in the cross-
device app configuration.
Microsoft Bookings provides online and mobile apps that make appointment scheduling
simple and efficient for businesses and their customers. Any organization that provides
service on an appointment basis, such as large scale enterprise companies, auto repair
shops, hair salons, and law firms, can benefit from having their bookings managed so as
to free up time for the more important task to grow their business. Microsoft Bookings
is available to enterprise organizations and businesses that have a Microsoft 365
Business Premium subscription.
Business operators can take bookings anywhere, on the web or a mobile app, in-person
or on the phone. They can reschedule, cancel, or re-assign an existing booking to
another available staff member.
API reference
Looking for the API reference for this service? See Microsoft Bookings API in Microsoft
Graph.
See also
Microsoft Bookings for Microsoft 365
Other Microsoft 365 business apps
Business rules for Bookings
appointments
Article • 06/22/2022
End users or apps who create or update appointments via Microsoft Graph APIs (using
application permissions) must adhere to business rules to prevent unforeseen errors.
If you use the create or update appointment APIs with application permissions, you
must follow the business rules described in this article.
Business-level settings
Follow these business rules for business-level settings.
Business hours
Use the Update bookingBusiness API to modify businessHours. Note that an
appointment can't be set outside the business hours.
Scheduling policy
For details about the scheduling policy, see bookingSchedulingPolicy.
Time increments (Time slot interval) indicates the duration of an appointment. While
validating business rules, make sure that an appointment is for the same duration as
indicated in the service.
Minimum lead time indicates the minimum time before an appointment can be made
or cancelled.
Maximum Lead time indicates the maximum time before an appointment can be made.
Allow staff selection is if a user wants to pass staff members via the appointment API,
they should set the allowStaffSelection attribute in BookingSchedulingPolicy resource
type to true.
7 Note
Service-level settings
Follow these business rules for service-level settings.
Scheduling
At a service level, the scheduling policy is inherited from the business. The customer
might choose to override the policies.
Main policy
If a scheduling policy exists at both the service level and the business level, the service-
level policy takes precedence.
Pre-buffer
This is the extra time needed for an appointment before a following appointment. In the
staff member calendar, the appointment is of duration "pre-buffer time" +
"appointment slot time".
Post-buffer
This is the extra time needed for an appointment after a previous appointment. In the
staff member calendar, the appointment is of duration "appointment slot time" + "post
buffer time".
See also
Microsoft Bookings API overview
Microsoft Bookings API in Microsoft Graph
Use the Edge API in Microsoft Graph to
manage browsers
Article • 11/29/2022
The Microsoft 365 admin center lets administrators manage applications, services,
data, devices, and users across Microsoft 365 services in an organization. Microsoft Edge
is one of the applications that administrators manage through the admin center.
API reference
Looking for the API reference for this service?
Next steps
Find out more about the use cases of the Edge API in Microsoft Graph.
Universal Print cloud printing API
overview
Article • 06/22/2022
Universal Print is a modern print solution that organizations can use to manage their
print infrastructure through cloud services from Microsoft.
Manage printers
Keeping track of an organization's printers, printer configurations, and printer usage is a
complex task. The Universal Print API enables integration in all three areas.
See who's using your printers and how much they're printing by using the
reporting APIs:
List dailyPrintUsageByUser
List monthlyPrintUsageByUser
List dailyPrintUsageByPrinter
List monthlyPrintUsageByPrinter
Sharing a printer creates a printerShare resource that can be updated at any time to
point to a different printer, making it easy to replace broken printer hardware or take
printers offline for maintenance.
To use this in your application, use Update printerShare to update the printerShare's
printer reference.
These triggers enable your application to interrupt the print workflow to do things such
as redirecting jobs to different printers and modifying the document payload.
3. Update the attributes of your virtual printer by using application permissions and
an application/ipp media type (see examples).
4. Create a task trigger for your virtual printer using an administrator authentication
token that will associate your task definition with virtual printer. The appId used to
generate the access token should be the same appId that was used to create the
task definition.
5. When a print job is submitted to the virtual printer, it will be paused due to the
printTaskTrigger. A printTask with processing state will be created based on the
associated printTaskDefinition.
6. When the user swipes a badge at a physical printer device, the printer will notify
your application. At that time, your application can fetch the jobs of the associated
virtual printer and filter the list to jobs created by the current user.
7. When the user selects one or more jobs to print, your application can redirect the
print job(s) to the physical printer and the job will start printing! The redirect call
will only succeed if there is a printTask in processing state on the associated
printer started by a trigger that this app created in step 4. The task will
automatically be set to completed state after redirecting it.
API reference
Looking for the API reference for this service?
Provide feedback
We'd love to hear your feedback about the Universal Print APIs. Provide your
suggestions on the Microsoft 365 Developer Platform ideas forum .
See also
What is Universal Print
Upload documents using the Microsoft
Graph Universal Print API
Article • 07/19/2022
To print a document using the Universal Print API in Microsoft Graph, you create a print
job, upload a document, and then start the print job. This article describes how to
upload a document, which starts with creating an upload session.
To upload a file, or a portion of a file, your app makes a PUT request to the uploadUrl
value received in the createUploadSession response. You can upload the entire file, or
split the file into multiple byte ranges, as long as the maximum bytes in any given
request is less than 10 MB.
The segments of the file can be uploaded in any order and can be uploaded in parallel,
with up to four concurrent requests. When all the binary segments of a document are
uploaded, the binary file is linked to the printDocument.
Note: If your app splits a file into multiple byte ranges, we recommend that the size
of each byte range is a multiple of 200 KB unless you're using the Microsoft Graph
SDK, which requires the segment size to be a multiple of 320 KB.
Upload a file
Request
Make a PUT request to the uploadUrl value received in the createUploadSession
response.
Request headers
Name Description
Content-Length {contentLength}Required.
Request body
The request body is a binary blob containing the bytes of the document that are
specified as an inclusive byte range in the Content-Range header.
Example
HTTP
PUT https://print.print.microsoft.com/uploadSessions/5400be13-5a4e-4c20-
be70-90c85bfe5d6e?tempauthtoken={token}
Content-Range: bytes=0-72796/4533322
Content-Length: 72797
Here, 0 and 72796 are the start and end indexes of the file segment and 4533322 is the
size of document.
Response
When the request is complete, the server will respond with 202 Accepted if there are
more byte ranges that need to be uploaded.
HTTP
{
"expirationDateTime": "2020-10-25T02:19:38.1694207Z",
"nextExpectedRanges": ["72797-4533321"]
}
Your app can use the nextExpectedRanges value to determine where to start the next
byte range. You might see multiple ranges specified, indicating parts of the file that the
server has not yet received. The nextExpectedRanges property indicates ranges of the
file that have not been received and not a pattern for how your app should upload the
file.
HTTP
{
"expirationDateTime": "2020-10-25T02:19:38.1694207Z",
"nextExpectedRanges": [
"72797-72897",
"78929-4533322"
]
}
Remarks
On failures, when the client sends a fragment the server has already received, the
server will respond with HTTP 416 Requested Range Not Satisfiable . You can
request upload status to get a more detailed list of missing ranges.
Including the Authorization header when making the PUT call might result in an
HTTP 401 Unauthorized response. The Authorization header and bearer token
should only be sent when creating the upload session. It should be not be included
when uploading data to the upload session.
printDocument.
Request
HTTP
PUT https://print.print.microsoft.com/uploadSessions/5400be13-5a4e-4c20-
be70-90c85bfe5d6e?tempauthtoken={token}
Content-Length: 10
Content-Range: bytes 4533312-4533321/4533322
Response
HTTP
{
"id": "9001bcd9-e36a-4f51-bfc6-140c3ad7f9f7",
"documentName": "TestFile.pdf",
"contentType": "application/pdf",
"size": 4533322
}
Note: The upload session is deleted after the document upload is complete.
Request
HTTP
GET https://print.print.microsoft.com/uploadSessions/5400be13-5a4e-4c20-
be70-90c85bfe5d6e?tempauthtoken={token}
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"expirationDateTime": "2020-10-25T02:19:38.1694207Z",
"nextExpectedRanges": [
"72797-72897",
"78929-4533322"
]
}
C#
Temporary files and their accompanying upload session are automatically cleaned up
after the expirationDateTime has passed.
Request
HTTP
DELETE https://print.print.microsoft.com/uploadSessions/5400be13-5a4e-4c20-
be70-90c85bfe5d6e?tempauthtoken={token}
Response
HTTP
Universal Print helps customers move their print infrastructure to the cloud, and is part
of a robust ecosystem of partner solutions that offer advanced print functionality. These
solutions can become even more powerful when you use the cloud printing APIs in
Microsoft Graph to integrate with Universal Print.
Many partner solutions need to process print jobs in real time as they're sent from users'
devices to printers, which means they need to be notified when print jobs are available
for processing. Universal Print provides hooks for print vendor solutions to be notified
as jobs move through the cloud, and APIs that enable management of printers and print
jobs.
This article describes how to subscribe to notifications for various print job events.
JobFetchable: After the job has started, third-party print applications or Universal
Print might do some processing (like converting XPS payload to PDF for a PDF
printer). After processing is complete and the payload is ready to be downloaded
by a printer, a JobFetchable event is raised for the corresponding print job.
7 Note
Permission scopes
To subscribe to notifications for print jobs, applications must have the following
permission scopes approved in the customer’s Azure AD tenant:
Applications must generate and use the Azure AD security token in the Microsoft Graph
API request header. The security token contains the claims as per the scopes approved
for the customer’s Azure AD tenant by its administrator.
A printTaskTrigger for each of the printer queues for which the partner wants to
receive a notification when a new print job starts. The printTaskTrigger needs to be
bound to the printTaskDefinition.
7 Note
One printer can be associated with only one printTaskTrigger and one
printTaskTrigger can be associated with only one printTaskDefinition. However,
one printTaskDefinition can have one or more printTaskTriggers associated with it.
With the printTaskDefinition that exists for customer’s Azure AD tenant, the application
can create a subscription for a printTask triggered (JobStarted) event using the
printTaskDefinition. While creating the subscription:
Request
The following is an example of the request.
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType":"created",
"resource":"print/taskDefinitions/{printTaskDefinition ID}/tasks",
"clientState":"secret",
"notificationUrl":"{URL for receiving the event – e.g.
https://webhookappexample.azurewebsites.net/api/notifications}",
"expirationDateTime":"2020-01-30T22:42:09Z"
}
Response
The following example shows the response.
HTTP
7 Note
Print jobs can't be modified when they enter the JobFetchable state. A
JobFetchable notification needs to be created for each printer queue. While
creating the subscription:
The expirationDateTime field needs to be less than the maximum expiration time.
For more details, see Subscription resource type properties.
Request
The following is an example of the request.
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType":"updated",
"resource":"print/printers/{printer id}/jobs",
"notificationQueryOptions": "$filter = isFetchable eq true",
"notificationUrl":"{URL for receiving the event – e.g.
https://webhookappexample.azurewebsites.net/api/notifications}",
"expirationDateTime":"2020-12-30T22:42:09Z",
"clientState":"mysecret"
}
Response
The following example shows the response.
HTTP
FAQs
See also
To learn more about the cloud printing API in Microsoft Graph, see Universal Print
cloud printing API overview.
For suggestions or feedback about the cloud printing API in Microsoft Graph, visit
the Universal Print tech community .
Intune devices and apps API overview
Article • 06/22/2022
Microsoft Intune helps enterprises manage devices and apps within an organization. You
can use the Intune API in Microsoft Graph to manage devices, apps, and even configure
Intune while using your preferred tools.
If you're an ISV, you can also use the Intune API to manage client tenants.
https://www.youtube-nocookie.com/embed/yU1HeqNmN7A
Manage devices
You can use the Intune API to:
Define and enforce device compliance policies, such as password complexity and
duration, encryption, threat protection levels, and so on. (Supported policies vary
according to operating system and version).
Protect company data, regardless of whether the device platform is Windows,
Android, Mac, or iOS.
Create and deploy device configuration policies, including operating system
platform/versioning, domain membership, and configuration setting management.
Create and deploy device access control policies, including restricted download,
network accessory access, and file transfer.
Perform remote actions, such as locate device, change password, and wipe device.
Manage apps
You can use the Intune API to perform the following app management tasks:
Automate Intune
Automate Intune by using the Intune API to:
API reference
Looking for the API reference for this service?
Next steps
Use Azure AD to access the Intune API.
See how to perform common tasks by using the PowerShell Intune samples .
Find out how to use the Intune REST API.
See the Changelog for information about what's new in the Intune API.
Explore resources for more ideas about how to use Microsoft Graph.
Overview for Windows 365 Cloud PC on
Microsoft Graph (preview)
Article • 06/22/2022
Windows 365 is a cloud-based service that provisions and hosts Cloud PCs as virtual
machines for end users. Administrators can easily set up, manage, and scale Windows
365 Cloud PCs to fit the organization's needs. Individual end users can securely stream
their rich, personalized Windows experience—including their apps, data, content, and
settings—from the Microsoft cloud to any device, any time, with their Windows 365
Cloud PC.
API reference
Looking for the API reference for the service?
Working with Windows 365 Cloud PCs using the Microsoft Graph API
Next step
Try out the Windows 365 Cloud PC APIs by using Graph Explorer.
Windows updates API overview
Article • 02/14/2023
The Windows Update for Business deployment service provides control over updates
through the ability to approve, schedule, and safeguard content delivered by Windows
Update to managed devices.
Today, the deployment service supports managing Windows feature updates, expediting
Windows security updates, and managing driver updates. To learn more about the
deployment service in the context of Windows Update for Business, see Overview of the
deployment service. To track the progress and status of your deployments, see Windows
Update for Business reports. This solution is integrated with the deployment service to
enable per deployment reporting, monitoring, and troubleshooting.
Prerequisites
To use the deployment service, your organization must have one of the following
subscriptions:
Feature updates
Feature updates add new features and functionality to Windows 10 and Windows 11.
You can use the deployment service to deploy a feature update of a supported Windows
OS version. When you successfully deploy a feature update to your devices, those
devices will be updated to the version specified in the deployment and stay at that
version until you target them with a new deployment that upgrades their current
operating system version. To deploy Windows 11, you can target current Windows 11
devices and Windows 10 devices that meet the Windows 11 minimum requirements .
Devices that don’t meet the requirements for Windows 11 won’t install the update and
will remain at their current Windows 10 version.
Quality updates
Quality updates released by Microsoft deliver both security and non-security fixes.
Windows Update for Business helps devices to take security updates through Expedite.
Security updates are typically released on the second Tuesday of each month, although
out-of-band security updates can be released at any time. Quality updates are
cumulative, so installing the latest quality update is sufficient to get all the available fixes
released for your specific operating system version.
Expedite Yes
Gradual rollout
Stage deployments over a period of days or weeks by specifying gradual rollout
settings. If you choose to deploy an update over a period of time, the deployment
service automatically optimizes the order in which devices are offered updates. When
possible, the service orders devices to ensure that a diversity of hardware and software
assets are represented early in the deployment, to minimize the number of devices that
might encounter an unexpected update issue.
Expedite
In the case of a critical security issue, you can use the deployment service to bypass a
standard update policy and expedite deployment of a security update.
Safeguard holds
Enjoy the benefit of safeguard holds that prevent devices with a quality or compatibility
issue from installing an update, resulting in failure or rollback otherwise. For
deployments of Windows 11, the deployment service extends these safeguard holds to
further protect devices. Microsoft uses machine learning algorithms to monitor the
breadth of the Windows ecosystem as devices upgrade to Windows 11. For devices that
are identified to be at a higher risk of experiencing a post-upgrade issue, the
deployment service applies early safeguards to protect these devices while the issue is
investigated and confirmed.
Additionally, you can configure monitoring rules that are unique to your organization.
These rules can send an alert or pause a deployment based on device signals such as
rollbacks.
API reference
Looking for the API reference for this service?
Software updates are the primary type of content the deployment service deploys. You
can look in a catalog to find specific updates that are available to deploy.
You might already be familiar with the Microsoft Update Catalog , which lists software
updates for Windows. The deployment service provides its own catalog, and aggregates
equivalent updates under a single catalogEntry to simplify decision making and
approval workflows.
The deployment service catalog also categorizes updates as feature, quality, and driver
updates. Quality update catalog entries define security and non-security updates in a
specific way and exclude driver updates. Note that the definition is different from the
Microsoft Update Catalog. See quality updates below for more details.
Effectively, the deployment service currently deploys only feature updates, security
quality updates, and driver updates as defined in its catalog. The service currently does
not deploy non-security quality updates.
To learn more about Windows 10 updates and servicing, see Quick guide to Windows as
a service.
For example, the following two security quality updates are considered different releases
in the Microsoft Update Catalog, even though they differ only by architecture.
2021-03 Cumulative Update for Windows 10 Version Windows 10, version Security
20H2 for x86-based Systems (KB5000802) 1903 and later Updates
Title Products Classification
2021-03 Cumulative Update for Windows 10 Version Windows 10, version Security
20H2 for x64-based Systems (KB5000802) 1903 and later Updates
In the catalog provided by the Windows Update for Business deployment service, these
updates are aggregated into a single entry.
This aggregation simplifies the process of approving updates across a diverse installed
base. Similarly, the deployment service rolls up feature update releases.
Common properties
All updates in the deployment service catalog have the following common properties.
Property Description
deployableUntilDateTime Date and time until the update can no longer be deployed, if known.
Feature updates
Feature updates in the deployment service catalog are identified by version. Entries
aggregate differences across architecture (for example, x86 vs. x64) and product (in the
Microsoft Update Catalog, all feature updates are for the Windows 10 product).
Property Description
Below are some examples of feature updates in the deployment service catalog.
Quality updates
Quality updates in the deployment service catalog are identified by a release date/time
and an update classification. Entries aggregate differences across architecture, product
(e.g. Windows 10, version 1903 and later vs. Windows 10 vs. Windows 10 LTSB), and
corresponding feature update version.
Property Description
The following table shows the classification mapping between the deployment service
catalog and the Microsoft Update Catalog.
Non-security Update
Servicing Stack Update
The entries from the Microsoft Update Catalog corresponding to a quality update in the
deployment service catalog with classification = security and releaseDateTime =
2021-03-09 might include the following.
2021-03 Cumulative Update for Windows 10 Version Windows 10, version Security
20H2 for x86-based Systems (KB5000802) 1903 and later Updates
Title Products Classification
2021-03 Cumulative Update for Windows 10 Version Windows 10, version Security
20H2 for x64-based Systems (KB5000802) 1903 and later Updates
2021-03 Cumulative Update for Windows 10 Version Windows 10, version Security
1909 for x86-based Systems (KB5000808) 1903 and later Updates
Once you have identified the desired update, assign it as content to a deployment using
catalogContent.
Examples
To see examples of listing catalog entries, see Deploy a feature update and Deploy an
expedited security update.
Deployments in the Windows Update
for Business deployment service
Article • 02/03/2023
Deployments are the foundation of the Windows Update for Business deployment
service. Through a deployment you can target a set of devices to receive specific
content from Windows Update, such as a software update.
1. Content: The update available to deploy from the catalog. This is represented by
the content property of the deployableContent type.
2. Audience: The devices to receive content. This is an audience relationship of the
deploymentAudience type.
3. Policy: The entity that governs the deployment of content to an associated
deployment audience. This is a policy relationship of the updatePolicy type.
4. Settings: The settings governing how and when content should be delivered to
devices. This is represented by the settings property of the deploymentSettings
type.
5. State: The current state of the deployment within its lifecycle. This is represented
by the state property of the deploymentState type.
To learn more about creating a deployment, see Deploy a feature update, Deploy an
expedited security update, and Manage driver update.
Configure settings
Schedule
Schedule settings govern how the content is deployed over time to devices in the
deployment audience. You can configure schedule settings for deployments of feature
updates.
Monitoring
You can use monitoring settings to configure alerts and automated actions to take
based on update signals from devices. Monitoring settings can be configured for
deployments of feature updates.
User experience
For deployments of expedited quality updates, user experience settings temporarily
override existing policies on the device for update experience.
To learn more about user experience settings, see Deploy an expedited security update.
States
Deployments move through lifecycle states as described in the following table.
State Description
scheduled The deployment is waiting for offer conditions to be met to start offering the update
to devices.
paused The deployment is paused and prevented from offering the update to devices until it
is unpaused.
faulted The deployment is not offering the update to devices due to a reason the service
cannot resolve.
Transitions
Transition Condition
offering , scheduled , or paused → There is an error that the service cannot resolve.
faulted
Resource model
The deployment resource has a state property of type deploymentState which provides
information about the current lifecycle state.
The service determines the effective value of the deployment state as a net result of
several inputs and asynchronous processes, but you can request a particular value by
setting requestedValue as one of these inputs. Other inputs to the effective deployment
state value include schedule settings and monitoring settings.
When you assign a device to two deployments for content of different update
categories (for example, a feature update and an expedited quality update), the
deployment service offers content in a sequence according to Microsoft’s
recommendation.
When you assign a device to two deployments for content of the same update category
(for example, feature update versions 20H1 and 20H2, or quality updates from March
2021 and April 2021, or driver version 1.0.0.0 published January 2023 and 1.0.0.1
published February 2023), the deployment service offers the content that is higher
ranked by Microsoft. For feature updates and quality updates, more recent updates are
higher ranked. For driver updates, applicable updates are typically ranked by version
and publication date. This behavior does not apply if one of the deployments is still
scheduled for the device and is not ready to offer content. In that case, the other
deployment delivers content to the device.
Enroll in update management by the
Windows Update for Business
deployment service
Article • 02/03/2023
When you enroll a device in update management by the Windows Update for Business
deployment service, you can use the deployment service to manage content delivered
from Windows Update to that device. You can enroll a device in update management by
update category.
The following example shows how to enroll a device in feature update management.
Request
HTTP
POST
https://graph.microsoft.com/beta/admin/windows/updates/updatableAssets/enrol
lAssets
Content-Type: application/json
{
"updateCategory": "feature",
"assets": [
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "String (identifier)"
},
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "String (identifier)"
},
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "String (identifier)"
}
]
}
Response
HTTP
Request
HTTP
GET
https://graph.microsoft.com/beta/admin/windows/updates/updatableAssets/983f0
3cd-03cd-983f-cd03-3f98cd033f98
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"value": {
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "983f03cd-03cd-983f-cd03-3f98cd033f98",
"errors": [],
"enrollments": [
{
"@odata.type":
"microsoft.graph.windowsUpdates.updateManagementEnrollment",
"updateCategory": "feature"
}
]
}
}
Request
HTTP
POST
https://graph.microsoft.com/beta/admin/windows/updates/updatableAssets/unenr
ollAssets
Content-Type: application/json
{
"updateCategory": "feature",
"assets": [
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "String (identifier)"
}
]
}
Response
HTTP
You can unregister a device from the service completely by deleting the device object.
When a device is unregistered, it is automatically unenrolled from management by the
service for all update categories and removed from every deploymentAudience and
updatableAssetGroup.
Request
HTTP
DELETE
https://graph.microsoft.com/beta/admin/windows/updates/updatableAssets/{azur
eADDeviceId}
Response
HTTP
With the Windows Update for Business deployment service, you can deploy Windows
updates to devices in an Azure AD tenant. Today, the deployment service supports
deployments of Windows 10/11 feature updates, expedited security updates, and driver
updates. This topic focuses on deployments of feature updates. For information on
deploying expedited security updates, see Deploy an expedited security update. For
infomation about deploying driver updates, see Manage driver update.
When you deploy a feature update to a device, Windows Update offers the specified
update to the device if it has not yet received the update. For example, if you deploy
Windows 10 feature update version 20H2 to a device that is enrolled in feature update
management and is currently on an older version of Windows 10, the device updates to
version 20H2. If the device is already at or above version 20H2, it stays on its current
version. If the device is not enrolled in feature update management, the device is not
affected by this operation.
As long as a device remains enrolled in feature update management, the device does
not receive any other feature updates from Windows Update unless explicitly deployed
using the deployment service.
) Important
By using the Windows Update for Business deployment service to upgrade devices
to Windows 11 (by setting the version paramater of a deployment to "Windows 11,
version 21H2"), you are agreeing that when applying this operating system to a
device either (1) the applicable Windows license was purchased though volume
licensing, or (2) that you are authorized to bind your organization and are
accepting on its behalf the relevant Microsoft Software License Terms to be found
here: Microsoft Software License Terms .
Prerequisites
Devices meet the prerequisites for the deployment service.
Before you can use the deployment service to deploy feature updates, devices
must be enrolled in management by the deployment service for the feature update
category.
Below is an example of querying for all Windows 10 feature updates that are deployable
by the deployment service.
Request
HTTP
GET https://graph.microsoft.com/beta/admin/windows/updates/catalog/entries?
$filter=isof('microsoft.graph.windowsUpdates.featureUpdateCatalogEntry')
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"value": [
{
"@odata.type":
"#microsoft.graph.windowsUpdates.featureUpdateCatalogEntry",
"id": "560a186a-1434-4364-8330-deb944b494ff",
"displayName": "Windows 10, version 20H2",
"releaseDate": "String (timestamp)",
"deployableUntilDateTime": "String (timestamp)",
"version": "20H2"
},
{
"@odata.type":
"#microsoft.graph.windowsUpdates.featureUpdateCatalogEntry",
"id": "5e436dae-56bd-4925-bf8b-acf550e07227",
"displayName": "Windows 10, version 2004",
"releaseDate": "String (timestamp)",
"deployableUntilDateTime": "String (timestamp)",
"version": "2004"
}
]
}
Request
HTTP
POST https://graph.microsoft.com/beta/admin/windows/updates/deployments
Content-type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
"catalogEntry": {
"@odata.type":
"#microsoft.graph.windowsUpdates.featureUpdateCatalogEntry",
"id": "cd45877c-87a9-4ed1-b184-fd89230207b1"
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"schedule": {
"gradualRollout": {
"@odata.type":
"#microsoft.graph.windowsUpdates.rateDrivenRolloutSettings",
"durationBetweenOffers": "P7D",
"devicePerOffer": 100
}
},
"monitoring": {
"monitoringRules": [
{
"signal": "rollback",
"threshold": 5,
"action": "pauseDeployment"
}
]
}
}
}
Response
HTTP
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"id": "b5171742-1742-b517-4217-17b5421717b5",
"state": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentState",
"value": "offering",
"reasons": [],
"requestedValue": "none",
"effectiveSinceDate": "String (timestamp)"
},
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent"
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"schedule": {
"gradualRollout": {
"@odata.type":
"#microsoft.graph.windowsUpdates.rateDrivenRolloutSettings",
"durationBetweenOffers": "P7D",
"devicePerOffer": 100
}
},
"monitoring": {
"monitoringRules": [
{
"@odata.type":
"#microsoft.graph.windowsUpdates.monitoringRule",
"signal": "rollback",
"threshold": 5,
"action": "pauseDeployment"
}
]
},
"userExperience": null
},
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}
Step 3: Assign devices to the deployment
audience
After a deployment is created, you can assign devices to the deployment audience. After
the deployment audience is successfully updated, Windows Update starts offering the
update to the relevant devices according to the deployment settings.
Devices are automatically registered with the service when added to the members or
exclusions collections of a deployment audience (that is, an azureADDevice object is
automatically created if it does not already exist).
The following example shows how to add Azure AD devices as members of the
deployment audience.
Request
HTTP
POST
https://graph.microsoft.com/beta/admin/windows/updates/deployments/{deployme
ntId}/audience/updateAudience
Content-type: application/json
{
"addMembers": [
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "String (identifier)"
},
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "String (identifier)"
},
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "String (identifier)"
}
]
}
Response
HTTP
After a deployment
After all devices assigned to a deployment audience have been initially offered the
update, it is possible that not all devices have started or completed the update, due to
factors like device connectivity. As long as the deployment still exists, Windows Update
continues to offer the update to the assigned devices whenever they reconnect.
Deploy an expedited security update
using the Windows Update for Business
deployment service
Article • 02/03/2023
With the Windows Update for Business deployment service, you can deploy Windows
updates to devices in an Azure AD tenant. Today, the deployment service supports
deployments of Windows 10/11 feature updates, expedited security updates, and driver
updates. This topic focuses on deployments of expedited security updates. For
information about deploying feature updates, see Deploy a feature update. For
infomation about deploying driver updates, see Manage driver update.
Expediting a security update overrides Windows Update for Business deferral policies so
that the update is installed as quickly as possible. It can be useful when critical security
events arise and you need to deploy the latest updates more rapidly than normal.
However, while it can help to achieve compliance targets against a specific security
update, it is not designed to be used every month. Instead, consider using compliance
deadlines for updates.
When you deploy an expedited security update to a device, Windows Update offers the
latest applicable update to the device if it has not yet received the update with the
specified release date. For example, if you deploy the Windows 10 security update
released on April 13, 2021 to a device that does not currently have the update, the
device receives an expedited update. If the device already has the specified update or
newer, it does not receive an expedited update.
The update starts right away rather than waiting for the next regular update scan,
which occurs once every 22 hours by default.
The update downloads and installs as quickly as possible.
The update process overrides configured device policy settings, such as days until
the device is forced to restart. After the expedited update is installed, the device
returns to the current policy settings.
Prerequisites
Devices meet the prerequisites for the deployment service.
Devices have installed the update described in KB4023057 - Update for Windows
10 Update Service components (or newer).
Below is an example of querying for all Windows 10 security updates that can be
deployed as expedited updates by the deployment service. Microsoft recommends to
only show the three most current updates, so the example includes $top=3 .
Request
HTTP
GET https://graph.microsoft.com/beta/admin/windows/updates/catalog/entries?
$top=3&$filter=isof('microsoft.graph.windowsUpdates.qualityUpdateCatalogEntr
y') and
microsoft.graph.windowsUpdates.qualityUpdateCatalogEntry/isExpeditable eq
true&$orderby=releaseDateTime desc
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"value": [
{
"@odata.type":
"#microsoft.graph.windowsUpdates.qualityUpdateCatalogEntry",
"id": "bd9554dc-2737-4e3c-b794-fa2b8b3f4a30",
"displayName": "MM/DD/YYYY - YYYY.MM B Security Updates for
Windows 10",
"releaseDateTime": "String (timestamp)",
"deployableUntilDateTime": null,
"isExpeditable": true,
"qualityUpdateClassification": "security"
},
{
"@odata.type":
"#microsoft.graph.windowsUpdates.qualityUpdateCatalogEntry",
"id": "68860630-c2d0-4dd2-8c4b-9b9737ee5081",
"displayName": "MM/DD/YYYY - YYYY.MM B Security Updates for
Windows 10",
"releaseDateTime": "String (timestamp)",
"deployableUntilDateTime": null,
"isExpeditable": true,
"qualityUpdateClassification": "security"
},
{
"@odata.type":
"#microsoft.graph.windowsUpdates.qualityUpdateCatalogEntry",
"id": "aa336b13-db33-4d94-89ea-90e43e4ad30b",
"displayName": "MM/DD/YYYY - YYYY.MM B Security Updates for
Windows 10",
"releaseDateTime": "String (timestamp)",
"deployableUntilDateTime": null,
"isExpeditable": true,
"qualityUpdateClassification": "security"
}
]
}
When you deploy an expedited security update to a device, Windows Update offers an
update that brings the device above the minimum compliance level specified.
Depending on when each device scans and updates, some devices may receive newer
updates (e.g. if there is a newer security update than the one corresponding to the
desired minimum compliance level), but all devices meet the specified security update
compliance standard. This behavior of offering the latest applicable update, indicated by
the property equivalentContent being set to the default value latestSecurity , helps
keep devices as secure as possible and prevents a device from receiving an expedited
update followed by another regular update just days later.
You can configure the device restart grace period using the property
daysUntilForcedReboot in the user experience settings of the deployment. The grace
period sets the amount of time after installation that the user can control the timing of
when the device restarts. If the device has not restarted by the time the grace period
expires, it restarts automatically.
Request
HTTP
POST https://graph.microsoft.com/beta/admin/windows/updates/deployments
Content-type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
"catalogEntry": {
"@odata.type":
"#microsoft.graph.windowsUpdates.qualityUpdateCatalogEntry",
"id": "catalog/entries/1"
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"expedite": {
"isExpedited": true
},
"userExperience": {
"daysUntilForcedReboot": 2
}
}
}
Response
HTTP
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment,
"id": "b5171742-1742-b517-4217-17b5421717b5",
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)",
"state": {
"effectiveValue": "offering",
"requestedValue": "none",
"reasons": []
},
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent"
},
"settings": {
"schedule": null,
"monitoring": null,
"contentApplicability": null,
"userExperience": {
"daysUntilForcedReboot": 2
},
"expedite": {
"isExpedited": true
}
}
}
Devices are automatically registered with the service when added to the members or
exclusions collections of a deployment audience (that is, an azureADDevice object is
automatically created if it does not already exist).
The following example shows how to add Azure AD devices as members of the
deployment audience.
Request
HTTP
POST
https://graph.microsoft.com/beta/admin/windows/updates/deployments/{deployme
ntId}/audience/updateAudience
Content-type: application/json
{
"addMembers": [
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "String (identifier)"
},
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "String (identifier)"
},
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "String (identifier)"
}
]
}
Response
HTTP
During a deployment
While a deployment is in progress, you can pause the deployment by updating its state,
as well as update its audience members and exclusions.
After a deployment
After all devices assigned to a deployment audience have been initially offered the
update, it is possible that not all devices have started or completed the update, due to
factors like device connectivity. As long as the deployment still exists, it continues to
make sure that Windows Update is offering the update to the assigned devices
whenever they reconnect.
Manage driver approvals using the
Windows Update for Business
deployment service
Article • 03/03/2023
With the Windows Update for Business deployment service, you can deploy Windows
updates to devices in an Azure AD tenant. Today, the deployment service supports
deployments of Windows 10 and Windows 11 feature updates, expedited security
updates, and driver updates. This topic focuses on managing the deployments of driver
updates. For information about deploying feature updates, see Deploy a feature update.
For information about deploying expedited security updates, see Deploy an expedited
security update.
When devices enrolled in the Windows Update for Business deployment service scan
Windows Update, the deployment service collects scan results of applicable drivers that
are better than what is currently installed on the device. The service then catalogs them
to be browsed, approved, and scheduled for deployment. Only content that has been
approved using the deployment service will be offered to devices as long as it remains
enrolled in driver management.
Prerequisites
Devices must meet the prerequisites for the deployment service.
Request
HTTP
POST
https://graph.microsoft.com/beta/admin/windows/updates/updatableAssets/enrol
lAssets
Content-Type: application/json
{
"updateCategory": "driver",
"assets": [
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "fb95f07d-9e73-411d-99ab-7eca3a5122b1"
},
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "fb95f07d-9e73-411d-99ab-7eca3a5122b2"
},
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "fb95f07d-9e73-411d-99ab-7eca3a5122b3"
}
]
}
Response
HTTP
The following example shows how to create a deployment audience. The targeted
devices are specified in the next step.
Request
HTTP
POST
https://graph.microsoft.com/beta/admin/windows/updates/deploymentAudiences
Content-Type: application/json
{
}
Response
HTTP
The following example shows how to add Azure AD devices as members of the
deployment audience.
Request
HTTP
POST
https://graph.microsoft.com/beta/admin/windows/updates/deploymentAudiences/f
660d844-30b7-46e4-a6cf-47e36164d3cb/updateAudience
Content-type: application/json
{
"addMembers": [
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "fb95f07d-9e73-411d-99ab-7eca3a5122b1"
},
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "fb95f07d-9e73-411d-99ab-7eca3a5122b2"
},
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "fb95f07d-9e73-411d-99ab-7eca3a5122b3"
}
]
}
Response
HTTP
The following example shows how to create an update policy and assign an existing
deployment audience to it.
Request
HTTP
POST https://graph.microsoft.com/beta/admin/windows/updates/updatePolicies
Content-type: application/json
{
"audience": {
"@odata.id": "f660d844-30b7-46e4-a6cf-47e36164d3cb1"
}
}
Response
HTTP
The following example shows how to get the inventory of driver updates available for
devices in an existing deployment audience.
Request
HTTP
GET
https://graph.microsoft.com/beta/admin/windows/updates/deploymentAudiences/f
660d844-30b7-46e4-a6cf-47e36164d3cb/applicableContent
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#admin/windows/updates/deployment
Audiences('f660d844-30b7-46e4-a6cf-47e36164d3cb')/applicableContent",
"value": [
{
"matchedDevices": [
{
"recommendedBy": [
"Microsoft"
],
"deviceId": "fb95f07d-9e73-411d-99ab-7eca3a5122b1"
}
],
"catalogEntry": {
"@odata.type":
"#microsoft.graph.windowsUpdates.driverUpdateCatalogEntry",
"id":
"5d6dede684ba5c4a731d62d9c9c2a99db12c5e6015e9f8ad00f3e9387c7f399c",
"displayName": "",
"deployableUntilDateTime": null,
"releaseDateTime": "",
"description": "",
"driverClass": "",
"provider": "",
"setupInformationFile": null,
"manufacturer": "",
"version": "",
"versionDateTime": ""
}
},
}
The following example shows how to add a content approval to an existing policy.
Request
HTTP
POST
https://graph.microsoft.com/beta/admin/windows/updates/updatePolicies/d7a892
08-17c5-4daf-a164-ce176b00e4ef/complianceChanges
Content-type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.contentApproval",
"content":{
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
"catalogEntry":{
"@odata.type":
"#microsoft.graph.windowsUpdates.driverUpdateCatalogEntry",
"id":
"5d6dede684ba5c4a731d62d9c9c2a99db12c5e6015e9f8ad00f3e9387c7f399c"
}
},
"deploymentSettings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"schedule": {
"startDateTime": "2023-02-14T01:00:00Z"
}
}
}
Response
HTTP
Request
HTTP
PATCH
https://graph.microsoft.com/beta/admin/windows/updates/updatePolicies/d7a892
08-17c5-4daf-a164-ce176b00e4ef/complianceChanges/dbf29574-ffd9-49cf-87f2-
f03629e596ba
Content-type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.contentApproval",
"isRevoked": true
}
Response
HTTP
Request
HTTP
POST
https://graph.microsoft.com/beta/admin/windows/updates/updatableAssets/unenr
ollAssets
Content-Type: application/json
{
"updateCategory": "driver",
"assets": [
{
"@odata.type": "#microsoft.graph.windowsUpdates.azureADDevice",
"id": "fb95f07d-9e73-411d-99ab-7eca3a5122b1"
}
]
}
Response
HTTP
When deploying an update using the deployment service, you can schedule the
deployment so that devices receive the update at a future date.
Request
HTTP
POST https://graph.microsoft.com/beta/admin/windows/updates/deployments
Content-type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
"catalogEntry": {
"@odata.type":
"#microsoft.graph.windowsUpdates.featureUpdateCatalogEntry",
"id": "catalog/entries/1"
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"schedule": {
"startDateTime": "2021-07-01T17:00:00Z",
}
}
}
Response
HTTP
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"id": "b5171742-1742-b517-4217-17b5421717b5",
"state": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentState",
"value": "offering",
"reasons": [
{
"@odata.type":
"microsoft.graph.windowsUpdates.deploymentStateReason",
"value": "offeringByRequest"
}
],
"requestedValue": "none",
"effectiveSinceDate": "String (timestamp)"
},
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"schedule": {
"startDateTime": "2021-07-01T17:00:00Z",
"gradualRollout": null
},
"monitoring": null,
"userExperience": null
},
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}
In this example, you configure a new deployment so that a new set of devices is offered
the update every week (durationBetweenOffers set to seven days), starting on July 1,
2021. All devices are offered the update before August 1, 2021.
Request
HTTP
POST https://graph.microsoft.com/beta/admin/windows/updates/deployments
Content-type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
"catalogEntry": {
"@odata.type":
"#microsoft.graph.windowsUpdates.featureUpdateCatalogEntry",
"id": "catalog/entries/1"
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"schedule": {
"startDateTime": "2021-07-01T17:00:00Z",
"gradualRollout": {
"@odata.type":
"#microsoft.graph.windowsUpdates.dateDrivenRolloutSettings",
"endDateTime": "2021-08-01T17:00:00Z",
"durationBetweenOffers": "P7D"
}
}
}
}
Response
HTTP
HTTP/1.1 201 Created
Content-Type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"id": "b5171742-1742-b517-4217-17b5421717b5",
"state": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentState",
"value": "offering",
"reasons": [
{
"@odata.type":
"microsoft.graph.windowsUpdates.deploymentStateReason",
"value": "offeringByRequest"
}
],
"requestedValue": "none",
"effectiveSinceDate": "String (timestamp)"
},
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"schedule": {
"startDateTime": "2021-07-01T17:00:00Z",
"gradualRollout": {
"@odata.type":
"#microsoft.graph.windowsUpdates.dateDrivenRolloutSettings",
"endDateTime": "2021-08-01T17:00:00Z",
"durationBetweenOffers": "P7D"
}
}
"monitoring": null,
"userExperience": null
},
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}
Request
HTTP
POST https://graph.microsoft.com/beta/admin/windows/updates/deployments
Content-type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
"catalogEntry": {
"@odata.type":
"#microsoft.graph.windowsUpdates.featureUpdateCatalogEntry",
"id": "catalog/entries/1"
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"schedule": {
"startDateTime": "2020-07-01T17:00:00Z",
"gradualRollout": {
"@odata.type":
"#microsoft.graph.windowsUpdates.rateDrivenRolloutSettings",
"durationBetweenOffers": "P7D",
"devicePerOffer": 100
}
}
}
}
Response
HTTP
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"id": "b5171742-1742-b517-4217-17b5421717b5",
"state": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentState",
"value": "offering",
"reasons": [
{
"@odata.type":
"microsoft.graph.windowsUpdates.deploymentStateReason",
"value": "offeringByRequest"
}
],
"requestedValue": "none",
"effectiveSinceDate": "String (timestamp)"
},
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"schedule": {
"startDateTime": "2020-07-01T17:00:00Z",
"gradualRollout": {
"@odata.type":
"#microsoft.graph.windowsUpdates.rateDrivenRolloutSettings",
"durationBetweenOffers": "P7D",
"devicePerOffer": 100
}
},
"monitoring": null,
"userExperience": null
},
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}
Manage safeguards using the Windows
Update for Business deployment service
Article • 02/03/2023
When you deploy updates with the deployment service, the service automatically
safeguards deployments by preventing devices with known or likely issues from being
offered the update by Windows Update.
The following example demonstrates how to create a deployment with all safeguards
applied.
Request
HTTP
POST https://graph.microsoft.com/beta/admin/windows/updates/deployments
Content-type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
"catalogEntry": {
"@odata.type":
"#microsoft.graph.windowsUpdates.featureUpdateCatalogEntry",
"id": "catalog/entries/1"
}
}
}
Response
HTTP
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"id": "b5171742-1742-b517-4217-17b5421717b5",
"state": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentState",
"value": "offering",
"reasons": [
{
"@odata.type":
"microsoft.graph.windowsUpdates.deploymentStateReason",
"value": "offeringByRequest"
}
],
"requestedValue": "none",
"effectiveSinceDate": "String (timestamp)"
},
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
}
},
"settings": null,
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}
Request
HTTP
POST https://graph.microsoft.com/beta/admin/windows/updates/deployments
Content-type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
"catalogEntry": {
"@odata.type":
"#microsoft.graph.windowsUpdates.featureUpdateCatalogEntry",
"id": "catalog/entries/1"
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"contentApplicability": {
"safeguard": {
"disabledSafeguardProfiles": [
{
"category": "likelyIssues"
}
]
}
}
}
}
Response
HTTP
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"id": "b5171742-1742-b517-4217-17b5421717b5",
"state": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentState",
"value": "offering",
"reasons": [
{
"@odata.type":
"microsoft.graph.windowsUpdates.deploymentStateReason",
"value": "offeringByRequest"
}
],
"requestedValue": "none",
"effectiveSinceDate": "String (timestamp)"
},
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"monitoring": null,
"schedule": null,
"userExperience": null,
"contentApplicability": {
"safeguard": {
"disabledSafeguardProfiles": [
{
"@odata.type":
"#microsoft.graph.windowsUpdates.safeguardProfile",
"category": "likelyIssues"
}
]
}
}
},
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}
Manage monitoring rules using the
Windows Update for Business
deployment service
Article • 02/03/2023
For deployments initiated by the deployment service, you can use a monitoring rule to
configure alerts and automated actions based on deployment signals.
Below is an example of creating a monitoring rule for a deployment at the same time as
creating the deployment.
Request
HTTP
POST https://graph.microsoft.com/beta/admin/windows/updates/deployments
Content-type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
"catalogEntry": {
"@odata.type":
"#microsoft.graph.windowsUpdates.featureUpdateCatalogEntry",
"id": "catalog/entries/1"
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"monitoring": {
"monitoringRules": [
{
"signal": "rollback",
"threshold": 5,
"action": "pauseDeployment"
}
]
}
}
}
Response
HTTP
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"id": "b5171742-1742-b517-4217-17b5421717b5",
"state": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentState",
"value": "offering",
"reasons": [
{
"@odata.type":
"microsoft.graph.windowsUpdates.deploymentStateReason",
"value": "offeringByRequest"
}
],
"requestedValue": "none",
"effectiveSinceDate": "String (timestamp)"
},
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent"
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"monitoring": {
"monitoringRules": [
{
"@odata.type":
"#microsoft.graph.windowsUpdates.monitoringRule",
"signal": "rollback",
"threshold": 5,
"action": "pauseDeployment"
}
]
},
"schedule": null,
"userExperience": null
},
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}
Request
HTTP
PATCH
https://graph.microsoft.com/beta/admin/windows/updates/deployments/b5171742-
1742-b517-4217-17b5421717b5
Content-Type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"monitoring": {
"monitoringRules": []
}
}
}
Response
HTTP
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"id": "b5171742-1742-b517-4217-17b5421717b5",
"state": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentState",
"value": "offering",
"reasons": [
{
"@odata.type":
"microsoft.graph.windowsUpdates.deploymentStateReason",
"value": "offeringByRequest"
}
],
"requestedValue": "none",
"effectiveSinceDate": "String (timestamp)"
},
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"monitoring": {
"monitoringRules": []
},
"schedule": null,
"userExperience": null
},
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}
Request
HTTP
PATCH
https://graph.microsoft.com/beta/admin/windows/updates/deployments/b5171742-
1742-b517-4217-17b5421717b5
Content-Type: application/json
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"monitoring": {
"monitoringRules": [
{
"signal": "rollback",
"threshold": 10,
"action": "pauseDeployment"
}
]
}
}
}
Response
HTTP
{
"@odata.type": "#microsoft.graph.windowsUpdates.deployment",
"id": "b5171742-1742-b517-4217-17b5421717b5",
"state": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentState",
"value": "offering",
"reasons": [
{
"@odata.type":
"microsoft.graph.windowsUpdates.deploymentStateReason",
"value": "offeringByRequest"
}
],
"requestedValue": "none",
"effectiveSinceDate": "String (timestamp)"
},
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent",
}
},
"settings": {
"@odata.type": "microsoft.graph.windowsUpdates.deploymentSettings",
"monitoring": {
"monitoringRules": [
{
"@odata.type":
"#microsoft.graph.windowsUpdates.monitoringRule",
"signal": "rollback",
"threshold": 10,
"action": "pauseDeployment"
}
]
},
"schedule": null,
"userExperience": null
},
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}
Manage multiple customer tenants
using the Microsoft 365 Lighthouse API
Article • 10/28/2022
Microsoft 365 Lighthouse is an admin portal that lets Managed Service Providers (MSPs)
remotely manage multiple customer tenants. It helps MSPs secure and manage devices,
data, and users at scale for small- and medium-sized business (SMB) customers who are
using Microsoft 365 Business Premium.
Microsoft 365 Lighthouse helps MSPs simplify onboarding of Microsoft 365 Business
Premium customer tenants. It offers an MSP the convenience of multi-tenant views
across all its customer tenant environments. It can recommend security configuration
baselines tailored to the MSP's SMB customers. With Microsoft 365 Lighthouse, MSPs
can scale the management of their customer tenants, focus on what's most important,
quickly find and investigate risks, and take action to help get their customer tenants to a
healthy and secure state.
7 Note
Devices
You can use the Lighthouse API to perform the following device tasks:
Gain insight to the state of malware that is present on the Windows devices
registered for management across your customers.
View the protection state for Windows devices registered for management across
your customers to ensure those using Windows Defender are in a healthy state.
Users
You can use the Lighthouse API to perform the following user tasks:
API reference
Looking for the API reference for this service?
7 Note
Next steps
Learn more about the Microsoft 365 Lighthouse portal.
Find out about the latest new features and updates for the Lighthouse API.
Explore examples for more ideas about how to use Microsoft Graph.
Access service health and
communications in Microsoft Graph
Article • 06/22/2022
You can use the service communications API in Microsoft Graph to access the health
status and message center posts about Microsoft cloud services. The actual health status
and posts correspond to the Microsoft 365 and Dynamics 365 services that are
supported by the API and subscribed by the tenant.
Customers can regularly review message center posts to keep track of upcoming new
features and updates, and other important announcements. They can then anticipate
how these changes may affect users and plan accordingly.
Apps can enable custom workflows for administrators to review, assign, and triage
change communications from the message center.
Service health
Message center
Next steps
Try service communications sample queries in Graph Explorer.
The education API in Microsoft Graph enhances Microsoft 365 resources with
information that is relevant for education scenarios, including information about
schools, classes, users (students and teachers), assignments, and submissions. This
makes it easy for you to build solutions that integrate with educational resources for
various school and classroom scenarios.
https://www.youtube-nocookie.com/embed/EnDM7KMTEqQ
Microsoft School Data Sync , combined with roster APIs, addresses this challenge for
application developers and schools. The following are some of the scenarios that the
roster APIs enable:
With the assignment API, your app can interact with the assignment service outside of
Microsoft Teams. Microsoft Teams will handle distribution, due dates, and grading while
your system can provide a rich learning experience to students.
The following are examples of a few scenarios enabled by the assignments API:
School Data Sync management APIs support end-to-end scenarios for managing sync;
for example:
API reference
Looking for the API reference for this service?
Education API in Microsoft Graph v1.0
Education API in Microsoft Graph beta
Next steps
To start using the education APIs, see:
Rubrics are an effective and widely-used way of grading assignments, and the education
API in Microsoft Graph supports them.
Level Level
Good Poor
Argument The essay's argument is persuasive. The essay's argument does not make
sense.
Spelling and The essay uses proper spelling and The essay has numerous errors in
grammar grammar with few or no errors. spelling and/or grammar.
Grading using a rubric involves selecting one level for each quality in the rubric.
A rubric may have points associated with each level, and a weight associated with each
quality. If present, weights must add up to 100.
Argument (weight The essay's argument is persuasive. The essay's argument does not
50) make sense.
Spelling and The essay uses proper spelling and The essay has numerous errors in
grammar (weight grammar with few or no errors. spelling and/or grammar.
50)
API reference
To begin using rubrics, start with the educationRubric resource in Microsoft Graph and
associated methods.
Upload files for education assignments and
submissions using the Microsoft Graph API
Article • 06/22/2022
Resources are an integral part of education assignments and submissions. Teachers determine
the resources to upload to an assignment folder, and students determine the resources to
upload to a submission folder.
This article describes how to use the education API in Microsoft Graph to upload files to an
assignment or submission folder.
Prerequisites
Before you can upload files, set up a SharePoint folder to which to upload the files for a given
education assignment or submission resource.
Upload a resource
The setUpResourcesFolder API returns a model that contains the resourcesFolderUrl property.
HTTP
{
...
"resourcesFolderUrl":
"https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4w
bOp_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJRQLVYT24IWWFAJHMRRNYCB3GFA"
...
}
The following steps describe how to upload a resource/file to a relevant resource folder.
resourcesFolderUrl property.
HTTP
https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wb
Op_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJRQLVYT24IWWFAJHMRRNYCB3GE2:/MyPictureFile.p
ng:/content
Step 2 - Upload the resource to SharePoint
Make a PUT request with the upload URL to upload the content.
The contents of the request body should be the binary stream of the file to be uploaded.
For more details, see Upload large files with an upload session.
Request
The following example shows the request.
HTTP
PUT
https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wb
Op_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJRQLVYT24IWWFAJHMRRNYCB3GE2:/MyPictureFile.p
ng:/content
Content-Type: text/plain
Response
The following example shows the response.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#drives('b%216SQl0y4WHkS2P5MeIsSGpKwfyn
EIaD1OvPVeH4wbOp_1uyhNwJMSSpseJneB7Z4F')/items/$entity",
"@microsoft.graph.downloadUrl": "...",
"createdDateTime": "2021-03-11T18:49:47Z",
"eTag": "\"{EDD00CE7-B74C-4C3E-BA3E-484CB41EF31D},1\"",
"id": "01YT2AIJU7DAXTU6XLOJGYWYMTGM5JT5UQ",
"lastModifiedDateTime": "2021-03-11T18:49:47Z",
"name": "MyPictureFile.png",
"webUrl":
"https://contososdorg.sharepoint.com/sites/GraphTest/Class%20Files/Assignments/Tes
t%20File%20Distribution/MyPictureFile.png",
"cTag": "\"c:{EDD00CE7-B74C-4C3E-BA3E-484CB41EF31D},2\"",
"size": 2302233,
"createdBy": {
"application": null,
"device": null,
"user": {
"email": "[email protected]",
"id": "42ff222c-571f-497c-a9d3-f77ea9ece327",
"displayName": "James"
}
},
"lastModifiedBy": {
"application": null,
"device": null,
"user": {
"email": "[email protected]",
"id": "42ff222c-571f-497c-a9d3-f77ea9ece327",
"displayName": "James"
}
},
"parentReference": {
"driveId":
"b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wbOp_1uyhNwJMSSpseJneB7Z4F",
"driveType": "documentLibrary",
"id": "01YT2AIJRQLVYT24IWWFAJHMRRNYCB3GE2",
"path":
"/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wbOp_1uyhNwJMSSpseJneB7Z4F/root:/
Assignments/Test File Distribution"
},
"file": {
"mimeType": "image/png",
"hashes": {
"quickXorHash": "CvYQxN7MCGrIsdrA38c6wWhOu5g="
}
},
"fileSystemInfo": {
"createdDateTime": "2021-03-11T18:49:47Z",
"lastModifiedDateTime": "2021-03-11T18:49:47Z"
},
"image": {}
}
id} and {item-id} placeholders with the values described in the following table.
HTTP
https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wb
Op_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJU7DAXTU6XLOJGYWYMTGM5JT5UQ
Use the fileUrl from the previous step in the request body to Create an
educationAssignmentResource.
Request
HTTP
POST https://graph.microsoft.com/v1.0/education/classes/b07edbef-7420-4b3d-8f7c-
d599cf21e069/assignments/48b80dff-452a-4108-bd85-fa0d84e39d0a/resources
Content-type: application/json
{
"resource": {
"@odata.type": "#microsoft.graph.educationFileResource",
"fileUrl":
"https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4w
bOp_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJU7DAXTU6XLOJGYWYMTGM5JT5UQ",
"displayName": "Parts of a Sonnet"
}
}
Response
HTTP
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#education/classes('b07edbef-7420-4b3d-
8f7c-d599cf21e069')/assignments('48b80dff-452a-4108-bd85-
fa0d84e39d0a')/resources/$entity",
"distributeForStudentWork": false,
"id": "ff1aafe4-ae89-49c3-8366-4b509f640d6a",
"resource": {
"@odata.type": "#microsoft.graph.educationFileResource",
"displayName": "Parts of a Sonnet",
"createdDateTime": "2021-03-11T18:35:40.6642039Z",
"lastModifiedDateTime": "2021-03-11T18:35:40.6642039Z",
"fileUrl":
"https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4w
bOp_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJU7DAXTU6XLOJGYWYMTGM5JT5UQ",
"createdBy": {
"application": null,
"device": null,
"user": {
"id": "42ff222c-571f-497c-a9d3-f77ea9ece327",
"displayName": null
}
},
"lastModifiedBy": {
"application": null,
"device": null,
"user": {
"id": "42ff222c-571f-497c-a9d3-f77ea9ece327",
"displayName": null
}
}
}
}
You have now successfully uploaded a SharePoint resource to an assignment resources folder
(and attached it to the associated assignment). You can follow similar steps to upload one or
more student work resources.
Resources are an integral part of education assignments and submissions. Teachers determine
the resources to upload to an assignment folder, and students determine the resources to
upload to a feedback resources folder.
This article describes how to use the education API in Microsoft Graph to upload files to a
feedback resources folder.
Prerequisites
Before you can upload files, set up a SharePoint folder to upload the files to for a given
education assignment or submission resource.
Upload a resource
The submission setUpResourcesFolder API returns a model that contains the
resourcesFolderUrl property.
HTTP
{
...
"resourcesFolderUrl":
"https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4w
bOp_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJRQLVYT24IWWFAJHMRRNYCB3GFA"
...
}
The following steps describe how to upload a resource/file to a relevant resource folder.
resourcesFolderUrl property.
HTTP
https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wb
Op_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJRQLVYT24IWWFAJHMRRNYCB3GE2:/MyPictureFile.p
ng:/content
Step 2: Upload the resource to SharePoint
Make a PUT request with the upload URL to upload the content.
The contents of the request body should be the binary stream of the file to be uploaded.
For more details, see Upload large files with an upload session.
Request
The following example shows the request.
HTTP
PUT
https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wb
Op_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJRQLVYT24IWWFAJHMRRNYCB3GE2:/MyPictureFile.p
ng:/content
Content-Type: text/plain
Response
The following example shows the response.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#drives('b%216SQl0y4WHkS2P5MeIsSGpKwfyn
EIaD1OvPVeH4wbOp_1uyhNwJMSSpseJneB7Z4F')/items/$entity",
"@microsoft.graph.downloadUrl": "...",
"createdDateTime": "2021-03-11T18:49:47Z",
"eTag": "\"{EDD00CE7-B74C-4C3E-BA3E-484CB41EF31D},1\"",
"id": "01YT2AIJU7DAXTU6XLOJGYWYMTGM5JT5UQ",
"lastModifiedDateTime": "2021-03-11T18:49:47Z",
"name": "MyPictureFile.png",
"webUrl":
"https://contososdorg.sharepoint.com/sites/GraphTest/Class%20Files/Assignments/Tes
t%20File%20Distribution/MyPictureFile.png",
"cTag": "\"c:{EDD00CE7-B74C-4C3E-BA3E-484CB41EF31D},2\"",
"size": 2302233,
"createdBy": {
"application": null,
"device": null,
"user": {
"email": "[email protected]",
"id": "42ff222c-571f-497c-a9d3-f77ea9ece327",
"displayName": "James"
}
},
"lastModifiedBy": {
"application": null,
"device": null,
"user": {
"email": "[email protected]",
"id": "42ff222c-571f-497c-a9d3-f77ea9ece327",
"displayName": "James"
}
},
"parentReference": {
"driveId":
"b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wbOp_1uyhNwJMSSpseJneB7Z4F",
"driveType": "documentLibrary",
"id": "01YT2AIJRQLVYT24IWWFAJHMRRNYCB3GE2",
"path":
"/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wbOp_1uyhNwJMSSpseJneB7Z4F/root:/
Assignments/Test File Distribution"
},
"file": {
"mimeType": "image/png",
"hashes": {
"quickXorHash": "CvYQxN7MCGrIsdrA38c6wWhOu5g="
}
},
"fileSystemInfo": {
"createdDateTime": "2021-03-11T18:49:47Z",
"lastModifiedDateTime": "2021-03-11T18:49:47Z"
},
"image": {}
}
id} and {item-id} placeholders with the values described in the following table.
HTTP
https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wb
Op_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJU7DAXTU6XLOJGYWYMTGM5JT5UQ
Use the fileUrl from the previous step in the request body to create an
educationFeedbackResourceOutcome.
Request
HTTP
POST https://graph.microsoft.com/beta/education/classes/37d99af7-cfc5-4e3b-8566-
f7d40e4a2070/assignments/a3cce0ba-2008-4c4d-bf62-
079408562d96/submissions/2185e6d7-2924-4ed1-dde1-269f89e29184/outcomes
Content-type: application/json
{
"@odata.type": "#microsoft.graph.educationFeedbackResourceOutcome",
"feedbackResource": {
"@odata.type": "#microsoft.graph.educationWordResource",
"displayName": "Document1.docx"
}
}
Response
HTTP
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/education/classes('37d99af7-cfc5-4e3b-8566-
f7d40e4a2070')/assignments('a3cce0ba-2008-4c4d-bf62-
079408562d96')/submissions('2185e6d7-2924-4ed1-dde1-
269f89e29184')/outcomes/$entity",
"@odata.type": "#microsoft.graph.educationFeedbackResourceOutcome",
"lastModifiedDateTime": "2022-05-06T00:50:30.0772434Z",
"id": "ba12f282-2190-4958-80b3-42b8afb9626a",
"resourceStatus": "notPublished",
"lastModifiedBy": {
"application": null,
"device": null,
"user": {
"id": "cb1a4af3-0aba-4679-aa12-9f99bab0b61a",
"displayName": null
}
},
"feedbackResource": {
"@odata.type": "#microsoft.graph.educationWordResource",
"displayName": "Document1.docx",
"createdDateTime": "2022-05-06T00:50:30.0772177Z",
"lastModifiedDateTime": "2022-05-06T00:50:30.0772434Z",
"fileUrl": "https://graph.microsoft.com/beta/drives/b!-
Ik2sRPLDEWy_bR8l75jfeDcpXQcRKVOmcml10NQLQ1F8CNZWU38SarWxPyWM7jx/items/01VANVJQZQ33
I4AJBSURHZJDDQKEJ5TEMJ",
"createdBy": {
"application": null,
"device": null,
"user": {
"id": "cb1a4af3-0aba-4679-aa12-9f99bab0b61a",
"displayName": null
}
},
"lastModifiedBy": {
"application": null,
"device": null,
"user": {
"id": "cb1a4af3-0aba-4679-aa12-9f99bab0b61a",
"displayName": null
}
}
}
}
You have now successfully uploaded a resource to a feedback resources folder (and attached it
to the associated submission). You can follow similar steps to upload one or more feedback
resources.
This article describes student and teacher roles for assignments and submissions state
transitions, and related transition rules.
See the code sample for a student account with Education assignment using Microsoft
Graph SDK
7 Note
See the code sample for a teacher account with Education assignment using Microsoft
Graph SDK .
See also
States, transitions, and limitations for assignments
States, transitions, and limitations for submissions
States, transitions, and limitations for
assignments in Microsoft Graph
Article • 06/02/2023
Assignments are an important part of the interaction between teachers and students'
actions. This article describes the changes in the assignment states during the process
flow and which education APIs in Microsoft Graph are involved.
Published A POST
background /education/classes/{id}/assignments/{id}/publish
processing
state when
the
assignment
is
distributed
to each
student
assigned.
State Description REST API call Features
available to
edit
The following diagram shows the state transitions that can occur for assignments.
How to verify that an assignment is published
The caller must use the GET assignment operation to check the current assignment
status and verify that the publishing process succeeded.
Draft Discarded
Published Discarded
Assigned Discarded
Pending Discarded
7 Note
Only actions and state transitions listed in the table are allowed.
Synchronous operations are executed one at a time. Each operation must be completed
before the next one can begin, and the final result is only returned once all operations
have finished. Asynchronous operations allow multiple tasks to run concurrently. While
one operation is in progress, another operation can start before the previous one is
finished. Asynchronous operations typically involve background activities, and the caller
needs to actively check for the result by polling or monitoring until it becomes available.
Limits
The following limits apply to all API calls:
See also
States, transitions, and limitations for submissions
States, transitions, and limitations for
submissions in Microsoft Graph
Article • 06/02/2023
Submissions are an important part in the interaction between teachers' and students'
actions. about the changes in the submission states during the process flow and which
education APIs in Microsoft Graph are involved.
The status is a read-only property in the submission. It changes based on the actions of
students and teachers.
7 Note
Any action and state transition not listed in the table is not allowed.
In this case, all the calls are asynchronous, which means the operation starts, and
another operation can begin before the first one finishes. The asynchronous operation
performs some background activity, and the caller must be polling to get the result.
Limits
The following limits apply to all API calls:
See also
States, transitions, and limitations for assignments
Specify the default channel for
education assignment notifications
using the Microsoft Graph API
Article • 09/10/2022
This article describes how to use the education API in Microsoft Graph to specify the
default Microsoft Teams channel to send notifications to about an assignment.
Specifying the default channel involves building the notificationChannelUrl string
property for an educationAssignment. The default value for this property is null .
Prerequisites
Before building the property, identify the corresponding team for the assignment and
the name of the channel.
To identify the team for the assignment, in the left menu in Teams, click Teams and then
select the appropriate team.
Identify the appropriate channel within the team that you selected.
Build the notificationChannelUrl property value
The following steps describe how to build the property value.
Request
The following example shows the request.
HTTP
HTTP
HTTP/1.1 200 Ok
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#teams",
"@odata.count": 1,
"value": [
{
"id": "72a7baec-c3e9-4213-a850-f62de0adad5f",
"createdDateTime": null,
"displayName": "English Fall '21",
"description": "English Fall '21",
"internalId": null,
"classification": null,
"specialization": null,
"visibility": null,
"webUrl": null,
"isArchived": null,
"isMembershipLimitedToOwners": null,
"memberSettings": null,
"guestSettings": null,
"messagingSettings": null,
"funSettings": null,
"discoverySettings": null
}
]
}
Request
The following example shows the request.
HTTP
GET https://graph.microsoft.com/v1.0/teams/72a7baec-c3e9-4213-a850-
f62de0adad5f/channels?$filter=displayName eq 'General'
Response
The following example shows the response.
HTTP
HTTP/1.1 200 Ok
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#teams('72a7baec-c3e9-4213-a850-
f62de0adad5f')/channels",
"@odata.count": 1,
"value": [
{
"id": "19:jb2-
[email protected]",
"createdDateTime": "2021-08-25T12:33:49.124Z",
"displayName": "General",
"description": "English Fall '21",
"isFavoriteByDefault": null,
"email": "",
"webUrl": "https://teams.microsoft.com/l/channel/19%3Ajb2-
ckDy2jONyW6ElO1phAVD5cTjuswYgoumI0oxrUw1%40thread.tacv2/General?
groupId=72a7baec-c3e9-4213-a850-f62de0adad5f&tenantId=b6338c92-533e-4f6d-
a327-994263712399",
"membershipType": "standard"
}
]
}
https://graph.microsoft.com/v1.0/teams/{team-id}/channels/{channel-id}
Replace the {team-id} and {channel-id} placeholders with the values described in the
following table.
HTTP
https://graph.microsoft.com/v1.0/teams/72a7baec-c3e9-4213-a850-
f62de0adad5f/channels/19:jb2-
[email protected]
Request
HTTP
PATCH https://graph.microsoft.com/beta/education/classes/72a7baec-c3e9-4213-
a850-f62de0adad5f/assignments/4679bc1b-90c5-45af-ae1a-d5357672ed39
Content-type: application/json
{
"displayName": "Property update",
"notificationChannelUrl":
"https://graph.microsoft.com/v1.0/teams/72a7baec-c3e9-4213-a850-
f62de0adad5f/channels/19:jb2-
[email protected]"
}
Response
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#education/classes('72a7baec-
c3e9-4213-a850-f62de0adad5f')/assignments/$entity",
"classId": "72a7baec-c3e9-4213-a850-f62de0adad5f",
"displayName": "Property update",
"closeDateTime": null,
"dueDateTime": "2021-09-10T00:00:00Z",
"assignDateTime": null,
"assignedDateTime": null,
"allowLateSubmissions": true,
"resourcesFolderUrl": null,
"createdDateTime": "2021-09-03T23:57:14.6088791Z",
"lastModifiedDateTime": "2021-09-04T15:01:35.3361649Z",
"allowStudentsToAddResourcesToSubmission": true,
"status": "draft",
"notificationChannelUrl":
"https://graph.microsoft.com/v1.0/teams/72a7baec-c3e9-4213-a850-
f62de0adad5f/channels/19:jb2-
[email protected]",
"webUrl": "https://teams.microsoft.com/l/entity/66aeee93-507d-479a-a3ef-
8f494af43945/classroom?
context=%7B%22subEntityId%22%3A%22%7B%5C%22version%5C%22%3A%5C%221.0%5C%22,%
5C%22config%5C%22%3A%7B%5C%22classes%5C%22%3A%5B%7B%5C%22id%5C%22%3A%5C%2272
a7baec-c3e9-4213-a850-
f62de0adad5f%5C%22,%5C%22displayName%5C%22%3Anull,%5C%22assignmentIds%5C%22%
3A%5B%5C%224679bc1b-90c5-45af-ae1a-
d5357672ed39%5C%22%5D%7D%5D%7D,%5C%22action%5C%22%3A%5C%22navigate%5C%22,%5C
%22view%5C%22%3A%5C%22assignment-
viewer%5C%22%7D%22,%22channelId%22%3Anull%7D",
"addToCalendarAction": "studentsAndPublisher",
"addedStudentAction": "none",
"id": "4679bc1b-90c5-45af-ae1a-d5357672ed39",
"instructions": {
"content": "Read chapter 5 and write your review",
"contentType": "text"
},
"grading": {
"@odata.type":
"#microsoft.graph.educationAssignmentPointsGradeType",
"maxPoints": 50
},
"assignTo": {
"@odata.type": "#microsoft.graph.educationAssignmentClassRecipient"
},
"createdBy": {
"application": null,
"device": null,
"user": {
"id": "f3a5344e-dbde-48b0-be24-b5b62a243836",
"displayName": null
}
},
"lastModifiedBy": {
"application": null,
"device": null,
"user": {
"id": "f3a5344e-dbde-48b0-be24-b5b62a243836",
"displayName": null
}
}
}
Request
HTTP
PATCH https://graph.microsoft.com/beta/education/classes/72a7baec-c3e9-4213-
a850-f62de0adad5f/assignmentDefaults
Content-Type: application/json
{
"addToCalendarAction": "studentsOnly",
"notificationChannelUrl":
"https://graph.microsoft.com/v1.0/teams/72a7baec-c3e9-4213-a850-
f62de0adad5f/channels/19:jb2-
[email protected]"
}
Response
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"addedStudentAction": "assignIfOpen",
"addToCalendarAction": "studentsOnly",
"dueTime": "23:59:00",
"notificationChannelUrl":
"https://graph.microsoft.com/v1.0/teams/72a7baec-c3e9-4213-a850-
f62de0adad5f/channels/19:jb2-
[email protected]"
}
See also
Update educationAssignmentDefaults
Update educationAssignment
Set up an EDU development
environment
Article • 09/10/2022
The education API in Microsoft Graph enhances Microsoft 365 resources with
information that is relevant for education scenarios. To implement and test your
education solutions, you need to set up a demo developer tenant.
You can create two types of developer tenants, depending on your needs:
Demo EDU development tenant - Use to develop and test education solutions that
integrate with Microsoft Teams, School Data Sync, Immersive Reader, and more.
Demo EDU tenant - Provides a fully functional Microsoft 365 environment that you
can use for customer demos and for personal development.
Before you set up your demo EDU tenant, you must join the Microsoft Partner Network.
Join the Microsoft Partner Network
Article • 09/10/2022
The Microsoft Partner Network is a powerful community of organizations like yours that
connects you to the relationships, insights, tools, resources, and programs you need to
amaze your customers and drive business growth.
You must join the Microsoft Partner Network in order to set up an EDU dev tenant or
publish apps to Microsoft marketplaces.
2. Select one or more options to specify how you would like to partner with
Microsoft, and choose Next.
4. To verify your identity, set your phone number and select Text me or Call me to
get the verification code. When you receive the code, input it and choose Next.
5. Select Yes to specify that your email address was provided by your company.
6. Complete you account information, set a password, and confirm the verification
code sent to your email, and then choose Next.
8. Provide your company information and choose Accept and continue. You have
created your Microsoft Partner Network account, and you can send an invitation to
members of your organization.
You can now access Partner Center with your Microsoft Partner Network account.
Next steps
Set up your development environment. You can create two types of EDU tenants:
See also
Partner with Microsoft
What is the Microsoft Partner Network?
Partner Center account management
Set up a demo tenant to develop
education solutions
Article • 09/10/2022
You can set up a demo EDU tenant that simulates a Microsoft 365 EDU customer tenant
that you can use to develop and test your education solutions.
Build rich solutions that integrate Microsoft 365 apps and business processes to
enhance productivity in the modern workplace.
Get a Teams development environment in seconds.
Extend and customize Teams to create and connect apps and workflows.
2. Complete the form. Pay attention to the Product Information section. In the MPN
No field, provide your Microsoft Partner Network ID, and in the Are you
requesting an EDU development tenant? box, choose Yes.
Note: If you don't have a Microsoft Partner Network ID, join the Microsoft Partner
Network.
See also
See the following resources to get started with your developer tenant:
If you need a tenant to use for your own learning or for customer demos, see Create a
demo EDU tenant.
Set up a demo education tenant
Article • 10/21/2022
If you need a tenant for your personal learning or for customer demos, but not for
developing education solutions, you can set up a demo EDU tenant instead of an EDU
dev tenant.
You'll use your Microsoft Partner Network (MPN) ID and the Customer Digital
Experiences (CDX) to create a demo EDU tenant.
2. On the My tenants tab, choose Create tenant. You can see the environment limits:
90-day tenants: 0 of 6
1-year tenants: 0 of 3
Custom tenants: 0 of 1
90 days: 90 day tenants include the latest services and content at time of
provisioning. This is the recommended option for specific customizations
related to a customer engagement. 90 day tenants will not be extended.
1 year: 1 year tenants include the latest services and content at time of
provisioning. This is the recommended option for customization and learning,
such as creating hybrid environments. Only 1 year tenants can be extended. If
a tenant is required long term, this is the best choice.
5. Look for Microsoft Education Demo Content and choose Create tenant.
Important: You must not use a demo EDU tenant for development purposes.
Next steps
Set up School Data Sync
See also
Set up an EDU dev tenant.
Set up School Data Sync
Article • 04/22/2023
Microsoft School Data Sync simplifies class management in Office 365. School Data Sync
reads rosters from your SIS and creates classes and groups for Microsoft Teams, Intune
for Education, and third-party applications. You must set up School Data Sync to use
Microsoft Graph education APIs.
To access the School Data Sync admin portal, launch a private web browser, go to
sds.microsoft.com , choose Sign In, and enter the Office 365 Global Admin account
credentials that you created when you set up your demo EDU tenant. After you sign in:
Enter a name for your sync profile. This name will be used to identify the sync
profile in the SDS Dashboard; you can't change it after you finish the setup
process.
Select Upload CVS files and CVS files: SDS Format.
Choose Start.
3. On the Sync options page, select New users, and then choose Upload files to
upload your six CSV files.
5. On the Teacher options page, make sure that faculty licenses are selected and
choose Next.
6. On the Student options page, make sure that student licenses are selected and
choose Next.
7. On the Review page, verify that you made the appropriate selections, and choose
Create profile.
8. After you create a sync profile, SDS will begin a pre-sync validation process. During
this process, SDS will verify that there are no obvious errors with your CSV files.
If any errors are found during the pre-sync validation process, you will have
the option to fix them and re-upload the files before you resume the sync.
If errors occur and you choose not to update the CSV files, you can still
choose to resume sync. Just be aware that SDS can only sustain up to 15,000
errors before the profile enters a quarantine status.
9. The sync process will take some time. When prompted, press F5 to manually
refresh the status page.
Next steps
Set up Microsoft Teams to set up classes (optional).
Set up Microsoft Teams to work with
tenant users
Article • 09/10/2022
To work with the education API in Microsoft Graph, you need to set up Microsoft Teams
and create a team. If you set up School Data Sync, you might already have teams set up
in your demo environment. To create more teams manually, follow the steps in this
article, using a teacher or admin account in your EDU demo tenant.
When prompted by the installer, sign in with your Office 365 Global Admin account
credentials.
Create a team
To create a team:
1. On the left menu, choose Teams, and then choose Create team. If you already
have a team, on the top right, choose Join or create a team, and then choose
Create team.
2. For the team type, select Class. Note that you will only see this choice if you are
signed in to an EDU tenant.
4. Add students to the team. In the search box, start typing a name, select a result,
and choose Add. Repeat this step for each student and teacher in the class.
You have successfully created your team.
Next steps
Use Graph Explorer to test Microsoft Graph calls.
Use Graph Explorer to work with the
education API in Microsoft Graph
Article • 09/10/2022
You can use the education API in Microsoft Graph to build applications that access EDU
data. For example, you can display information from School Data Sync (SDS) and
Microsoft Teams, or automate common tasks like adding students and creating
assignments.
You can use Graph Explorer to test Microsoft Graph queries before you implement them
in your application.
Use the following steps to try education API calls in Graph Explorer:
You might have to wait for the permissions to update before you can run all
queries.
```json
{
"dueDateTime": "2024-02-15T00:00:00Z",
"displayName": "Reading and comprehension",
"instructions": {
"contentType": "text",
"content": "Read the chapter and answer the questions"
},
"grading": {
"@odata.type":
"#microsoft.graph.educationAssignmentPointsGradeType",
"maxPoints": 50
},
"assignTo": {
"@odata.type":
"#microsoft.graph.educationAssignmentClassRecipient"
},
"allowStudentsToAddResourcesToSubmission": true
}
```
10. Choose Run query. If your query is successful, you'll get a Created – 201 response
and a JSON object that represents the new assignment.
11. Try more queries. For more examples, see the education API reference content.
Next steps
Working with education APIs in Microsoft Graph
Connect to assignments and grades
Article • 01/24/2023
In recent years, Microsoft Teams for education has become an essential solution that
supports educators and students. Assignments and grades are a core part of Teams for
education, and provide the central workflow that educators use to assign, assess, grade,
and provide feedback to students around the world.
Microsoft Graph provides a set of integration points that enable you to customize and
extend the experience for educators, admins, and students when they work with
assignments and grades.
Get started
All Teams for education users have access to assignment and grade functionality. To set
up a demo or development tenant for Teams to start building your custom solutions,
see Set up an EDU development environment.
Scenarios
You can read and update data and integrate your app with assignments and grades in
multiple ways. The following are some key scenarios that you can apply, in one or more
combinations, to integrate with assignments and grades.
Education institutions have custom tools that need data from assignments and grades;
for example, tools that are used for reporting and communication to the school district,
or tools that are used to automate a set of processes. You can use the education API in
Microsoft Graph to get data for assignments and grades for both classes and students.
Note: You can use Graph Explorer to test the APIs mentioned in this article.
After you get the relevant class and member information, you can get the assignment
and grade information that you need.
educationAssignment resource type: Allows you to list and see all data for
assignments in a class.
educationSubmission resource type: A submission is created for every student for
whom an assignment is published. You can use this API to get the submission
status - that is, whether it was turned in and graded, resources submitted by the
student, and the grade (outcome) for the submission.
List assignments of a user: Lists all assignments for a given user. You can use either
this by a delegated user or the preferred way is to use AppOnly person to use
/users/{user-id} .
Permissions
The assignments API supports both delegated (per user) and app only (per app)
permission. App-only permissions simplify the experience for students and teachers
because they only have to approve the app in order to retrieve data.
For assignments, delta queries are supported for assignment information changes only,
and not submission changes for an assignment.
Filtering data
Assignment API endpoints return a large amount of data. You can use the filter OData
query parameter to handle the data as needed.
Integrate your Teams app with
education assignments
Article • 01/10/2023
The education community has a rich set of tools and applications that enhance the
experience for educators and users. You can use Microsoft Graph APIs to make your
solution available to teachers and students by integrating your app with assignments in
Teams.
Note: You can use Graph Explorer to test the APIs mentioned in this article.
To get started building your own Teams app, see Create a new Teams app.
For best practices for integrating your Teams app with assignments, see the assignment
apps sample .
For details about the requirements for integrating with the assignments flow in Teams,
see Assignment app integration requirements .
1. Get the application id using this endpoint. Do not supply a request body.
HTTP
Request
The following is an example of the request. Use the id from the previous request for the
appId property value.
HTTP
POST https://graph.microsoft.com/beta/education/classes/72a7baec-c3e9-4213-
a850-f62de0adad5f/assignments/1618dfb0-3ff2-4edf-8d5c-b8f81df00e80/resources
Content-type: application/json
{
"distributeForStudentWork": false,
"resource": {
"contentUrl": "https://sd-prod-us-web-
galileo.azurewebsites.net/assets/content.html",
"appId": "7caaa66b-34b0-4c15-a65d-dba6edf0c8fd",
"appIconUrl": "https://statics.teams.cdn.office.net/evergreen-
assets/ThirdPartyApps/7caaa66b-34b0-4c15-a65d-dba6edf0c8fd_largeImage.png?
v=1.3.0",
"displayName": "School Day",
"websiteUrl": "https://sd-prod-us-web-galileo.azurewebsites.net/",
"@odata.type": "#microsoft.graph.educationTeamsAppResource"
}
}
Response
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#education/classes('72a7baec-
c3e9-4213-a850-f62de0adad5f')/assignments('1618dfb0-3ff2-4edf-8d5c-
b8f81df00e80')/resources/$entity",
"distributeForStudentWork": false,
"status": "published",
"id": "de220fbc-865a-4c8e-a013-fc5dabe0f817",
"resource": {
"@odata.type": "#microsoft.graph.educationTeamsAppResource",
"displayName": "School Day",
"createdDateTime": "2022-12-21T02:17:01.9365101Z",
"lastModifiedDateTime": "2022-12-21T02:17:01.9365342Z",
"appId": "7caaa66b-34b0-4c15-a65d-dba6edf0c8fd",
"appIconUrl": "https://statics.teams.cdn.office.net/evergreen-
assets/ThirdPartyApps/7caaa66b-34b0-4c15-a65d-dba6edf0c8fd_largeImage.png?
v=1.3.0",
"contentUrl": "https://sd-prod-us-web-
galileo.azurewebsites.net/assets/content.html",
"websiteUrl": "https://sd-prod-us-web-galileo.azurewebsites.net/",
"createdBy": {
"application": null,
"device": null,
"user": {
"id": "cb1a4af3-0aba-4679-aa12-9f99bab0b61a",
"displayName": null
}
},
"lastModifiedBy": {
"application": null,
"device": null,
"user": {
"id": "cb1a4af3-0aba-4679-aa12-9f99bab0b61a",
"displayName": null
}
}
}
}
3. The Teams App is now added to the assignment and is available for students to
launch.
For an example that shows how to integrate a Teams app with an assignment, see
Example 7: Create an educationTeamsAppResource.
Permissions
The assignments API supports both delegated (per user) and app-only (per app)
permissions. For ease of use for the student and teacher, app-only permissions are
preferred. This allows for approval of your app only to retrieve data.
Get links to assignments and
submissions
Article • 01/19/2023
Education institutions have custom tools for students and users to view details about or
complete assignments. You can use education APIs in Microsoft Graph to get deep links
to assignments and submissions for use in custom tools. Before you can get links to
assignments and submissions, you must get the relevant class and member information.
Note: You can use Graph Explorer to test the education APIs mentioned in this
article.
After you get the relevant class and member information, you can get the assignment
and grade information you need.
The following example describes how to get the deep link URL for a given assignment.
Request
The following example shows the request.
GET https://graph.microsoft.com/v1.0/education/classes/f4a941ff-9da6-4707-
ba5b-0eae93cad0b4/assignments/3c77de7f-539b-49e1-9c96-1274f2f0ee3b
Response
The following example shows the response.
Note: The response object shown here might be shortened for readability.
HTTP/1.1 200 OK
Content-type: application/json
Content-length: 279
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#education/classes('f4a941ff-
9da6-4707-ba5b-0eae93cad0b4')/assignments/$entity",
"classId": "f4a941ff-9da6-4707-ba5b-0eae93cad0b4",
"displayName": "07.30 SubmissionsUploadResource Word2",
"closeDateTime": null,
"dueDateTime": "2021-08-01T06:59:00Z",
"assignDateTime": null,
"assignedDateTime": "2021-07-30T16:01:32.5518042Z",
"allowLateSubmissions": true,
"status": "assigned",
"notificationChannelUrl": null,
"webUrl": "https://teams.microsoft.com/l/entity/66aeee93-507d-479a-a3ef-
8f494af43945/classroom?
context=%7b%22subEntityId%22%3a%22%7b%5c%22version%5c%22%3a%5c%221.0%5c%22%2
c%5c%22config%5c%22%3a%7b%5c%22classes%5c%22%3a%5b%7b%5c%22id%52navigate%5c%
22%2c%5c%22view%5c%22%3a%5c%22assignment-
viewer%5c%22%7d%22%2c%22channelId%22%3anull%7d",
"addedStudentAction": "none",
"id": "3c77de7f-539b-49e1-9c96-1274f2f0ee3b",
"instructions": {
"content": "<div style=\"font-family: inherit; font-size: inherit;
color: inherit;\">upload a word document</div>",
"contentType": "html"
},
"grading": {
"@odata.type":
"#microsoft.graph.educationAssignmentPointsGradeType",
"maxPoints": 10
},
"lastModifiedBy": {
"application": null,
"device": null,
"user": {
"id": "f3a5344e-dbde-48b0-be24-b5b62a243836",
"displayName": null
}
}
}
The webUrl property in the response provides the deep link URL for the assignment.
The following example describes how to get the deep link URL for a given submission.
Request
The following example shows the request.
Get https://graph.microsoft.com/beta/education/classes/2003c52e-807a-4186-
9b49-60c573095461/assignments/8f5311bb-ee1e-4bf0-9827-
3fd8c57bdde2/submissions/57ef8ee2-4755-4351-66d0-8e37192870a5
Response
The following example shows the resposnse.
Note: The response object shown here might be shortened for readability.
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#education/classes('2003c52e-
807a-4186-9b49-60c573095461')/assignments('8f5311bb-ee1e-4bf0-9827-
3fd8c57bdde2')/submissions/$entity",
"status": "working",
"submittedDateTime": null,
"unsubmittedDateTime": null,
"returnedDateTime": null,
"reassignedDateTime": null,
"resourcesFolderUrl":
"https://graph.microsoft.com/v1.0/drives/b!IDwAYNkmlUucm64fxXxnzYYTuh2luKRDv
UVGQBLOmvYqism21WrdQ4Aijx5lDIKE/items/0173CEVEPVMJCDTMO5RRH256O6T5NIB2CF",
"webUrl": "https://teams.microsoft.com/l/entity/66aeee93-507d-479a-a3ef-
8f494af43945/classroom?
context=%7B%22subEntityId%22%3A%22%7B%5C%22version%5C%22%3A%5C%221.0%5C%22,%
5C%22action%5C%22%3A%5C%22navigate%5C%22,%5C%22view%5C%22%3A%5C%22speed-
grader%5C%22%7D%22,%22channelId%22%3Anull%7D",
"id": "57ef8ee2-4755-4351-66d0-8e37192870a5",
"recipient": {
"@odata.type":
"#microsoft.graph.educationSubmissionIndividualRecipient",
"userId": "51cf5a99-d234-4e43-96de-cd65df14bfa1"
},
"submittedBy": {
"application": null,
"device": null,
"user": {
"id": "51cf5a99-d234-4e43-96de-cd65df14bfa1",
"displayName": null
}
},
"reassignedBy": {
"application": null,
"device": null,
"user": {
"id": null,
"displayName": null
}
}
}
The webUrl property in the response provides the deep link URL for the submission.
Permissions
The assignments APIs support both delegated and application permissions. We
recommend using application permissions because that permits your app only to
retrieve data.
Update assignment and grade data
Article • 01/19/2023
Education institutions have custom tools to update assignment and grade data. For
example, a teacher might need to make an update to an assignment before students
submit them, or make a change to a grade (outcome) by using a custom tool.
Before you can update data, you must get the relevant class and member information.
Note: You can use Graph Explorer to test the Education APIs mentioned in this
article.
After you get the relevant class and member information, you can get the assignment
and grade information you need.
Request
The following example shows the request.
Note: The request body should only include the values of the fields that need to be
updated.
PATCH https://graph.microsoft.com/v1.0/education/classes/acdefc6b-2dc6-4e71-
b1e9-6d9810ab1793/assignments/cf6005fc-9e13-44a2-a6ac-
a53322006454/submissions/d1bee293-d8bb-48d4-af3e-
c8cb0e3c7fe7/outcomes/9c0f2850-ff8f-4fd6-b3ac-e23077b59141
Content-type: application/json
{
"@odata.type":"#microsoft.graph.educationPointsOutcome",
"points":{
"@odata.type":"#microsoft.graph.educationAssignmentPointsGrade",
"points":85.0
}
}
Response
The following example shows the resposnse.
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.type":"#microsoft.graph.educationPointsOutcome",
"id":"ea1351f6-ba33-4940-b2cb-6a7254af2dc8",
"lastModifiedBy":{
"user":{
"id":"9391878d-903c-406c-bb1c-0f17d00fd878"
}
},
"points":{
"gradedDateTime":"2019-07-15T22:35:48.2429387Z",
"points":85.0,
"gradedBy":{
"user":{
"id":"9391878d-903c-406c-bb1c-0f17d00fd878"
}
}
}
}
Permissions
Delegated and application permissions are required to update data in assignments.
Application permissions are currently supported in the beta version only.
Note: Because student and grade information is sensitive data, be sure to verify
which permissions are required.
Download all resources from a set of
assignments
Article • 01/24/2023
This article describes how to use Microsoft Graph to download all SharePoint resources
from a set of assignments at the end of a grade period. This can be helpful for end-of-
year archiving or for reviewing feedback given to students.
Note: You can use Graph Explorer to test the APIs mentioned in this article.
You can use the List outcomes API to get a list of education outcome objects.
You can then use the Download file API to download the contents of the file from
SharePoint. Note that only driveItems with the file property can be downloaded.
Alternatively, you can download the files from a JavaScript app. For details, see
Downloading files in JavaScript apps.
Embed a Teams app in an assignment
Article • 01/24/2023
This article describes how to use Microsoft Graph to embed a Teams app in an
assignment to add additional functionality.
Note: You can use Graph Explorer to test the APIs mentioned in this article.
List apps in a team: Get a list of apps installed in the specified team.
Get a specific app installed in a team: Get information about an app installed in the
specified team.
You can look for the required app in the app catalog; if it isn't installed in the team, you
can use the following API:
Permissions
The teacher role is required to add a Teams app as a resource to assignments.
Add custom data to resources using
extensions
Article • 05/30/2023
Microsoft Graph provides a single API endpoint to access rich people-centric data and
insights through resources such as user and message. You can also extend Microsoft
Graph by adding custom properties to resource instances without requiring an external
data store.
In this article, we'll discuss how Microsoft Graph supports extending its resources, the
options available to add custom properties and when to use them.
) Important
The extensions mentioned in this article are not similar to Azure AD custom
security attributes. To understand their differences, see How do custom security
attributes compare with extensions?
Extension attributes
Directory (Azure AD) extensions
Schema extensions
Open extensions
Extension attributes
Azure AD offers a set of 15 extension attributes with predefined names on the user and
device resources. These properties were initially custom attributes provided in on-
premises Active Directory (AD) and Microsoft Exchange. However, they can now be used
for more than syncing on-premises AD and Microsoft Exchange data to Azure AD
through Microsoft Graph.
Developer experience
You can use the 15 extension attributes to store String values on user or device resource
instances, through the onPremisesExtensionAttributes and extensionAttributes
properties respectively. The values may be assigned when creating a new resource
instance or when updating an existing resource instance. You can also filter by the
values.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/071cc716-8147-4397-a5ba-
b2105951cc0b
{
"onPremisesExtensionAttributes": {
"extensionAttribute1": "skypeId.adeleVance",
"extensionAttribute13": null
}
}
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?
$select=id,displayName,onPremisesExtensionAttributes
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users(id,displayName,onPremisesE
xtensionAttributes)",
"value": [
{
"id": "071cc716-8147-4397-a5ba-b2105951cc0b",
"displayName": "Adele Vance",
"onPremisesExtensionAttributes": {
"extensionAttribute1": "Contractor",
"extensionAttribute2": "50",
"extensionAttribute3": null,
"extensionAttribute4": "1478354",
"extensionAttribute5": "10239390",
"extensionAttribute6": null,
"extensionAttribute7": null,
"extensionAttribute8": null,
"extensionAttribute9": null,
"extensionAttribute10": "11",
"extensionAttribute11": null,
"extensionAttribute12": "/o=ExchangeLabs/ou=Exchange
Administrative Group
(FYDIBOHF47SPDLT)/cn=Recipients/cn=5ee781fc7egc7aa0b9394bddb44e7f04-Adele
Vance",
"extensionAttribute13": null,
"extensionAttribute14": null,
"extensionAttribute15": null
}
}
]
}
The 15 extension attributes are already predefined in Microsoft Graph and their property
names can't be changed. Therefore, you can't use custom names such as SkypeId for
the extension attributes. This requires you and the organization to be aware of the
extension attribute properties that are in use so that the values aren't inadvertently
overwritten by other apps.
For the list of resource types that can be specified as target objects for a directory
extension, see Comparison of extension types.
Developer experience
Directory extension definitions are managed through the extensionProperty resource
and its associated methods. The data is managed through the REST API requests that
you use to manage the resource instance.
Before you can add a directory extension to a resource instance, you must first define
the directory extension.
Request
HTTP
POST https://graph.microsoft.com/v1.0/applications/30a5435a-1871-485c-
8c7b-65f69e287e7b/extensionProperties
{
"name": "jobGroupTracker",
"dataType": "String",
"targetObjects": [
"User"
]
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#applications('30a5435a-1871-
485c-8c7b-65f69e287e7b')/extensionProperties/$entity",
"id": "4e3dbc8f-ca32-41b4-825a-346215d7d20f",
"deletedDateTime": null,
"appDisplayName": "HR-sync-app",
"dataType": "String",
"isSyncedFromOnPremises": false,
"name": "extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker",
"targetObjects": [
"User"
]
}
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
{
"accountEnabled": true,
"displayName": "Adele Vance",
"mailNickname": "AdeleV",
"userPrincipalName": "[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn": false,
"password": "xWwvJ]6NMw+bWH-d"
},
"extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker":
"JobGroupN"
}
The request returns a 201 Created response code and a user object in the response
body.
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/users?
$select=id,displayName,extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGro
upTracker,extension_b7d8e648520f41d3b9c0fdeb91768a0a_permanent_pensionab
le
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users(id,displayName,extension_b
7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker,extension_b7d8e648520f41d3b9
c0fdeb91768a0a_permanent_pensionable)",
"value": [
{
"id": "63384f56-42d2-4aa7-b1d6-b10c78f143a2",
"displayName": "Adele Vance",
"extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker":
"E4",
"extension_b7d8e648520f41d3b9c0fdeb91768a0a_permanent_pensionable": true
}
]
}
To update or delete the value of the directory extension for a resource instance, use the
PATCH method. To delete the extension property and its associated value, set its value to
null .
The following request updates the value of one directory extension and deletes another
extension property.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/63384f56-42d2-4aa7-b1d6-
b10c78f143a2
{
"extension_b7d8e648520f41d3b9c0fdeb91768a0a_permanent_pensionable":
null,
"extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker": "E4"
}
When the definition is deleted before data in the associated extension property is
deleted, there's no way to know the existence of the extension property via Microsoft
Graph - even though the undiscoverable property counts against the 100-limit.
Deleting an owner app in the home tenant makes the associated directory extensions
and their data undiscoverable. Restoring an owner app restores the directory extension
definitions but doesn't make the directory extension properties or their data immediately
discoverable. This is because restoring an app doesn't automatically restore the
associated service principal in the tenant. To make the directory extension properties
and their data discoverable, either create a new service principal or restore the deleted
service principal. NO changes are made to other tenants where the app has been
consented to.
Schema extensions
Microsoft Graph schema extensions are conceptually similar to directory extensions.
First, you define your schema extension. Then, use it to extend supported resource
instances with strongly typed custom properties. In addition, you can control the status
of your schema extension and let it be discoverable by other apps.
For the list of resource types that support schema extensions, see Comparison of
extension types.
https://www.youtube-nocookie.com/embed/3MOAlUFNus0
Developer experience
When creating a schema extension definition, you must provide a unique name for its
id. There are two naming options:
If you already have a vanity .com , .net , .gov , .edu or a .org domain that you've
verified with your tenant, you can use the domain name along with the schema
name to define a unique name, in this format {domainName}_{schemaName}. For
example, if your vanity domain is contoso.com , you can define an id of
contoso_mySchema . This option is highly recommended.
Alternatively, you can set the id to a schema name (without a domain name prefix).
For example, mySchema . Microsoft Graph will assign a string ID for you based on
the supplied name, in this format: ext{8-random-alphanumeric-chars}_{schema-
name} . For example, extkvbmkofy_mySchema .
The id will be the name of the complex type that will store your data on the extended
resource instance.
Once you register a schema extension, it's available to be used by all applications in the
same tenant as the associated owner application (when in the InDevelopment state) or
by all applications in any tenant (when in the Available state). Like directory extensions,
authorized apps have the ability to read and write data on any extensions defined on
the target object.
You manage the schema extension definitions and the data in the corresponding
schema extension property using separate sets of API operations. To manage the
schema extension data on the extended resource instance, use the same REST request
that you use to manage the resource instance.
Use POST to store data in the schema extension property when you're creating a
new user.
Use PATCH to either store data in the schema extension property or update or
delete the stored data.
To delete data from a property, set its value to null .
To delete data from all properties, set its value to null . If all properties are
null , the schema extension object is also deleted.
To update any property, you must specify all properties in the request body.
Otherwise, Microsoft Graph will update the unspecified properties to null .
Use GET to read the schema extension properties for all users or individual users in
the tenant.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/schemaExtensions
{
"id": "graphLearnCourses",
"description": "Graph Learn training courses extensions",
"targetTypes": [
"user"
],
"properties": [
{
"name": "courseId",
"type": "Integer"
},
{
"name": "courseName",
"type": "String"
},
{
"name": "courseType",
"type": "String"
}
]
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#schemaExtensions/$entity",
"id": "extkmpdyld2_graphLearnCourses",
"description": "Graph Learn training courses extensions",
"targetTypes": [
"user"
],
"status": "InDevelopment",
"properties": [
{
"name": "courseId",
"type": "Integer"
},
{
"name": "courseName",
"type": "String"
},
{
"name": "courseType",
"type": "String"
}
]
}
HTTP
HTTP
POST https://graph.microsoft.com/beta/users
{
"accountEnabled": true,
"displayName": "Adele Vance",
"mailNickname": "AdeleV",
"userPrincipalName": "[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn": false,
"password": "xWwvJ]6NMw+bWH-d"
},
"extkmpdyld2_graphLearnCourses": {
"courseId": 100,
"courseName": "Explore Microsoft Graph",
"courseType": "Online"
}
}
The request returns a 201 Created response code and a schemaExtension object in the
response body
The following example deletes the value of the courseId property and updates the
courseType property. To delete the extkmpdyld2_graphLearnCourses extension property
in its entirety, set its value to null .
HTTP
HTTP
PATCH https://graph.microsoft.com/beta/users/0668e673-908b-44ea-861d-
0661297e1a3e
{
"extkmpdyld2_graphLearnCourses": {
"courseType": "Instructor-led",
"courseId": null
}
}
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/users/0668e673-908b-44ea-861d-
0661297e1a3e?$select=id,displayName,extkmpdyld2_graphLearnCourses
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users(id,displayName,extkmpdyld2
_graphLearnCourses)/$entity",
"id": "63384f56-42d2-4aa7-b1d6-b10c78f143a2",
"displayName": "Adele Vance",
"extkmpdyld2_graphLearnCourses": {
"@odata.type": "#microsoft.graph.ComplexExtensionValue",
"courseType": "Instructor-led",
"courseName": "Explore Microsoft Graph",
"courseId": null
}
}
Deleting a schema extension definition without setting the schema extension to null
makes the property and its associated user data undiscoverable.
Deleting an owner app in the home tenant doesn't delete the associated schema
extension definition or the property and the data it stores. The schema extension
property can still be read, deleted, or updated for users. However, the schema extension
definition can't be updated.
Open extensions
Microsoft Graph open extensions are open types that offer a simple and flexible way
to add untyped data directly to a resource instance. These extensions aren't strongly
typed, discoverable, or filterable.
For the list of resource types that support Microsoft Graph open extensions, see
Comparison of extension types.
https://www.youtube-nocookie.com/embed/ibdlADb8IZc
Developer experience
Open extensions, together with their data, are accessible through the extensions
navigation property of the resource instance. They allow you to group related properties
for easier access and management.
You define and manage open extensions on the fly on resource instances. They're
considered unique for each object, and it's not required to apply a universally consistent
pattern for all objects. For example, in the same tenant:
The user object for Adele can have an open extension named socialSettings that
has three properties: linkedInProfile, skypeId, and xboxGamertag.
The user object for Bruno can have no open extension property.
The user object for Alex can have an open extension named socialSettings with five
properties: theme, color, language, font, and fontSize.
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users/3fbd929d-8c56-4462-851e-
0eb9a7b3a2a5/extensions
{
"@odata.type": "#microsoft.graph.openTypeExtension",
"extensionName": "com.contoso.socialSettings",
"skypeId": "skypeId.AdeleV",
"linkedInProfile": "www.linkedin.com/in/testlinkedinprofile",
"xboxGamerTag": "AwesomeAdele",
"id": "com.contoso.socialSettings"
}
The request returns a 201 Created response code and an openTypeExtension object in
the response body.
To update an open extension, you must specify all its properties in the request body.
Otherwise, the unspecified properties will be updated to null and deleted from the
open extension.
The following request specifies only the linkedInProfile and xboxGamerTag properties.
The value of the xboxGamerTag property is being updated while the linkedInProfile
property remains the same. This request also deletes the unspecified skypeId property.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/3fbd929d-8c56-4462-851e-
0eb9a7b3a2a5/extensions/com.contoso.socialSettings
{
"xboxGamerTag": "FierceAdele",
"linkedInProfile": "www.linkedin.com/in/testlinkedinprofile"
}
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users/3fbd929d-8c56-4462-851e-
0eb9a7b3a2a5/extensions/com.contoso.socialSettings
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('3fbd929d-8c56-4462-
851e-0eb9a7b3a2a5')/extensions/$entity",
"@odata.type": "#microsoft.graph.openTypeExtension",
"xboxGamerTag": "FierceAdele",
"linkedInProfile": "www.linkedin.com/in/testlinkedinprofile",
"id": "com.contoso.socialSettings"
}
7 Note
1
Due to an existing service limitation, delegates cannot create open extension-
appended events in shared mailbox calendars. Attempts to do so will result in an
ErrorAccessDenied response.
2
Only available in public preview for directory extensions.
3 These limits on open extensions apply to the following directory resources: user,
group, device, and organization.
4
Each open extension is stored in a MAPI named property, which are a limited
resource in a user's mailbox. This limit applies to the following Outlook resources:
message, event, and contact
You can manage all extensions when you're signed in with a work or school
account. Additionally, you can manage open extensions for the following resources
when signed-in with a personal Microsoft account: event, post, group, message,
contact, and user.
Known limitations
For known limitations using extensions, see the extensions section in the known issues
article.
Next steps
Training module: Add custom data to your app using extensions in Microsoft
Graph
Add custom data to users using open extensions
Add custom data to groups using schema extensions
Add custom data to users using open
extensions
Article • 04/19/2023
Imagine you're building an application that is available on multiple client platforms, such
as desktop and mobile. You want to let users configure their UI experience so it’s
consistent no matter which device they use to sign in to your app.
For this scenario, this article will show you how to:
1. Add an open extension representing some roaming profile information about the
user.
2. Query the user and return the roaming profile.
3. Change the user's roaming profile information (the open extension value).
4. Delete the user's roaming profile information.
7 Note
Apart from users, open extensions are also supported and can be managed for
other resource types.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/me/extensions
Content-type: application/json
{
"@odata.type":"microsoft.graph.openTypeExtension",
"extensionName":"com.contoso.roamingSettings",
"theme":"dark",
"color":"purple",
"lang":"Japanese"
}
Response
HTTP
{
"@odata.type": "#microsoft.graph.openTypeExtension",
"extensionName": "com.contoso.roamingSettings",
"id": "com.contoso.roamingSettings",
"theme": "dark",
"color": "purple",
"lang": "Japanese"
}
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me?
$select=id,displayName,mail,mobilePhone&$expand=extensions
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "84b80893-8749-40a3-97b7-68513b600544",
"displayName": "John Smith",
"mail": "[email protected]",
"mobilePhone": "1-555-6589",
"extensions": [
{
"@odata.type": "#microsoft.graph.openTypeExtension",
"extensionName": "com.contoso.roamingSettings",
"id": "com.contoso.roamingSettings",
"theme": "dark",
"color": "purple",
"lang": "Japanese"
}
]
}
Request
HTTP
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/extensions/com.contoso.roamingSettin
gs
Content-type: application/json
{
"theme":"light",
"color":"yellow",
"lang":"Swahili"
}
Response
HTTP/1.1 204 No content
Request
HTTP
HTTP
DELETE
https://graph.microsoft.com/v1.0/me/extensions/com.contoso.roamingSettin
gs
Response
See also
Add custom data to resources using extensions
Add custom data to groups using schema extensions
openTypeExtension resource type
Add custom data to groups using
schema extensions
Article • 03/02/2023
For this scenario, this article will show you how to:
7 Note
Apart from groups, schema extensions are also supported and can be managed for
other resource types.
In the following example, you query the schemaExtension resource for a specific
schema extension by its id.
Notice that the extension returned in the response has Available as the status value,
which indicates that any app that has permission to the resources in the targetTypes
property can use and update the extension with additive changes. In general, this
operation returns any schema extensions that satisfy the specified filter regardless of
status, so do check the extension status before using it.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/schemaExtensions?$filter=id eq
'graphlearn_test'
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"value": [
{
"id":"graphlearn_test",
"description": "Yet another test schema",
"targetTypes": [
"User", "Group"
],
"status": "Available",
"owner": "24d3b144-21ae-4080-943f-7067b395b913",
"properties": [
{
"name": "testName",
"type": "String"
}
]
}
]
}
Then, specify a description, target resources this extension applies to, and the custom
properties that make up the schema. In this example, specify the courseId , courseName
and courseType custom properties and their types.
Notice that when you initially create a schema extension, its status is InDevelopment.
While you're developing the extension, you can keep it in this status, during which only
the app that created it can update it with additive changes or delete it. When you're
ready to share the extension for use by other apps, set status to Available.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/schemaExtensions
Content-type: application/json
{
"id":"graphlearn_courses",
"description": "Graph Learn training courses extensions",
"targetTypes": [
"Group"
],
"properties": [
{
"name": "courseId",
"type": "Integer"
},
{
"name": "courseName",
"type": "String"
},
{
"name": "courseType",
"type": "String"
}
]
}
Response
HTTP
{
"id": "graphlearn_courses",
"description": "Graph Learn training courses extensions",
"targetTypes": [
"Group"
],
"status": "InDevelopment",
"owner": "24d3b144-21ae-4080-943f-7067b395b913",
"properties": [
{
"name": "courseId",
"type": "Integer"
},
{
"name": "courseName",
"type": "String"
},
{
"name": "courseType",
"type": "String"
}
]
}
The response won't mirror back any data extensions. You need to explicitly $select the
extension by name using a GET /group/{id} operation.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/groups
Content-type: application/json
{
"displayName": "New Managers March 2017",
"description": "New Managers training course for March 2017",
"groupTypes": [
"Unified"
],
"mailEnabled": true,
"mailNickname": "newMan201703",
"securityEnabled": false,
"graphlearn_courses": {
"courseId": "123",
"courseName": "New Managers",
"courseType": "Online"
}
}
Response
HTTP
{
"id": "dfc8016f-db97-4c47-a582-49cb8f849355",
"createdDateTime": "2017-02-09T00:17:05Z",
"description": "New Managers training course for March 2017",
"displayName": "New Managers March 2017",
"groupTypes": [
"Unified"
],
"mail": "[email protected]",
"mailEnabled": true,
"mailNickname": "newMan201703",
"securityEnabled": false,
"theme": null,
"visibility": "Public"
}
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/groups/dfc8016f-db97-4c47-a582-
49cb8f849355
Content-type: application/json
{
"graphlearn_courses": {
"courseId": "123",
"courseName": "New Managers",
"courseType": "Online"
}
}
Response
HTTP
If you want to update the values of the extension data, put the entire extension complex
type in the body of a PATCH request (similar to adding custom data to an existing
resource).
To remove custom data added to a resource instance, but keep the schema extension
property on the resource instance, set the corresponding extension property to null .
To remove a schema extension from a resource instance, set the extension complex type
in that instance to null .
The following example looks for the group that has the graphlearn_courses extension
with a courseId property value matching 123 , and gets the group properties
displayName, id, and description, and the custom data in the graphlearn_courses
extension.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/groups?
$filter=graphlearn_courses/courseId eq
'123'&$select=displayName,id,description,graphlearn_courses
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"value": [
{
"displayName": "New Managers March 2017",
"id": "14429ae5-3e74-41a2-9fa8-028fbb984637",
"description": "New Managers training course for March 2017",
"graphlearn_courses": {
"@odata.type": "#microsoft.graph.ComplexExtensionValue",
"courseId": "123",
"courseName": "New Managers",
"courseType": "Online"
}
}
]
}
See also
Add custom data to resources using extensions
Add custom data to users using open extensions (preview)
schemaExtension resource type
OneDrive file storage API overview
Article • 09/09/2022
OneDrive is the files hub in Microsoft 365. People work with files in a variety of contexts,
like Microsoft Teams, groups, SharePoint, and more. With OneDrive, users can access
these files no matter where they are stored, and with Microsoft Graph, you can use a
single API to work with them.
Files in Microsoft 365 are stored in drives. Users can store files in a personal drive—their
OneDrive—or in a shared drive powered by a SharePoint document library. OneDrive's
flexibility lets users collaborate however it works best for them. Users can share links to
files, copy or move files to team drives, or even attach OneDrive files to mail messages
in Outlook.
https://www.youtube-nocookie.com/embed/vG-hQxFHCAE
With over 500 million devices running the OneDrive app and over 85% of the Fortune
500 using OneDrive for Business, by integrating your app with OneDrive, you can
connect with millions of consumers, students, and business users and engage with
customers where they already do their work every day.
API reference
Looking for the API reference for this service?
Next steps
Find out more about using the OneDrive API in Microsoft Graph v1.0.
Address resources in a drive on
OneDrive
Article • 06/22/2022
Learn how to access items within a drive on OneDrive with ID-based and path-based
addressing, and how to properly encode paths for Microsoft Graph.
ID-based addressing
OneDrive supports ID-based addressing of items. Items are assigned a unique identifier
when they are created and the ID persists across the actions a user performs on the
item. Renaming or moving the item will not change the item's ID.
ID-based addressing is a useful way to track items that might be moved by the user to
different locations on OneDrive. As long as you have the item's ID and the item exists,
you'll be able to find it.
Path-based addressing
OneDrive also supports path-based addressing. This allows you to use a friendly URL
syntax to address items relative to the hierarchy of items visible in OneDrive. If you know
the hierarchy to an item, you can directly address that item, without spending any time
making repeated calls to discover each level of the hierarchy.
However, since path-based addressing is based on the name of the item, renaming or
moving the item to a new location will cause the path of the item to change.
You can use path-based addressing relative to any item in OneDrive. For example, when
working with shared folders, you can use a path-based URL relative to the shared
folder's item ID to address something in the shared folder by path.
Examples
The following examples show the different URL formats available to access data. All of
these URLs are logically equivalent and return the content of MyFile.xlsx.
Path encoding
OneDrive supports addressing files and folders using the path of the item in the user's
OneDrive. However, because the path contains user specified content, which can
potentially contain characters that are not URL safe, you should ensure proper encoding
of any path segments.
Microsoft Graph expects that URLs conform to RFC 3986 . The following is a summary
of how to properly encode paths for Microsoft Graph.
7 Note
For more information, see Restrictions and limitations when you sync SharePoint
libraries to your computer through OneDrive for work or school .
URI path characters
When constructing the path segment of a URL for the Microsoft Graph API, the
following characters are allowed for path names, based on the URI RFC.
Item name characters, which are not included in the pchar group, such as # and
(space), must be percent encoded.
Encoding characters
Microsoft Graph uses standard percent encoding, where URL-invalid characters are
encoded with a % and then the UTF-8 character code for the character. For example:
Write this:
Instead of using those methods, you should use UriBuilder to construct a properly
escaped URL.
C#
Objective-C / iOS
For Objective-C, iOS and Mac OS X development, use the
stringByAddingPercentEncodingWithAllowedCharacters method and [NSCharacterSet
Objective-C
Android
Use the Uri.Builder class to construct a properly encoded URL.
Java
JavaScript
Use escape() in JavaScript to properly encode a path component.
JavaScript
Examples
Here is an example of a OneDrive user (Adele) with the following folder hierarchy:
OneDrive
\Adele's Files
\doc (1).docx
\estimate%s.docx
\Break#Out
\saved_game[1].bin
\...\estimate%.docx /root:/Adele's%20Files/estimate%25s.docx
\Break#Out /root:/Break%23Out
\...\saved_game[1].bin /root:/Break%23Out/saved_game[1].bin
See also
OneDrive file storage API overview
Dynamics 365 Business Central API
overview (preview)
Article • 06/22/2022
Authorization
Use the Azure AD v2.0 endpoint to authenticate Dynamics 365 Business Central APIs. All
APIs require the Authorization: Bearer {access-token} request header. For more
information about authorization, see Get access tokens to call Microsoft Graph.
API reference
Looking for the API reference for this service?
Azure Active Directory (Azure AD) helps centralize identity and access management
(IAM) to enable secure and productive access between apps, devices, services, and
infrastructure. Organizations can use Azure AD to manage identities and control access
in on-premises, hybrid, and cloud environments.
You can use the Azure AD REST APIs in Microsoft Graph to create unique workflows
between Azure AD resources and third-party services.
For many enterprise developers, Microsoft Graph and Azure AD help "lift and shift"
existing applications to the cloud, speeding an organization's digital transformation. You
can take advantage of Azure AD capabilities to add access control mechanisms to
applications, including verifying a user's group membership, directory role, or
administrative unit membership.
You can use Microsoft Graph and Azure AD as a way to quickly and easily reach more
than 15 million organizations, including 90% of the Fortune 500 companies that already
use Azure AD services. Integrated applications feature seamless sign-in experiences and
can use existing organizational data to create personalized experiences.
You can use the Azure AD APIs in Microsoft Graph to query the user's profile, find other
users, manage organizational relationships, track assignments, or create original
solutions that incorporate existing organizational data. These APIs provide a solid
foundation to seamlessly integrate custom business applications into an organization's
existing digital services.
Look up and manage user profile information for users in your organization, such
as name, photo, email address, job title, office location, and more.
Create groups for projects and teams in your organization. Add and remove
members from the group to control access to resources. (Dynamic groups can
automatically change membership based on user property values.)
Check for transitive membership in a list of groups or get all the resources of a
specified type (like user or group) from a list of generic resource IDs to control
access.
Manage devices
Manage devices registered in the organization. Devices are registered to users and
include items like laptops, desktops, tablets, and mobile phones. Devices are typically
created in the cloud using the Device Registration Service or by Microsoft Intune.
They're used by conditional access policies for multifactor authentication.
You can also manage domains associated with a tenant. Domain operations enable
Microsoft partners to automate domain registration for services such as Microsoft 365.
Tenant management
Azure AD APIs for tenant management allow you to:
Get information about an organization, such as its business address, technical and
notification contacts, active service subscriptions, and the domains associated with
it.
Get information about the service SKUs that a company is subscribed to.
Invite external (guest) users to an organization.
Monitor identity risks
Most security breaches are the result of attackers stealing a user’s identity, and attackers
have become terrifyingly effective in taking advantage of third-party breaches, password
spray attacks, and sophisticated phishing attacks. This means you need to protect all
your user accounts from these attacks and proactively prevent compromised identities
from being abused.
Azure AD uses adaptive machine learning algorithms and heuristics to detect anomalies
that indicate potentially compromised accounts. Using this data, Azure AD Identity
Protection protects your users with risk-based conditional access policies and generates
reports and alerts on its detections.
API reference
Looking for the API reference for this service?
Next steps
Find out how to Use the Azure AD REST APIs.
Use Azure AD to authenticate to Microsoft Graph.
Integrate Azure AD sign-in into your app or website.
See the Changelog for information about what's new in the Azure AD APIs.
Explore samples for more ideas about how to use Microsoft Graph.
Manage custom security attribute
assignments
Article • 06/01/2023
Custom security attributes in Azure Active Directory (Azure AD) are business-specific
attributes (key-value pairs) that you can define and assign to Azure AD objects. These
attributes can be used to store information, categorize objects, or enforce fine-grained
access control over specific Azure resources through Azure attribute-based access
control (Azure ABAC).
Custom security attributes are supported for users and service principals only. This
article provides examples of how to assign, update, list, or remove different types of
custom security attributes for users and applications using Microsoft Graph.
Prerequisites
Create custom security attributes. For more information about how to define and
manage custom security attribute definitions, see Overview of custom security
attributes using Microsoft Graph.
For delegated scenarios, the calling must be assigned the following permissions
and administrative roles.
To assign, update, or remove:
Azure AD roles: Attribute Assignment Administrator
Microsoft Graph permissions:
Users: CustomSecAttributeAssignment.ReadWrite.All and User.Read.All
Service principals: CustomSecAttributeAssignment.ReadWrite.All and
Application.Read.All
To read:
Azure AD roles: Attribute Assignment Reader or Attribute Assignment
Administrator
Microsoft Graph permissions:
Users: CustomSecAttributeAssignment.Read.All and User.Read.All
Service principals: CustomSecAttributeAssignment.Read.All and
Application.Read.All
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/{id}
Content-type: application/json
{
"customSecurityAttributes":
{
"Engineering":
{
"@odata.type":"#Microsoft.DirectoryServices.CustomSecurityAttributeValue
",
"ProjectDate":"2022-10-01"
}
}
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/servicePrincipals/{id}
Content-type: application/json
{
"customSecurityAttributes":
{
"Engineering":
{
"@odata.type":"#Microsoft.DirectoryServices.CustomSecurityAttributeValue
",
"ProjectDate":"2022-10-01"
}
}
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/{id}
Content-type: application/json
{
"customSecurityAttributes":
{
"Engineering":
{
"@odata.type":"#Microsoft.DirectoryServices.CustomSecurityAttributeValue
",
"[email protected]":"#Collection(String)",
"Project":["Baker","Cascade"]
}
}
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/{id}
Content-type: application/json
{
"customSecurityAttributes":
{
"Engineering":
{
"@odata.type":"#Microsoft.DirectoryServices.CustomSecurityAttributeValue
",
"[email protected]":"#Int32",
"NumVendors":4
}
}
}
Response
HTTP
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/{id}
Content-type: application/json
{
"customSecurityAttributes":
{
"Engineering":
{
"@odata.type":"#Microsoft.DirectoryServices.CustomSecurityAttributeValue
",
"[email protected]":"#Collection(Int32)",
"CostCenter":[1001,1003]
}
}
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/{id}
Content-type: application/json
{
"customSecurityAttributes":
{
"Engineering":
{
"@odata.type":"#Microsoft.DirectoryServices.CustomSecurityAttributeValue
",
"Certification":true
}
}
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/{id}
Content-type: application/json
{
"customSecurityAttributes":
{
"Engineering":
{
"@odata.type":"#Microsoft.DirectoryServices.CustomSecurityAttributeValue
",
"[email protected]":"#Int32",
"NumVendors":8
}
}
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/{id}
Content-type: application/json
{
"customSecurityAttributes":
{
"Engineering":
{
"@odata.type":"#Microsoft.DirectoryServices.CustomSecurityAttributeValue
",
"Certification":false
}
}
}
Response
HTTP
Attribute #1
Attribute #2
Attribute #3
Attribute #4
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users/{id}?
$select=customSecurityAttributes
Response
HTTP
HTTP/1.1 200 OK
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users(customSecurityAttributes)/
$entity",
"customSecurityAttributes": {
"Marketing": {
"@odata.type": "#microsoft.graph.customSecurityAttributeValue",
"EmployeeId": "QN26904"
},
"Engineering": {
"@odata.type": "#microsoft.graph.customSecurityAttributeValue",
"[email protected]": "#Collection(String)",
"Project": [
"Baker",
"Cascade"
],
"[email protected]": "#Collection(Int32)",
"CostCenter": [
1001
],
"Certification": true
}
}
}
If there are no custom security attributes assigned to the user or if the calling principal
does not have access, the following will be the response:
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users(customSecurityAttributes)/
$entity",
"customSecurityAttributes": null
}
User #1
User #2
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?
$count=true&$select=id,displayName,customSecurityAttributes&$filter=cust
omSecurityAttributes/Marketing/AppCountry eq 'Canada'
ConsistencyLevel: eventual
Response
HTTP
HTTP/1.1 200 OK
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users(id,displayName,customSecur
ityAttributes)",
"@odata.count": 2,
"value": [
{
"id": "dbaf3778-4f81-4ea0-ac1c-502a293c12ac",
"displayName": "Jiya",
"customSecurityAttributes": {
"Engineering": {
"@odata.type":
"#microsoft.graph.customSecurityAttributeValue",
"[email protected]": "#Collection(String)",
"Datacenter": [
"India"
]
},
"Marketing": {
"@odata.type":
"#microsoft.graph.customSecurityAttributeValue",
"[email protected]": "#Collection(String)",
"AppCountry": [
"India",
"Canada"
],
"EmployeeId": "KX19476"
}
}
},
{
"id": "6bac433c-48c6-4213-a316-1428de32701b",
"displayName": "Jana",
"customSecurityAttributes": {
"Marketing": {
"@odata.type":
"#microsoft.graph.customSecurityAttributeValue",
"[email protected]": "#Collection(String)",
"AppCountry": [
"Canada",
"Mexico"
],
"EmployeeId": "GS46982"
}
}
}
]
}
User #1
User #2
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?
$count=true&$select=id,displayName,customSecurityAttributes&$filter=star
tsWith(customSecurityAttributes/Marketing/EmployeeId,'GS')
ConsistencyLevel: eventual
Response
HTTP
HTTP/1.1 200 OK
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users(id,displayName,customSecur
ityAttributes)",
"@odata.count": 1,
"value": [
{
"id": "6bac433c-48c6-4213-a316-1428de32701b",
"displayName": "Jana",
"customSecurityAttributes": {
"Marketing": {
"@odata.type":
"#microsoft.graph.customSecurityAttributeValue",
"[email protected]": "#Collection(String)",
"AppCountry": [
"Canada",
"Mexico"
],
"EmployeeId": "GS46982"
}
}
}
]
}
User #1
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?
$count=true&$select=id,displayName,customSecurityAttributes&$filter=cust
omSecurityAttributes/Marketing/AppCountry ne 'Canada'
ConsistencyLevel: eventual
Response
HTTP
HTTP/1.1 200 OK
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users(id,displayName,customSecur
ityAttributes)",
"@odata.count": 32,
"value": [
{
"id": "c4f9ecd3-d3c1-4544-b49a-bc9bb62beb67",
"displayName": "Alain",
"customSecurityAttributes": null
},
{
"id": "de4f1218-b0fb-4449-b3a0-1e1dd193e6e7",
"displayName": "Joe",
"customSecurityAttributes": {
"Engineering": {
"@odata.type":
"#microsoft.graph.customSecurityAttributeValue",
"[email protected]": "#Collection(String)",
"Project3": [
"Baker",
"Cascade"
],
"[email protected]": "#Collection(Int32)",
"CostCenter": [
1001
],
"Certification": true
},
"Marketing": {
"@odata.type":
"#microsoft.graph.customSecurityAttributeValue",
"EmployeeId": "QN26904"
}
}
},
{
"id": "f24d1474-ded5-432d-be08-8abd39921aac",
"displayName": "Isabella",
"customSecurityAttributes": {
"Marketing": {
"@odata.type":
"#microsoft.graph.customSecurityAttributeValue",
"[email protected]": "#Collection(String)",
"AppCountry": [
"France"
]
}
}
},
{
"id": "849e81fe-1109-4d57-9536-a25d537eec1f",
"displayName": "Dara",
"customSecurityAttributes": {
"Engineering": {
"@odata.type":
"#microsoft.graph.customSecurityAttributeValue",
"ProjectDate": "2023-04-12"
}
}
},
{
"id": "42c88239-db99-45f0-85af-cbb6c8acb2a3",
"displayName": "Chandra",
"customSecurityAttributes": null
}
]
}
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/{id}
Content-type: application/json
{
"customSecurityAttributes":
{
"Engineering":
{
"@odata.type":"#Microsoft.DirectoryServices.CustomSecurityAttributeValue
",
"ProjectDate":null
}
}
}
Response
HTTP
HTTP/1.1 204 No Content
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/{id}
Content-type: application/json
{
"customSecurityAttributes":
{
"Engineering":
{
"@odata.type":"#Microsoft.DirectoryServices.CustomSecurityAttributeValue
",
"Project":[]
}
}
}
Response
HTTP
Next steps
Overview of custom security attributes using the Microsoft Graph API (Preview)
What are custom security attributes in Azure AD?
Assign Azure AD roles through
Privileged Identity Management (PIM)
APIs in Microsoft Graph
Article • 03/02/2023
In this tutorial, a fictitious company called Contoso Limited wishes to have its IT
Helpdesk manage the lifecycle of employees’ access. The company has identified the
Azure AD User Administrator role as the appropriate privileged role required by IT
Helpdesk, and will use the PIM API to assign the role.
You'll create a role-assignable security group for IT Helpdesk and using the PIM API,
assign the security group eligibility to the User Administrator role. By assigning the
eligible role to a security group, Contoso has a more efficient way to manage
administrator access to resources such as Azure AD roles. For example:
7 Note
The response objects shown in this tutorial might be shortened for readability.
Prerequisites
To complete this tutorial, you need the following resources and privileges:
A working Azure AD tenant with an Azure AD Premium P2 or EMS E5 license
enabled.
Sign in to an API client such as Graph Explorer , Postman, or create your own
client app to call Microsoft Graph. To call Microsoft Graph APIs in this tutorial, you
need to use an account with the Global Administrator role.
[Optional] Start a new session in another browser. You'll sign in later in this
tutorial.
Grant yourself the following delegated permissions: User.ReadWrite.All ,
Group.ReadWrite.All , Directory.Read.All ,
RoleEligibilitySchedule.ReadWrite.Directory , and
RoleAssignmentSchedule.ReadWrite.Directory , and
RoleManagement.ReadWrite.Directory .
Authenticator app installed on your phone to register a user for multifactor
authentication (MFA).
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
Content-Type: application/json
{
"accountEnabled": true,
"displayName": "Aline Dupuy",
"mailNickname": "AlineD",
"userPrincipalName": "[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn": true,
"password": "xWwvJ]6NMw+bWH-d"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"@odata.id": "https://graph.microsoft.com/v2/29a4f813-9274-4e1b-858d-
0afa98ae66d4/directoryObjects/7146daa8-1b4b-4a66-b2f7-
cf593d03c8d2/Microsoft.DirectoryServices.User",
"id": "7146daa8-1b4b-4a66-b2f7-cf593d03c8d2",
"displayName": "Aline Dupuy",
"userPrincipalName": "[email protected]"
}
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/groups
Content-type: application/json
{
"description": "IT Helpdesk to support Contoso employees",
"displayName": "IT Helpdesk (User)",
"mailEnabled": false,
"mailNickname": "userHelpdesk",
"securityEnabled": true,
"isAssignableToRole": true,
"[email protected]": [
"https://graph.microsoft.com/v1.0/users/1ed8ac56-4827-4733-8f80-
86adc2e67db5"
],
"[email protected]": [
"https://graph.microsoft.com/v1.0/users/1ed8ac56-4827-4733-8f80-
86adc2e67db5",
"https://graph.microsoft.com/v1.0/users/7146daa8-1b4b-4a66-b2f7-
cf593d03c8d2"
]
}
Response
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
"@odata.id": "https://graph.microsoft.com/v2/29a4f813-9274-4e1b-858d-
0afa98ae66d4/directoryObjects/e77cbb23-0ff2-4e18-819c-
690f58269752/Microsoft.DirectoryServices.Group",
"id": "e77cbb23-0ff2-4e18-819c-690f58269752",
"description": "IT Helpdesk to support Contoso employees",
"displayName": "IT Helpdesk (User)",
"groupTypes": [],
"isAssignableToRole": true,
"mailEnabled": false,
"mailNickname": "userHelpdesk",
"securityEnabled": true,
"securityIdentifier": "S-1-12-1-3883711267-1310199794-258579585-
1385637464",
"visibility": "Private",
"onPremisesProvisioningErrors": []
}
Step 3: Create a
unifiedRoleEligibilityScheduleRequest
Now that you have a security group, assign it as eligible for the User Administrator role.
In this step:
Request
Replace e77cbb23-0ff2-4e18-819c-690f58269752 with the value of the id of the IT
Helpdesk (User) security group. This principalId identifies the assignee of eligibility to
the User Administrator role. The roleDefinitionId fe930be7-5e62-47db-91af-98c3a49a38b1
is the global template identifier for the User Administrator role in Azure AD.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/roleManagement/directory/roleEligibilit
yScheduleRequests
Content-type: application/json
{
"action": "AdminAssign",
"justification": "Assign User Admin eligibility to IT Helpdesk
(User) group",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/",
"principalId": "e77cbb23-0ff2-4e18-819c-690f58269752",
"scheduleInfo": {
"startDateTime": "2021-07-01T00:00:00Z",
"expiration": {
"endDateTime": "2022-06-30T00:00:00Z",
"type": "AfterDateTime"
}
}
}
Response
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#roleManagement/directory/roleEli
gibilityScheduleRequests/$entity",
"id": "64a8bd54-4591-4f6a-9c77-3e9cb1fdd29b",
"status": "Provisioned",
"createdDateTime": "2021-09-03T20:45:28.3848182Z",
"completedDateTime": "2021-09-03T20:45:39.1194292Z",
"action": "AdminAssign",
"principalId": "e77cbb23-0ff2-4e18-819c-690f58269752",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/",
"isValidationOnly": false,
"targetScheduleId": "64a8bd54-4591-4f6a-9c77-3e9cb1fdd29b",
"justification": "Assign User Admin eligibility to IT Helpdesk (User)
group",
"createdBy": {
"user": {
"id": "1ed8ac56-4827-4733-8f80-86adc2e67db5"
}
},
"scheduleInfo": {
"startDateTime": "2021-09-03T20:45:39.1194292Z",
"expiration": {
"type": "afterDateTime",
"endDateTime": "2022-06-30T00:00:00Z"
}
},
"ticketInfo": {}
}
Request
In the following request, replace 7146daa8-1b4b-4a66-b2f7-cf593d03c8d2 with the value
of Aline's id.
HTTP
HTTP
GET
https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignment
s?$filter=principalId eq '7146daa8-1b4b-4a66-b2f7-cf593d03c8d2'
Response
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#roleManagement/directory/roleAss
ignments",
"value": []
}
The empty response object shows that Aline has no existing Azure AD roles in Contoso.
Aline will now activate their eligible User Administrator role for a limited time.
First, start the Authenticator app on your phone and open Aline Dupuy's account.
Sign in to Graph Explorer as Aline. You may use the another browser for this step. By
doing so, you won't interrupt your current session as a user in the Global Administrator
role. Alternatively, you can interrupt your current session by signing out of Graph
Explorer and signing back in as Aline.
Signed in as Aline, you'll first change your password because this was specified during
account creation. Then, because the administrator configured your account for MFA,
you'll be prompted to set up your account in the Authenticator app and be challenged
for MFA sign-in. This is because PIM requires that MFA for all active role assignments.
After signing in, activate your User Administrator role for five hours.
Request
To activate a role, call the roleAssignmentScheduleRequests endpoint. In this request, the
UserActivate action allows you to activate your eligible assignment, in this case for five
hours.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignment
ScheduleRequests
Content-type: application/json
{
"action": "SelfActivate",
"principalId": "7146daa8-1b4b-4a66-b2f7-cf593d03c8d2",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/",
"justification": "Need to invalidate all app refresh tokens for
Contoso users.",
"scheduleInfo": {
"startDateTime": "2021-09-04T15:13:00.000Z",
"expiration": {
"type": "AfterDuration",
"duration": "PT5H"
}
},
"ticketInfo": {
"ticketNumber": "CONTOSO:Security-012345",
"ticketSystem": "Contoso ICM"
}
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#roleManagement/directory/roleAss
ignmentScheduleRequests/$entity",
"id": "295edd40-4646-40ca-89b8-ab0b46b6f60e",
"status": "Granted",
"createdDateTime": "2021-09-03T21:10:49.6670479Z",
"completedDateTime": "2021-09-04T15:13:00Z",
"action": "SelfActivate",
"principalId": "7146daa8-1b4b-4a66-b2f7-cf593d03c8d2",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/",
"isValidationOnly": false,
"targetScheduleId": "295edd40-4646-40ca-89b8-ab0b46b6f60e",
"justification": "Need to invalidate all app refresh tokens for Contoso
users.",
"createdBy": {
"user": {
"id": "7146daa8-1b4b-4a66-b2f7-cf593d03c8d2"
}
},
"scheduleInfo": {
"startDateTime": "2021-09-04T15:13:00Z",
"expiration": {
"type": "afterDuration",
"endDateTime": null,
"duration": "PT5H"
}
},
"ticketInfo": {
"ticketNumber": "CONTOSO:Security-012345",
"ticketSystem": "Contoso ICM"
}
}
Back in the global administrator session, you have received notifications of both the
eligible assignment and the role activation. This allows the global administrator to be
aware of all elevations to administrator privileges across your organization.
Request
Replace e77cbb23-0ff2-4e18-819c-690f58269752 with the id of IT Support (Users) group.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/roleManagement/directory/roleEligibilit
yScheduleRequests
Content-type: application/json
{
"action": "AdminRemove",
"principalId": "e77cbb23-0ff2-4e18-819c-690f58269752",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/"
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#roleManagement/directory/roleEli
gibilityScheduleRequests/$entity",
"id": "dcd11a1c-300f-4d17-8c7a-523830400ec8",
"status": "Revoked",
"action": "AdminRemove",
"principalId": "e77cbb23-0ff2-4e18-819c-690f58269752",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/"
}
Delete the IT Support (Users) group
Request
Replace e77cbb23-0ff2-4e18-819c-690f58269752 with the id of IT Support (Users) group.
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/groups/e77cbb23-0ff2-4e18-819c-
690f58269752
Response
HTTP
Request
Replace 7146daa8-1b4b-4a66-b2f7-cf593d03c8d2 with the value of Aline's id.
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/users/7146daa8-1b4b-4a66-b2f7-
cf593d03c8d2
Response
HTTP
Authentication methods are the ways that users authenticate in Azure Active Directory
(Azure AD). Authentication methods in Azure AD include password and phone (for
example, SMS and voice calls), which are manageable in Microsoft Graph today, among
many others such as FIDO2 security keys and the Microsoft Authenticator app.
Authentication methods are used in primary, second-factor, and step-up authentication,
and also in the self-service password reset (SSPR) process.
You can use the authentication method APIs to manage a user's authentication
methods. For example, you can:
Add a phone number for a user, who can then use that number for SMS and voice
call authentication if they're enabled to use it by policy
Update or delete the phone number assigned to a user
Enable or disable the number for SMS sign-in
Reset a user's password
The APIs are a key tool to manage your users' authentication methods.
Global administrator
Privileged authentication administrator
Authentication administrator
Next, modify your permissions. We'll use UserAuthenticationMethod.ReadWrite.All for
this tutorial, so make sure it's enabled in Graph Explorer or your app.
Once the scope is assigned and consented, you can start using the API. The examples
here use a standard user named Avery Howard. You should use a preexisting test
account or create a new one following these instructions. These APIs are live so don't
test them on real users.
Request
HTTP
GET
https://graph.microsoft.com/beta/users/[email protected]/au
thentication/methods
Response
JSON
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('avery.howard%40wingtiptoy
sonline.com')/authentication/methods",
"value": [
{
"@odata.type": "#microsoft.graph.passwordAuthenticationMethod",
"id": "28c10230-6103-485e-b985-444c60001490",
"password": null,
"creationDateTime": null
}
]
}
Request
HTTP
POST
https://graph.microsoft.com/beta/users/[email protected]/au
thentication/phoneMethods
Content-Type: application/json
JSON
{
"phoneType": "mobile",
"phoneNumber": "+1 2065550123"
}
Response
JSON
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('avery.howard%40wingtiptoy
sonline.com')/authentication/phoneMethods/$entity",
"id": "3179e48a-750b-4051-897c-87b9720928f7",
"phoneNumber": "+1 2065550123",
"phoneType": "mobile",
"smsSignInState": "ready"
}
To add Avery's office number, you'll POST again to the same URL but update the phone
type and number:
Request
HTTP
POST
https://graph.microsoft.com/beta/users/[email protected]/au
thentication/phoneMethods
Content-Type: application/json
JSON
{
"phoneType": "office",
"phoneNumber": "+1 4255550199"
}
Response
JSON
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('avery.howard%40wingtiptoy
sonline.com')/authentication/phoneMethods/$entity",
"id": "e37fc753-ff3b-4958-9484-eaa9425c82bc",
"phoneNumber": "+1 4255550199",
"phoneType": "office",
"smsSignInState": "notSupported"
}
Do one more GET to the phone methods URL to see all of Avery's phone numbers:
Request
HTTP
GET
https://graph.microsoft.com/beta/users/[email protected]/au
thentication/phoneMethods
Response
JSON
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('avery.howard%40wingtiptoy
sonline.com')/authentication/phoneMethods",
"value": [
{
"id": "e37fc753-ff3b-4958-9484-eaa9425c82bc",
"phoneNumber": "+1 4255550199",
"phoneType": "office",
"smsSignInState": "notSupported"
},
{
"id": "3179e48a-750b-4051-897c-87b9720928f7",
"phoneNumber": "+1 2065550123",
"phoneType": "mobile",
"smsSignInState": "ready"
}
]
}
Request
HTTP
DELETE
https://graph.microsoft.com/beta/users/[email protected]/au
thentication/phoneMethods/e37fc753-ff3b-4958-9484-eaa9425c82bc
There's no data in the response because there's no more office phone as intended. You
can confirm it's gone by looking at all of Avery's methods, which is the same GET that
was made previously:
Request
HTTP
GET
https://graph.microsoft.com/beta/users/[email protected]/au
thentication/methods
Response
JSON
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('avery.howard%40wingtiptoy
sonline.com')/authentication/methods",
"value": [
{
"@odata.type": "#microsoft.graph.phoneAuthenticationMethod",
"id": "3179e48a-750b-4051-897c-87b9720928f7",
"phoneNumber": "+1 2065550123",
"phoneType": "mobile",
"smsSignInState": "ready"
},
{
"@odata.type": "#microsoft.graph.passwordAuthenticationMethod",
"id": "28c10230-6103-485e-b985-444c60001490",
"password": null,
"creationDateTime": null
}
]
}
As expected, the user is now back to only having one mobile phone and a password.
Request
HTTP
POST
https://graph.microsoft.com/beta/users/[email protected]/au
thentication/passwordMethods/28c10230-6103-485e-b985-
444c60001490/resetPassword
Content-Type: application/json
JSON
{
"newPassword": "29sdjfw#fajsdA_a_3an3223"
}
Response
HTTP
Location: https://graph.microsoft.com/beta/users/ed178e23-7447-4892-baf8-
fc46f8af26ce/authentication/operations/74bfa1a6-c0e0-4957-8c37-f91048f4959e?
aadgdc=BY01P&aadgsu=ssprprod-a
Because this is syncing the password down to Active Directory in the tenant's on-prem
infrastructure, it might take a few minutes, so you have an address where you can check
to see if it's complete. This address is in the location header of the response, and to see
the status do a GET on that URL.
Request
HTTP
GET https://graph.microsoft.com/beta/users/ed178e23-7447-4892-baf8-
fc46f8af26ce/authentication/operations/74bfa1a6-c0e0-4957-8c37-f91048f4959e?
aadgdc=BY01P&aadgsu=ssprprod-a
Response
JSON
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('ed178e23-7447-4892-baf8-
fc46f8af26ce')/authentication/operations/$entity",
"id": "74bfa1a6-c0e0-4957-8c37-f91048f4959e",
"createdDateTime": "2020-05-14T00:23:40Z",
"lastActionDateTime": "2020-05-14T00:23:41Z",
"status": "succeeded",
"statusDetail": "ResetSuccess",
"resourceLocation": "https://graph.microsoft.com/beta/users/ed178e23-
7447-4892-baf8-fc46f8af26ce/authentication/methods/28c10230-6103-485e-b985-
444c60001490"
}
And success! You've walked through seeing a user's profile, their auth methods, adding
and removing phone numbers, and resetting their password. Now you're ready to go
manage your own users' methods.
API reference
Looking for the API reference for authentication methods?
Next steps
Use Azure AD to authenticate to Microsoft Graph.
Integrate Azure AD sign-in into your app or website.
See the Changelog for information about what's new in the Azure AD APIs.
Explore examples for more ideas about how to use Microsoft Graph.
Identify and remediate risks using
Microsoft Graph
Article • 03/02/2023
Azure AD Identity Protection provides organizations insight into identity-based risk and
different ways to investigate and automatically remediate risk. The Identity Protection
APIs used in this tutorial can help you identify risk and configure a workflow to confirm
compromise or enable remediation. For more information, see What is risk?
In this tutorial, you learn how to generate a risky sign-in and remediate the risk status of
the user with a conditional access policy that requires multi-factor authentication (MFA).
An optional section shows you how to block the user from signing in also using a
conditional access policy, and dismissing the user risk.
7 Note
The response objects shown in this tutorial might be shortened for readability.
Prerequisites
To successfully complete this tutorial, make sure that you have the required
prerequisites:
You must have an Azure AD Premium P1 or P2 license to use the risk detection API.
This tutorial uses the Tor browser to sign in to the Azure portal anonymously. You
can use any anonymous browser to accomplish the task. To download the Tor
browser, see Download Tor Browser .
Sign in to an API client such as Graph Explorer , Postman, or create your own
client app to call Microsoft Graph. To call Microsoft Graph APIs in this tutorial, you
need to use an account with the Global Administrator role.
Grant yourself the following delegated permissions: IdentityRiskEvent.Read.All ,
IdentityRiskyUser.ReadWrite.All , Policy.Read.All ,
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
Content-type: application/json
{
"accountEnabled":true,
"displayName":"MyTestUser1",
"mailNickname":"MyTestUser1",
"userPrincipalName":"[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn":true,
"password":"Contoso1234"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"id": "4628e7df-dff3-407c-a08f-75f08c0806dc",
"businessPhones": [],
"displayName": "MyTestUser1",
"givenName": null,
"jobTitle": null,
"mail": null,
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "[email protected]"
}
1. Open the browser and enter portal.azure.com for the site address.
2. Sign in to the portal using the credentials for the MyTestUser1 account that you
previously created. You will be asked to change the existing password.
to get only the risk detections that are associated with the MyTestUser1 user account.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/identityProtection/riskDetections?
$filter=userDisplayName eq 'MyTestUser1'
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#riskDetections",
"value": [
{
"id":
"d52a631815aaa527bf642b196715da5cf0f35b6879204ea5b5c99b21bd4c16f4",
"requestId": "06f7fd18-b8f1-407d-86a3-f6cbe3a4be00",
"correlationId": "2a38abff-5701-4073-a81e-fd3aac09cba3",
"riskType": "anonymizedIPAddress",
"riskEventType": "anonymizedIPAddress",
"riskState": "atRisk",
"riskLevel": "medium",
"riskDetail": "none",
"source": "IdentityProtection",
"detectionTimingType": "realtime",
"activity": "signin",
"tokenIssuerType": "AzureAD",
"ipAddress": "178.17.170.23",
"activityDateTime": "2020-11-03T20:51:34.6245276Z",
"detectedDateTime": "2020-11-03T20:51:34.6245276Z",
"lastUpdatedDateTime": "2020-11-03T20:53:12.1984203Z",
"userId": "4628e7df-dff3-407c-a08f-75f08c0806dc",
"userDisplayName": "MyTestUser1",
"userPrincipalName": "[email protected]",
"additionalInfo": "[{\"Key\":\"userAgent\",\"Value\":\"Mozilla/5.0
(Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0\"}]",
"location": {
"city": "Chisinau",
"state": "Chisinau",
"countryOrRegion": "MD",
"geoCoordinates": {
"latitude": 47.0269,
"longitude": 28.8416
}
}
}
]
}
7 Note
1. Sign in the to the keep your account secure site using the MyTestUser1 account.
2. Complete the MFA setup procedure using the appropriate method for your
situation, such as having a text message sent to your phone.
Create the conditional access policy
The conditional access policy provides the ability to set the conditions of the policy to
identify sign-in risk levels. Risk levels can be low , medium , high , none . In the response
that was returned from listing the risk detections for MyTestUser1, we can see that the
risk level is medium . This example shows how to require MFA for MyTestUser1 who was
identified as a risky user.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies
Content-type: application/json
{
"displayName": "Policy for risky sign-in",
"state": "enabled",
"conditions": {
"signInRiskLevels": [
"high",
"medium"
],
"applications": {
"includeApplications": ["All"]
},
"users": {
"includeUsers": [
"4628e7df-dff3-407c-a08f-75f08c0806dc"
]
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"mfa"
]
}
}
Response
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identity/conditionalAccess/polic
ies/$entity",
"id": "9ad78153-b1f8-4714-adc1-1445727678a8",
"displayName": "Policy for risky sign-in",
"createdDateTime": "2020-11-03T20:56:38.6210843Z",
"modifiedDateTime": null,
"state": "enabled",
"sessionControls": null,
"conditions": {
"signInRiskLevels": [
"high",
"medium"
],
"clientAppTypes": [
"all"
],
"platforms": null,
"locations": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [],
"includeUserActions": []
},
"users": {
"includeUsers": [
"4628e7df-dff3-407c-a08f-75f08c0806dc"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [],
"includeRoles": [],
"excludeRoles": []
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"mfa"
],
"customAuthenticationFactors": [],
"termsOfUse": []
}
}
With this conditional access policy in place, the MyTestUser1 account is now required to
use MFA when signing in because the sign-in risk level is medium or high.
1. Open the browser and enter portal.azure.com for the site address.
2. Sign in to the portal using the credentials for the MyTestUser1 account and
complete the MFA process.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/identityProtection/riskDetections?
$filter=userDisplayName eq 'MyTestUser1'
Response
HTTP
{
"id": "ba9d45f16d8f87f6ae974efda7336b2120962a398cb362dfd9e5bdc8e9d149d0",
"requestId": "156c01fb-31cf-4a10-b9a9-beee93e6a400",
"correlationId": "a8aaac45-fe22-46df-babf-10a8dba85d62",
"riskType": "anonymizedIPAddress",
"riskEventType": "anonymizedIPAddress",
"riskState": "remediated",
"riskLevel": "medium",
"riskDetail": "userPassedMFADrivenByRiskBasedPolicy",
"source": "IdentityProtection",
"detectionTimingType": "realtime",
"activity": "signin",
"tokenIssuerType": "AzureAD",
"ipAddress": "185.220.101.213",
"activityDateTime": "2020-11-12T23:45:22.4092789Z",
"detectedDateTime": "2020-11-12T23:45:22.4092789Z",
"lastUpdatedDateTime": "2020-11-12T23:47:57.7831423Z",
"userId": "4b608561-9258-44ba-8cdb-3286dcbf0e3b",
"userDisplayName": "MyTestUser1",
"userPrincipalName": "[email protected]",
"additionalInfo": "[{\"Key\":\"userAgent\",\"Value\":\"Mozilla/5.0
(Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0\"}]",
"location": {
"city": "Schoenwalde-Glien",
"state": "Brandenburg",
"countryOrRegion": "DE",
"geoCoordinates": {
"latitude": 52.61983,
"longitude": 13.12743
}
}
}
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies
Content-type: application/json
{
"displayName": "Policy for risky sign-in block access",
"state": "enabled",
"conditions": {
"signInRiskLevels": [
"high",
"medium"
],
"applications": {
"includeApplications": ["All"]
},
"users": {
"includeUsers": [
"4628e7df-dff3-407c-a08f-75f08c0806dc"
]
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"block"
]
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identity/conditionalAccess/polic
ies/$entity",
"id": "9ad78153-b1f8-4714-adc1-1445727678a8",
"displayName": "Policy for risky sign-in block access",
"createdDateTime": "2020-11-03T20:56:38.6210843Z",
"modifiedDateTime": null,
"state": "enabled",
"sessionControls": null,
"conditions": {
"signInRiskLevels": [
"high",
"medium"
],
"clientAppTypes": [
"all"
],
"platforms": null,
"locations": null,
"applications": {
"includeApplications": [
"All"
],
"excludeApplications": [],
"includeUserActions": []
},
"users": {
"includeUsers": [
"4628e7df-dff3-407c-a08f-75f08c0806dc"
],
"excludeUsers": [],
"includeGroups": [],
"excludeGroups": [],
"includeRoles": [],
"excludeRoles": []
}
},
"grantControls": {
"operator": "OR",
"builtInControls": [
"block"
],
"customAuthenticationFactors": [],
"termsOfUse": []
}
}
With this conditional access policy in place, the MyTestUser1 account is now blocked
from signing in because the sign-in risk level is medium or high .
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/identityProtection/riskyUsers/dismiss
Content-Type: application/json
{
"userIds": [
"4628e7df-dff3-407c-a08f-75f08c0806dc"
]
}
Response
HTTP
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/identityProtection/riskyUsers?
$filter=userDisplayName eq 'MyTestUser1'
Response
HTTP
{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#riskyUsers",
"value": [
{
"id": "4628e7df-dff3-407c-a08f-75f08c0806dc",
"isDeleted": false,
"isProcessing": false,
"riskLevel": "none",
"riskState": "dismissed",
"riskDetail": "adminDismissedAllRiskForUser",
"riskLastUpdatedDateTime": "2020-11-03T21:48:53.4298425Z",
"userDisplayName": "MyTestUser1",
"userPrincipalName": "[email protected]"
}
]
}
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/users/4628e7df-dff3-407c-a08f-
75f08c0806dc
Response
HTTP
No Content - 204
Delete the conditional access policy
Delete the conditional access policy that you created.
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/groups/9ad78153-b1f8-4714-adc1-
1445727678a8
Response
HTTP
No Content - 204
See also
In this tutorial, you used many APIs to accomplish tasks. Explore the API reference for
these APIs to learn more about what the APIs can do.
The Lifecycle Workflows API in Microsoft Graph enables you to automate basic lifecycle
processes for your users at three levels: Joiner, Leaver, and Mover. Core to the workflows
are tasks, that represent the specific actions that run automatically when a workflow is
triggered.
Microsoft Graph supports 16 built-in tasks that you can use to create your custom
workflows. Each task has a set of arguments that are allowed for that task. For example,
a task to generate a temporary access pass (TAP) for a user allows you to configure the
lifetime of the TAP and whether the user can reuse it. A task to add a user to a group
requires you to specify the groups to which you want to add the user. This configuration
is made on the arguments property of a task and is based on the keyValuePair resource
type.
This article provides guidance on the allowed configuration for the arguments property
of tasks in Lifecycle Workflows.
name: customBody
value:The body of the customized email.
name: locale
value: Language value that overrides the email recipient's
language settings. Will not customize the custom text of the
email, and should be set in the same language as the custom
text.
Task taskDefinitionId arguments
description
name: customBody
value:The body of the customized email.
name: locale
value: Language value that overrides the email recipient's
language settings. Will not customize the custom text of the
email, and should be set in the same language as the custom
text.
Task taskDefinitionId arguments
description
name: customSubject
value: A custom subject for the email being sent.
name: customBody
value:The body of the customized email.
name: locale
value: Language value that overrides the email recipient's
language settings. Will not customize the custom text of the
email, and should be set in the same language as the custom
text.
name: customBody
value:The body of the customized email.
name: locale
value: Language value that overrides the email recipient's
language settings. Will not customize the custom text of the
email, and should be set in the same language as the custom
text.
Examples
HTTP
{
"category": "leaver",
"continueOnError": true,
"displayName": "Send offboarding email to user's manager after the last
day of work",
"description": "Send email after user’s last day",
"isEnabled": true,
"continueOnError": true,
"taskDefinitionId": "6f22ddd4-b3a5-47a4-a846-0d7c201a49ce",
"arguments": []
}
HTTP
{
"category": "leaver",
"description": "Add user to university alumni team",
"displayName": "AddUserToUniAlumniTeam",
"isEnabled": true,
"continueOnError": true,
"taskDefinitionId": "e440ed8d-25a1-4618-84ce-091ed5be5594",
"arguments": [
{
"name": "teamID",
"value": "e3cc382a-c4b6-4a8c-b26d-a9a3855421bd"
}
]
}
Next steps
Lifecycle Workflows
Automate employee onboarding tasks
before their first day of work using
Lifecycle Workflows APIs
Article • 03/02/2023
This tutorial provides step-by-step guidance for automating pre-hire tasks with Lifecycle
Workflows using Microsoft Graph.
This pre-hire scenario will generate a temporary password for the new employee and
send it via email to the user's new manager.
Prerequisites
To complete this tutorial, you need the following resources and privileges:
The tenant you want to use to preview the Lifecycle Workflows feature with an
Azure AD Premium P2 license enabled.
Sign in to an API client such as Graph Explorer , Postman, or create your own
client app to call Microsoft Graph. To call Microsoft Graph APIs in this tutorial, you
need to use an account with the Lifecycle Administrator or Global Administrator
Azure AD role.
You must have two user accounts to use for this tutorial, one for the new hire and
another for their manager.
department Used to provide the scope for the workflow. Set to Sales . Employee,
Manager
You must enable the Temporary Access Pass (TAP) policy in your tenant and the
new user enabled to use the authentication method. For more information, see
temporaryAccessPassAuthenticationMethodConfiguration resource type.
Request
The following request creates a pre-hire workflow with the following settings:
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows
Content-type: application/json
{
"displayName":"Onboard pre-hire employee",
"description":"Configure pre-hire tasks for onboarding employees
before their first day",
"isEnabled":true,
"isSchedulingEnabled": false,
"executionConditions": {
"@odata.type":
"microsoft.graph.identityGovernance.triggerAndScopeBasedConditions",
"scope": {
"@odata.type":
"microsoft.graph.identityGovernance.ruleBasedSubjectSet",
"rule": "(department eq 'Sales')"
},
"trigger": {
"@odata.type":
"microsoft.graph.identityGovernance.timeBasedAttributeTrigger",
"timeBasedAttribute": "employeeHireDate",
"offsetInDays": -2
}
},
"tasks":[
{
"isEnabled":true,
"category": "Joiner",
"taskDefinitionId":"1b555e50-7f65-41d5-b514-5894a026d10d",
"displayName":"Generate TAP And Send Email",
"description":"Generate Temporary Access Pass and send via
email to user's manager",
"arguments":[
{
"name": "tapLifetimeMinutes",
"value": "480"
},
{
"name": "tapIsUsableOnce",
"value": "true"
}
]
}
]
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/lifecycleWork
flows/workflows/$entity",
"category": "joiner",
"description": "Configure pre-hire tasks for onboarding employees before
their first day",
"displayName": "Onboard pre-hire employee",
"lastModifiedDateTime": "2022-10-04T07:45:14.3410141Z",
"createdDateTime": "2022-10-04T07:45:14.3410017Z",
"deletedDateTime": null,
"id": "ea71190c-075a-4ae7-9bca-34abf3b7b056",
"isEnabled": true,
"isSchedulingEnabled": false,
"nextScheduleRunDateTime": null,
"version": 1,
"executionConditions": {
"@odata.type":
"#microsoft.graph.identityGovernance.triggerAndScopeBasedConditions",
"scope": {
"@odata.type":
"#microsoft.graph.identityGovernance.ruleBasedSubjectSet",
"rule": "(department eq 'Sales')"
},
"trigger": {
"@odata.type":
"#microsoft.graph.identityGovernance.timeBasedAttributeTrigger",
"timeBasedAttribute": "employeeHireDate",
"offsetInDays": -2
}
}
}
Request
Because the workflow hasn't been scheduled to run, it must be run manually. In the
following request, the user for whom the workflow will run is identified by ID 8930f0c7-
cdd7-4885-9260-3b4a8111de5c .
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/ea71190c-075a-4ae7-9bca-34abf3b7b056/activate
{
"subjects": [
{
"id": "8930f0c7-cdd7-4885-9260-3b4a8111de5c"
}
]
}
Response
HTTP
Request
The following request retrieves the summary of tasks run at the user level.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/ea71190c-075a-4ae7-9bca-34abf3b7b056/userProcessingResults
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/lifecycleWork
flows/workflows('ea71190c-075a-4ae7-9bca-
34abf3b7b056')/userProcessingResults",
"value": [
{
"id": "5772d894-3bcf-4d1c-9cfc-8c182331215b",
"completedDateTime": "2022-10-04T08:07:23.2591226Z",
"failedTasksCount": 0,
"processingStatus": "completed",
"scheduledDateTime": "2022-10-04T08:07:03.8706523Z",
"startedDateTime": "2022-10-04T08:07:09.4670969Z",
"totalTasksCount": 1,
"totalUnprocessedTasksCount": 0,
"workflowExecutionType": "onDemand",
"workflowVersion": 1,
"subject": {
"id": "8930f0c7-cdd7-4885-9260-3b4a8111de5c"
}
}
]
}
Request
You can request the aggregate high-level summary of the user-level results for a
workflow, within a specified period.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/ea71190c-075a-4ae7-9bca-
34abf3b7b056/userProcessingResults/summary(startDateTime=2022-10-
01T00:00:00Z,endDateTime=2022-10-30T00:00:00Z)
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#microsoft.graph.identityGovernan
ce.userSummary",
"failedTasks": 0,
"failedUsers": 0,
"successfulUsers": 1,
"totalTasks": 1,
"totalUsers": 1
}
Request
You can also retrieve the detailed log of all tasks that were executed for a specific user in
the workflow.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/ea71190c-075a-4ae7-9bca-
34abf3b7b056/userProcessingResults/5772d894-3bcf-4d1c-9cfc-
8c182331215b/taskProcessingResults
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/lifecycleWork
flows/workflows('ea71190c-075a-4ae7-9bca-
34abf3b7b056')/userProcessingResults('5772d894-3bcf-4d1c-9cfc-
8c182331215b')/taskProcessingResults",
"value": [
{
"completedDateTime": "2022-10-04T08:07:15.9906441Z",
"createdDateTime": "2022-10-04T08:07:09.8072395Z",
"id": "227c85e4-7b84-461f-8df5-c347c2435eb2",
"processingStatus": "completed",
"startedDateTime": "2022-10-04T08:07:11.1595421Z",
"failureReason": null,
"subject": {
"id": "8930f0c7-cdd7-4885-9260-3b4a8111de5c"
},
"task": {
"category": "joiner",
"continueOnError": false,
"description": "Generate Temporary Access Pass and send via
email to user's manager",
"displayName": "Generate TAP And Send Email",
"executionSequence": 1,
"id": "8b9b47c0-957b-4a52-8f2d-816e59c40fd2",
"isEnabled": true,
"taskDefinitionId": "1b555e50-7f65-41d5-b514-5894a026d10d",
"arguments": [
{
"name": "tapLifetimeMinutes",
"value": "480"
},
{
"name": "tapIsUsableOnce",
"value": "true"
}
]
}
}
]
}
HTTP
HTTP
PATCH
https://graph.microsoft.com/beta/identityGovernance/lifecycleWorkflows/w
orkflows/ea71190c-075a-4ae7-9bca-34abf3b7b056
Content-type: application/json
{
"isEnabled": true,
"isSchedulingEnabled": true
}
When a workflow is scheduled, Lifecycle Workflows will check every three hours for
users in the associated execution condition and execute the configured tasks for those
users. You can customize this recurrence from between one hour to 24 hours.
Response
HTTP
See also
Automate employee onboarding tasks before their first day of work with Azure
portal (preview)
Overview of Azure AD Lifecycle Workflows
Overview of reporting in Azure AD Lifecycle Workflows
Automate employee offboarding tasks
after their last day of work using
Lifecycle Workflows APIs
Article • 03/02/2023
This tutorial provides step-by-step guidance for configuring offboarding tasks for
employees after their last day of work using Lifecycle workflows APIs in Microsoft Graph.
This post off-boarding scenario will run a scheduled workflow and accomplish the
following tasks:
Prerequisites
To complete this tutorial, you need the following resources and privileges:
The tenant you want to use to preview the Lifecycle Workflows feature with an
Azure AD Premium P2 license enabled.
Sign in to an API client such as Graph Explorer , Postman, or create your own
client app to call Microsoft Graph. To call Microsoft Graph APIs in this tutorial, you
need to use an account with the Lifecycle Administrator or Global Administrator
Azure AD role.
Grant yourself the following LifecycleWorkflows.ReadWrite.All delegated
permission.
Create a test user account that you'll use to represent an employee leaving your
organization. This test user account will be deleted when the workflow runs. Assign
licenses and Teams memberships to the test user account.
Request
The following request creates an offboarding workflow with the following settings:
It can currently be run on-demand but not on schedule. This step will allow us to
validate the workflow using the test user's account. The workflow will be updated
to run on schedule later in this tutorial.
The workflow runs seven days after the employee's employeeLeaveDateTime, and
if they are in the "Marketing" department.
Three workflow tasks are enabled to run in sequence: the user is unassigned all
licenses, then removed from all teams, then their user account is deleted.
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows
Content-type: application/json
{
"category": "leaver",
"displayName": "Post-Offboarding of an employee",
"description": "Configure offboarding tasks for employees after
their last day of work",
"isEnabled": true,
"isSchedulingEnabled": false,
"executionConditions": {
"@odata.type":
"#microsoft.graph.identityGovernance.triggerAndScopeBasedConditions",
"scope": {
"@odata.type":
"#microsoft.graph.identityGovernance.ruleBasedSubjectSet",
"rule": "department eq 'Marketing'"
},
"trigger": {
"@odata.type":
"#microsoft.graph.identityGovernance.timeBasedAttributeTrigger",
"timeBasedAttribute": "employeeLeaveDateTime",
"offsetInDays": 7
}
},
"tasks": [
{
"category": "leaver",
"continueOnError": false,
"description": "Remove all licenses assigned to the user",
"displayName": "Remove all licenses for user",
"executionSequence": 1,
"isEnabled": true,
"taskDefinitionId": "8fa97d28-3e52-4985-b3a9-a1126f9b8b4e",
"arguments": []
},
{
"category": "leaver",
"continueOnError": false,
"description": "Remove user from all Teams memberships",
"displayName": "Remove user from all Teams",
"executionSequence": 2,
"isEnabled": true,
"taskDefinitionId": "81f7b200-2816-4b3b-8c5d-dc556f07b024",
"arguments": []
},
{
"category": "leaver",
"continueOnError": false,
"description": "Delete user account in Azure AD",
"displayName": "Delete User Account",
"executionSequence": 3,
"isEnabled": true,
"taskDefinitionId": "8d18588d-9ad3-4c0f-99d0-ec215f0e3dff",
"arguments": []
}
]
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/lifecycleWork
flows/workflows/$entity",
"category": "leaver",
"description": "Configure offboarding tasks for employees after their
last day of work",
"displayName": "Post-Offboarding of an employee",
"lastModifiedDateTime": "2022-10-03T18:29:10.8412536Z",
"createdDateTime": "2022-10-03T18:29:10.8412352Z",
"deletedDateTime": null,
"id": "15239232-66ed-445b-8292-2f5bbb2eb833",
"isEnabled": true,
"isSchedulingEnabled": false,
"nextScheduleRunDateTime": null,
"version": 1,
"executionConditions": {
"@odata.type":
"#microsoft.graph.identityGovernance.triggerAndScopeBasedConditions",
"scope": {
"@odata.type":
"#microsoft.graph.identityGovernance.ruleBasedSubjectSet",
"rule": "department eq 'Marketing'"
},
"trigger": {
"@odata.type":
"#microsoft.graph.identityGovernance.timeBasedAttributeTrigger",
"timeBasedAttribute": "employeeLeaveDateTime",
"offsetInDays": 7
}
}
}
Request
Because the workflow hasn't been scheduled to run, it must be run manually, on-
demand. In the following request, the user for whom the workflow will run is identified
by ID df744d9e-2148-4922-88a8-633896c1e929 .
While you configured execution conditions for the workflow, this request to run the
workflow on demand ignores the execution conditions. For example, if the user
identified by ID df744d9e-2148-4922-88a8-633896c1e929 isn't in the "Marketing"
department or their employeeLeaveDateTime is set to null , this command will still run
the tasks that were defined in the workflow, for the user.
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/15239232-66ed-445b-8292-2f5bbb2eb833/activate
{
"subjects": [
{
"id": "df744d9e-2148-4922-88a8-633896c1e929"
}
]
}
Response
HTTP
Request
The following request retrieves the summary of tasks run at the user level.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/15239232-66ed-445b-8292-2f5bbb2eb833/userProcessingResults
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/lifecycleWork
flows/workflows('15239232-66ed-445b-8292-
2f5bbb2eb833')/userProcessingResults",
"value": [
{
"id": "40efc576-840f-47d0-ab95-5abca800f8a2",
"completedDateTime": "2022-10-03T18:31:00.3581066Z",
"failedTasksCount": 0,
"processingStatus": "completed",
"scheduledDateTime": "2022-10-03T18:30:43.154495Z",
"startedDateTime": "2022-10-03T18:30:46.9357178Z",
"totalTasksCount": 3,
"totalUnprocessedTasksCount": 0,
"workflowExecutionType": "onDemand",
"workflowVersion": 1,
"subject": {
"id": "df744d9e-2148-4922-88a8-633896c1e929"
}
}
]
}
Request
You can request the aggregate high-level summary of the user-level results for a
workflow, within a specified period.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/15239232-66ed-445b-8292-
2f5bbb2eb833/userProcessingResults/summary(startDateTime=2022-10-
01T00:00:00Z,endDateTime=2022-10-30T00:00:00Z)
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#microsoft.graph.identityGovernan
ce.userSummary",
"failedTasks": 0,
"failedUsers": 0,
"successfulUsers": 1,
"totalTasks": 3,
"totalUsers": 1
}
Request
You can also retrieve the detailed log of all tasks that were executed for a specific user in
the workflow.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/15239232-66ed-445b-8292-
2f5bbb2eb833/userProcessingResults/40efc576-840f-47d0-ab95-
5abca800f8a2/taskProcessingResults
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/lifecycleWork
flows/workflows('15239232-66ed-445b-8292-
2f5bbb2eb833')/userProcessingResults('40efc576-840f-47d0-ab95-
5abca800f8a2')/taskProcessingResults",
"value": [
{
"completedDateTime": "2022-10-03T18:30:50.483365Z",
"createdDateTime": "2022-10-03T18:30:47.6125438Z",
"id": "78650318-7238-4e7e-852f-2c36cbeff340",
"processingStatus": "completed",
"startedDateTime": "2022-10-03T18:30:50.0549446Z",
"failureReason": null,
"subject": {
"id": "df744d9e-2148-4922-88a8-633896c1e929"
},
"task": {
"category": "leaver",
"continueOnError": false,
"description": "Remove all licenses assigned to the user",
"displayName": "Remove all licenses for user",
"executionSequence": 1,
"id": "f71246b2-269c-4ba6-ab8e-afc1a05114cb",
"isEnabled": true,
"taskDefinitionId": "8fa97d28-3e52-4985-b3a9-a1126f9b8b4e",
"arguments": []
}
},
{
"completedDateTime": "2022-10-03T18:30:57.6034021Z",
"createdDateTime": "2022-10-03T18:30:47.8824313Z",
"id": "3d2e459d-5614-42e4-952b-0e917b5f6646",
"processingStatus": "completed",
"startedDateTime": "2022-10-03T18:30:53.6770279Z",
"failureReason": null,
"subject": {
"id": "df744d9e-2148-4922-88a8-633896c1e929"
},
"task": {
"category": "leaver",
"continueOnError": false,
"description": "Remove user from all Teams memberships",
"displayName": "Remove user from all Teams",
"executionSequence": 2,
"id": "ed545f03-e8d8-45fb-9cbd-15c937f2a866",
"isEnabled": true,
"taskDefinitionId": "81f7b200-2816-4b3b-8c5d-dc556f07b024",
"arguments": []
}
},
{
"completedDateTime": "2022-10-03T18:31:00.0894515Z",
"createdDateTime": "2022-10-03T18:30:48.0004721Z",
"id": "03359fa6-c63c-4573-92c2-4c9518ca98aa",
"processingStatus": "completed",
"startedDateTime": "2022-10-03T18:30:59.6195169Z",
"failureReason": null,
"subject": {
"id": "df744d9e-2148-4922-88a8-633896c1e929"
},
"task": {
"category": "leaver",
"continueOnError": false,
"description": "Delete user account in Azure AD",
"displayName": "Delete User Account",
"executionSequence": 3,
"id": "b4cefaa0-6ceb-461d-bbf5-ec69246463fd",
"isEnabled": true,
"taskDefinitionId": "8d18588d-9ad3-4c0f-99d0-ec215f0e3dff",
"arguments": []
}
}
]
}
HTTP
PATCH
https://graph.microsoft.com/beta/identityGovernance/lifecycleWorkflows/w
orkflows/15239232-66ed-445b-8292-2f5bbb2eb833
Content-type: application/json
{
"isEnabled": true,
"isSchedulingEnabled": true
}
When a workflow is scheduled, Lifecycle Workflows will check every three hours for
users in the associated execution condition and execute the configured tasks for those
users. You can customize this recurrence from between one hour to 24 hours.
Response
HTTP
See also
Automate employee offboarding tasks after their last day of work with Azure portal
(preview)
Overview of Azure AD Lifecycle Workflows
Overview of reporting in Azure AD Lifecycle Workflows
Complete employee offboarding tasks
in real-time on their last day of work
using Lifecycle Workflows APIs
Article • 03/02/2023
This post off-boarding scenario will run a workflow on-demand and accomplish the
following tasks:
Prerequisites
To complete this tutorial, you need the following resources and privileges:
The tenant you want to use to preview the Lifecycle Workflows feature with an
Azure AD Premium P2 license enabled.
Sign in to an API client such as Graph Explorer , Postman, or create your own
client app to call Microsoft Graph. To call Microsoft Graph APIs in this tutorial, you
need to use an account with the Lifecycle Administrator or Global Administrator
Azure AD role.
Grant yourself the following LifecycleWorkflows.ReadWrite.All delegated
permission.
Create a test user account that you'll use to represent an employee leaving your
organization. This test user account will be deleted when the workflow runs. Assign
licenses and Teams memberships to the test user account.
Request
The following request creates an offboarding workflow with the following settings:
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows
Content-type: application/json
{
"category": "Leaver",
"displayName": "Real-time employee termination",
"description": "Execute real-time termination tasks for employees on
their last day of work",
"isEnabled": true,
"isSchedulingEnabled": false,
"executionConditions":{
"@odata.type":"#microsoft.graph.identityGovernance.onDemandExecutionOnly
"
},
"tasks": [
{
"continueOnError": false,
"description": "Remove user from all Azure AD groups
memberships",
"displayName": "Remove user from all groups",
"executionSequence": 1,
"isEnabled": true,
"taskDefinitionId": "b3a31406-2a15-4c9a-b25b-a658fa5f07fc",
"arguments": []
},
{
"continueOnError": false,
"description": "Remove user from all Teams memberships",
"displayName": "Remove user from all Teams",
"executionSequence": 2,
"isEnabled": true,
"taskDefinitionId": "81f7b200-2816-4b3b-8c5d-dc556f07b024",
"arguments": []
},
{
"continueOnError": false,
"description": "Delete user account in Azure AD",
"displayName": "Delete User Account",
"executionSequence": 3,
"isEnabled": true,
"taskDefinitionId": "8d18588d-9ad3-4c0f-99d0-ec215f0e3dff",
"arguments": []
}
]
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/lifecycleWork
flows/workflows/$entity",
"category": "leaver",
"description": "Execute real-time termination tasks for employees on
their last day of work",
"displayName": "Real-time employee termination",
"lastModifiedDateTime": "2022-10-04T08:33:01.0619748Z",
"createdDateTime": "2022-10-04T08:33:01.0619653Z",
"deletedDateTime": null,
"id": "368dfba3-2303-4e02-b258-87d742187e1b",
"isEnabled": true,
"isSchedulingEnabled": false,
"nextScheduleRunDateTime": null,
"version": 1,
"executionConditions": {
"@odata.type":
"#microsoft.graph.identityGovernance.onDemandExecutionOnly"
}
}
Request
In the following request, the user for whom the workflow will run is identified by ID
8930f0c7-cdd7-4885-9260-3b4a8111de5c .
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/368dfba3-2303-4e02-b258-87d742187e1b/activate
{
"subjects": [
{
"id": "8930f0c7-cdd7-4885-9260-3b4a8111de5c"
}
]
}
Response
HTTP
Request
The following request retrieves the summary of tasks run at the user level.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/368dfba3-2303-4e02-b258-87d742187e1b/userProcessingResults
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/lifecycleWork
flows/workflows('368dfba3-2303-4e02-b258-
87d742187e1b')/userProcessingResults",
"value": [
{
"id": "bc5b9d36-55fb-4036-8551-582668a6b78e",
"completedDateTime": "2022-10-04T08:37:47.3197648Z",
"failedTasksCount": 0,
"processingStatus": "completed",
"scheduledDateTime": "2022-10-04T08:37:28.3040665Z",
"startedDateTime": "2022-10-04T08:37:32.1018797Z",
"totalTasksCount": 3,
"totalUnprocessedTasksCount": 0,
"workflowExecutionType": "onDemand",
"workflowVersion": 1,
"subject": {
"id": "8930f0c7-cdd7-4885-9260-3b4a8111de5c"
}
}
]
}
Request
You can request the aggregate high-level summary of the user-level results for a
workflow, within a specified period.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/368dfba3-2303-4e02-b258-
87d742187e1b/userProcessingResults/summary(startDateTime=2022-10-
01T00:00:00Z,endDateTime=2022-10-30T00:00:00Z)
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#microsoft.graph.identityGovernan
ce.userSummary",
"failedTasks": 0,
"failedUsers": 0,
"successfulUsers": 1,
"totalTasks": 3,
"totalUsers": 1
}
Request
You can also retrieve the detailed log of all tasks that were executed for a specific user in
the workflow.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/LifecycleWorkflows/w
orkflows/368dfba3-2303-4e02-b258-
87d742187e1b/userProcessingResults/bc5b9d36-55fb-4036-8551-
582668a6b78e/taskProcessingResults
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/lifecycleWork
flows/workflows('368dfba3-2303-4e02-b258-
87d742187e1b')/userProcessingResults('bc5b9d36-55fb-4036-8551-
582668a6b78e')/taskProcessingResults",
"value": [
{
"completedDateTime": "2022-10-04T08:37:37.1440809Z",
"createdDateTime": "2022-10-04T08:37:32.6985496Z",
"id": "0819ee66-f85c-49a2-bdbd-3bbdbb3c1797",
"processingStatus": "completed",
"startedDateTime": "2022-10-04T08:37:36.2260254Z",
"failureReason": null,
"subject": {
"id": "8930f0c7-cdd7-4885-9260-3b4a8111de5c"
},
"task": {
"category": "leaver",
"continueOnError": false,
"description": "Remove user from all Azure AD groups
memberships",
"displayName": "Remove user from all groups",
"executionSequence": 1,
"id": "ab400768-ff1e-4a2f-ac0e-bae5d8419613",
"isEnabled": true,
"taskDefinitionId": "b3a31406-2a15-4c9a-b25b-a658fa5f07fc",
"arguments": []
}
},
{
"completedDateTime": "2022-10-04T08:37:42.8173083Z",
"createdDateTime": "2022-10-04T08:37:32.76041Z",
"id": "f1e16080-0117-41ba-9632-74eb60a4b005",
"processingStatus": "completed",
"startedDateTime": "2022-10-04T08:37:38.383087Z",
"failureReason": null,
"subject": {
"id": "8930f0c7-cdd7-4885-9260-3b4a8111de5c"
},
"task": {
"category": "leaver",
"continueOnError": false,
"description": "Remove user from all Teams memberships",
"displayName": "Remove user from all Teams",
"executionSequence": 2,
"id": "b49e306a-17ad-4bed-89cb-f312b9d30eb3",
"isEnabled": true,
"taskDefinitionId": "81f7b200-2816-4b3b-8c5d-dc556f07b024",
"arguments": []
}
},
{
"completedDateTime": "2022-10-04T08:37:46.8305324Z",
"createdDateTime": "2022-10-04T08:37:33.0279549Z",
"id": "21d40600-259a-4581-a011-0a56d2ee6e7a",
"processingStatus": "completed",
"startedDateTime": "2022-10-04T08:37:46.3131624Z",
"failureReason": null,
"subject": {
"id": "8930f0c7-cdd7-4885-9260-3b4a8111de5c"
},
"task": {
"category": "leaver",
"continueOnError": false,
"description": "Delete user account in Azure AD",
"displayName": "Delete User Account",
"executionSequence": 3,
"id": "ce568616-5615-4783-a519-6bec9f13514e",
"isEnabled": true,
"taskDefinitionId": "8d18588d-9ad3-4c0f-99d0-ec215f0e3dff",
"arguments": []
}
}
]
}
Next steps
Execute employee offboarding tasks in real-time on their last day of work with
Azure portal (preview)
Overview of Azure AD Lifecycle Workflows
Overview of reporting in Azure AD Lifecycle Workflows
Configure the employeeLeaveDateTime
property for a user
Article • 03/02/2023
This article describes how to configure the employeeLeaveDateTime attribute for a user.
This property can be used as a trigger for "leaver" workflows created using Lifecycle
Workflows.
Permissions
One of the following permissions is required to call this API. To learn more, including
how to choose permissions, see Permissions.
For delegated scenarios, the admin must also have the Global Administrator Azure AD
role.
Request
The following example shows a user who will leave on September 30, 2022 at 23:59.
HTTP
HTTP
PATCH https://graph.microsoft.com/beta/users/df744d9e-2148-4922-88a8-
633896c1e929
{
"employeeLeaveDateTime": "2022-09-30T23:59:59Z"
}
Next steps
Lifecycle Workflows API overview
How to synchronize attributes for Lifecycle workflows
Manage access to resources using the
entitlement management APIs in
Microsoft Graph
Article • 03/02/2023
Managing access to all the resources that employees need, such as groups, applications,
and sites, is an important function for organizations. You want to grant employees the
right level of access they need to be productive and remove their access when it is no
longer needed. Azure Active Directory (Azure AD) entitlement management using
Microsoft Graph APIs enables you to manage this type of access.
In this tutorial, you learn how to develop code to create a package of resources for a
marketing campaign that internal users can self-service request. Requests do not require
approval and user's access expires after 30 days. For this tutorial, the marketing
campaign resources are just membership in a single group, but it could be a collection
of groups, applications, or SharePoint Online sites.
7 Note
The response objects shown in this tutorial might be shortened for readability.
Prerequisites
To successfully complete this tutorial, make sure that you have the required
prerequisites:
information on the Azure Active Directory overview page. Record the value of the id
property that is returned to be used later in the tutorial.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
Content-type: application/json
{
"accountEnabled":true,
"displayName":"Requestor1",
"mailNickname":"Requestor1",
"userPrincipalName":"[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn":true,
"password":"Contoso1234"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"id": "007d1c7e-7fa8-4e33-b678-5e437acdcddc",
"deletedDateTime": null,
"accountEnabled": true,
"ageGroup": null,
"businessPhones": [],
"city": null,
"createdDateTime": null,
"creationType": null,
"companyName": null,
"consentProvidedForMinor": null,
"country": null,
"department": null,
"displayName": "Requestor1",
"employeeId": null,
"faxNumber": null,
"givenName": null,
"imAddresses": [],
"infoCatalogs": [],
"isResourceAccount": null,
"jobTitle": null,
"legalAgeGroupClassification": null,
"mail": null,
"mailNickname": "Requestor1",
}
Create a group
In this tutorial, you create a group named Marketing resources that is the target
resource for entitlement management. You can use an existing group if you already have
one. Record the value of the id property that is returned to use later in this tutorial.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/groups
Content-type: application/json
{
"description":"Marketing group",
"displayName":"Marketing resources",
"mailEnabled":false,
"mailNickname":"markres",
"securityEnabled":true
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
"id": "e93e24d1-2b65-4a6c-a1dd-654a12225487",
"deletedDateTime": null,
"classification": null,
"createdDateTime": "2020-06-24T16:47:37Z",
"createdByAppId": "de8bc8b5-d9f9-48b1-a8ad-b748da725064",
"description": "Marketing group",
"displayName": "Marketing resources",
"expirationDateTime": null,
"groupTypes": [],
"infoCatalogs": [],
"isAssignableToRole": null,
"mail": null,
"mailEnabled": false,
"mailNickname": "markres"
}
Request
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackageCatalogs?$filter=(displayName eq 'General')
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#accessPackageCatalogs",
"value": [
{
"id": "cec5d6ab-c75d-47c0-9c1c-92e89f66e384",
"displayName": "General",
"description": "Built-in catalog.",
"catalogType": "ServiceDefault",
"catalogStatus": "Published",
"isExternallyVisible": true,
"createdBy": "Azure AD",
"createdDateTime": "2020-05-30T10:58:05.363Z",
"modifiedBy": "Azure AD",
"modifiedDateTime": "2020-05-30T10:58:05.363Z"
}
]
}
The response should only contain the catalog whose name you provided in the request.
If there are no values returned, check that the name of the catalog is correct before you
proceed.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackageResourceRequests
Content-type: application/json
{
"catalogId":"cec5d6ab-c75d-47c0-9c1c-92e89f66e384",
"requestType": "AdminAdd",
"justification": "",
"accessPackageResource": {
"displayName": "Marketing resources",
"description": "Marketing group",
"resourceType": "AadGroup",
"originId": "e93e24d1-2b65-4a6c-a1dd-654a12225487",
"originSystem": "AadGroup"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/entitlementMa
nagement/accessPackageResourceRequests/$entity",
"catalogId": "cec5d6ab-c75d-47c0-9c1c-92e89f66e384",
"executeImmediately": false,
"id": "44e521e0-fb6b-4d5e-a282-e7e68dc59493",
"requestType": "AdminAdd",
"requestState": "Delivered",
"requestStatus": "Fulfilled",
"isValidationOnly": false,
"expirationDateTime": null,
"justification": ""
}
Request
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackageCatalogs/cec5d6ab-c75d-47c0-9c1c-
92e89f66e384/accessPackageResources?$filter=(displayName eq 'Marketing
resources')
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#accessPackageResources",
"value": [
{
"id": "4a1e21c5-8a76-4578-acb1-641160e076e8",
"displayName": "Marketing resources",
"description": "Marketing group",
"url": "https://account.activedirectory.windowsazure.com/r?
tenantId=d3030981-8fb9-4919-9980-5580caeddd75#/manageMembership?
objectType=Group&objectId=e93e24d1-2b65-4a6c-a1dd-654a12225487",
"resourceType": "Security Group",
"originId": "e93e24d1-2b65-4a6c-a1dd-654a12225487",
"originSystem": "AadGroup",
"isPendingOnboarding": false,
"addedBy": "[email protected]",
"addedOn": "2020-08-21T19:27:29.967Z"
}
]
}
In the request, use the id of the catalog and the id of the group resource in the catalog
that you recorded to get the originId of the Member resource role. Record the value of
the originId property to use later in this tutorial.
Request
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackageCatalogs/cec5d6ab-c75d-47c0-9c1c-
92e89f66e384/accessPackageResourceRoles?$filter=
(originSystem+eq+%27AadGroup%27+and+accessPackageResource/id+eq+%274a1e2
1c5-8a76-4578-acb1-
641160e076e8%27+and+displayName+eq+%27Member%27)&$expand=accessPackageRe
source
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/entitlementMa
nagement/accessPackageCatalogs('ede67938-cda7-4127-a9ca-
7c7bf86a19b7')/accessPackageResourceRoles(accessPackageResource())",
"value": [
{
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "Member",
"description": null,
"originSystem": "AadGroup",
"originId": "Member_e93e24d1-2b65-4a6c-a1dd-654a12225487",
"accessPackageResource": {
"id": "4a1e21c5-8a76-4578-acb1-641160e076e8",
"displayName": "Marketing resources",
"description": "Marketing group",
"url": "https://account.activedirectory.windowsazure.com/r?
tenantId=d3030981-8fb9-4919-9980-5580caeddd75#/manageMembership?
objectType=Group&objectId=e93e24d1-2b65-4a6c-a1dd-654a12225487",
"resourceType": "Security Group",
"originId": "e93e24d1-2b65-4a6c-a1dd-654a12225487",
"originSystem": "AadGroup",
"isPendingOnboarding": false,
"addedBy": "[email protected]",
"addedOn": "2020-06-26T17:13:23.723Z",
"accessPackageResourceScopes": []
}
}
]
}
If successful, a single value is returned, which represents the Member role of that group.
If no roles are returned, check the id values of the catalog and the access package
resource.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackages
Content-type: application/json
{
"catalogId": "cec5d6ab-c75d-47c0-9c1c-92e89f66e384",
"displayName": "Marketing Campaign",
"description": "Access to resources for the campaign"
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/entitlementMa
nagement/accessPackages/$entity",
"id": "88203d16-0e31-41d4-87b2-dd402f1435e9",
"catalogId": "cec5d6ab-c75d-47c0-9c1c-92e89f66e384",
"displayName": "Marketing Campaign",
"description": "Access to resources for the campaign",
"isHidden": false,
"isRoleScopesVisible": false,
"createdBy": "[email protected]",
"createdDateTime": "2020-08-21T19:45:33.2042281Z",
"modifiedBy": "[email protected]",
"modifiedDateTime": "2020-08-21T19:45:33.2042281Z"
}
Request
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackages/88203d16-0e31-41d4-87b2-
dd402f1435e9/accessPackageResourceRoleScopes
Content-type: application/json
{
"accessPackageResourceRole": {
"originId":"Member_e93e24d1-2b65-4a6c-a1dd-654a12225487",
"displayName":"Member",
"originSystem":"AadGroup",
"accessPackageResource": {
"id":"4a1e21c5-8a76-4578-acb1-
641160e076e8","resourceType":"Security Group",
"originId":"e93e24d1-2b65-4a6c-a1dd-
654a12225487","originSystem":"AadGroup"
}
},
"accessPackageResourceScope": {
"originId":"e93e24d1-2b65-4a6c-a1dd-
654a12225487","originSystem":"AadGroup"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#identityGovernance/entitlementMa
nagement/accessPackages('88203d16-0e31-41d4-87b2-
dd402f1435e9')/accessPackageResourceRoleScopes/$entity",
"id": "e081321b-2802-4834-a6ca-6f598ce3cdf7_6dbd2209-9d14-4c76-b92b-
fcb00e835fe1",
"createdBy": "[email protected]",
"createdDateTime": "2020-08-21T19:56:00.6320729Z",
"modifiedBy": "[email protected]",
"modifiedDateTime": "2020-08-21T19:56:00.6320729Z"
}
The access package now has one resource role, which is group membership. The role is
assigned to any user who has the access package.
The value of the durationInDays property enables the Requestor1 account to access the
resources in the access package for up to 30 days. Record the value of the id property
that is returned to use later in this tutorial.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackageAssignmentPolicies
Content-type: application/json
{
"accessPackageId": "88203d16-0e31-41d4-87b2-dd402f1435e9",
"displayName": "Specific users",
"description": "Specific users can request assignment",
"accessReviewSettings": null,
"durationInDays": 30,
"requestorSettings": {
"scopeType": "SpecificDirectorySubjects",
"acceptRequests": true,
"allowedRequestors": [
{
"@odata.type": "#microsoft.graph.singleUser",
"isBackup": false,
"id": "007d1c7e-7fa8-4e33-b678-5e437acdcddc",
"description": "Requestor1"
}
]
},
"requestApprovalSettings": {
"isApprovalRequired": false,
"isApprovalRequiredForExtension": false,
"isRequestorJustificationRequired": false,
"approvalMode": "NoApproval",
"approvalStages": []
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#accessPackageAssignmentPolicies/
$entity",
"id": "db440482-1210-4a60-9b55-3ac7a72f63ba",
"accessPackageId": "88203d16-0e31-41d4-87b2-dd402f1435e9",
"displayName": "Specific users",
"description": "Specific users can request assignment",
"canExtend": false,
"durationInDays": 30,
"expirationDateTime": null,
"createdBy": "[email protected]",
"createdDateTime": "2020-06-29T19:47:44.7399675Z",
"modifiedBy": "[email protected]",
"modifiedDateTime": "2020-06-29T19:47:44.7555489Z",
"accessReviewSettings": null,
"requestorSettings": {
"scopeType": "SpecificDirectorySubjects",
"acceptRequests": true,
"allowedRequestors": [
{
"@odata.type": "#microsoft.graph.singleUser",
"isBackup": false,
"id": "007d1c7e-7fa8-4e33-b678-5e437acdcddc",
"description": "Requestor1"
}
]
},
"requestApprovalSettings": {
"isApprovalRequired": false,
"isApprovalRequiredForExtension": false,
"isRequestorJustificationRequired": false,
"approvalMode": "NoApproval",
"approvalStages": []
}
}
To request access to resources in the access package, you need to provide these values:
id of the Requestor1 user account that you created for the value of the targetId
property
id of the assignment policy for the value of the assignmentPolicyId property
id of the access package for the value of accessPackageId property
In the response you can see the status of Accepted and a state of Submitted. Record
the value of the id property that is returned to get the status of the request later.
If you haven't done so already, sign out of the administrator account that you were
using in Microsoft Graph Explorer. Sign in to the Requestor1 user account that you
created. You will be asked to change the password if it is the first time you are signing
in.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackageAssignmentRequests
Content-type: application/json
{
"requestType": "UserAdd",
"accessPackageAssignment":{
"targetId":"007d1c7e-7fa8-4e33-b678-5e437acdcddc",
"assignmentPolicyId":"db440482-1210-4a60-9b55-3ac7a72f63ba",
"accessPackageId":"88203d16-0e31-41d4-87b2-dd402f1435e9"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#accessPackageAssignmentRequests/
$entity",
"createdDateTime": null,
"completedDate": null,
"id": "a6bb6942-3ae1-4259-9908-0133aaee9377",
"requestType": "UserAdd",
"requestState": "Submitted",
"requestStatus": "Accepted",
"isValidationOnly": false,
"expirationDateTime": null,
"justification": null
}
Sign out of the Requestor1 account and sign back in to the administrator account to see
the status of the request.
Get the status of the request
Use the value of the id property of the request to get the current status of it. In the
response, you can see the status changed to Fulfilled and the state changed to
Delivered.
Request
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackageAssignmentRequests/a6bb6942-3ae1-4259-9908-0133aaee9377
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#accessPackageAssignmentRequests/
$entity",
"createdDateTime": "2020-06-29T20:24:24.683Z",
"completedDate": "2020-06-29T20:24:47.937Z",
"id": "a6bb6942-3ae1-4259-9908-0133aaee9377",
"requestType": "UserAdd",
"requestState": "Delivered",
"requestStatus": "FulfilledNotificationTriggered",
"isValidationOnly": false,
"expirationDateTime": null,
"justification": null
}
Request
HTTP
HTTP
GET
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackageAssignments?$filter=accessPackageAssignmentPolicy/Id eq
'db440482-1210-4a60-9b55-
3ac7a72f63ba'&$expand=target,accessPackageAssignmentResourceRoles
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#accessPackageAssignments",
"value": [
{
"id": "a6bb6942-3ae1-4259-9908-0133aaee9377",
"catalogId": "cec5d6ab-c75d-47c0-9c1c-92e89f66e384",
"accessPackageId": "88203d16-0e31-41d4-87b2-dd402f1435e9",
"assignmentPolicyId": "db440482-1210-4a60-9b55-3ac7a72f63ba",
"targetId": "2bc42425-6dc5-4f2a-9ebb-7a7464481eb0",
"assignmentStatus": "Delivered",
"assignmentState": "Delivered",
"isExtended": false,
"expiredDateTime": null,
"target": {
"id": "8586ddc8-0ff7-4c24-9c79-f192bc3566e3",
"objectId": "2bc42425-6dc5-4f2a-9ebb-7a7464481eb0"
},
"accessPackageAssignmentResourceRoles": [
{
"id": "bdb7e0a0-a927-42ab-bf30-c5b5533dc54a",
"originSystem": "AadGroup",
"status": "Fulfilled"
}
]
}
]
}
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/groups/e93e24d1-2b65-4a6c-a1dd-
654a12225487/members
Response:
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#directoryObjects",
"value": [
{
"@odata.type": "#microsoft.graph.user",
"id": "007d1c7e-7fa8-4e33-b678-5e437acdcddc",
"deletedDateTime": null,
"accountEnabled": true,
"ageGroup": null,
"businessPhones": [],
"city": null,
"createdDateTime": "2020-06-23T18:43:24Z",
"creationType": null,
"companyName": null,
"consentProvidedForMinor": null,
"country": null,
"department": null,
"displayName": "Requestor1",
"employeeId": null,
"faxNumber": null,
"givenName": null,
"imAddresses": [],
"infoCatalogs": [],
"isResourceAccount": null,
"jobTitle": null,
"legalAgeGroupClassification": null,
"mail": null,
"mailNickname": "Requestor1"
}
]
}
Step 5: Clean up resources
In this step, you remove the changes you made and delete the Marketing Campaign
access package.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackageAssignmentRequests
Content-type: application/json
{
"requestType": "AdminRemove",
"accessPackageAssignment":{
"id": "a6bb6942-3ae1-4259-9908-0133aaee9377"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#accessPackageAssignmentRequests/
$entity",
"createdDateTime": null,
"completedDate": null,
"id": "78eaee8c-e6cf-48c9-8f99-aae44c35e379",
"requestType": "AdminRemove",
"requestState": "Submitted",
"requestStatus": "Accepted",
"isValidationOnly": false,
"expirationDateTime": null,
"justification": null
}
Request
HTTP
HTTP
DELETE
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackageAssignmentPolicies/6c1f65ec-8c25-4a45-83c2-a1de2a6d0e9f
Response
HTTP
No Content - 204
Request
HTTP
HTTP
DELETE
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackages/cf54c6ca-d717-49bc-babe-d140d035dfdd
Response
HTTP
No Content - 204
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/users/ce02eca8-752b-4ecf-ac29-
aa9bccd87606
Response
HTTP
No Content - 204
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/groups/a468eaea-ed6c-4290-98d2-
a96bb1cb4209
Response
HTTP
No Content - 204
See also
In this tutorial, you used many APIs to accomplish tasks. Explore the API reference for
these APIs to learn more about what the APIs can do:
Azure Active Directory (Azure AD) access reviews is a feature of Azure AD Identity
Governance that helps to ensure that the right identities (or principals) have the right
access to the right resources in the organization. This review can be implemented
programmatically using the access reviews API in Microsoft Graph.
Resources for which access can be reviewed include groups, privileged roles (including
Azure AD roles and Azure resource roles), access packages, and applications.
The reviewers, or attesters, in the access review may include the following users or
groups of users:
A user (guest user or a member) reviewing their own access and attesting to their
need for continued access.
Another user, for example, an admin in a Security Administrator role, reviewing
access for other principals.
A user's manager attesting to their direct reports' need for continued access.
Members of a group.
Group owners, including owners who might meet specific criteria.
Application owners.
Access reviews also support auditing the decisions that were made on each access
review instance, with the decisions also downloadable for offline auditing.
In a delegated (user) context, an application calls the access reviews API on behalf of a
user. Typical scenarios include:
In an application context, an application calls the access reviews API without a signed-in
user present. A typical scenario is a scheduled background script regularly collecting
decisions for all access reviews.
Next steps
Use the access reviews API
Read more about Azure AD access reviews
Try out the following tutorials to manage access reviews:
Use the access reviews API to review access to your security groups
Use the access reviews API to review guest access to your Microsoft 365 groups
Review access to your security groups
using the access reviews API in
Microsoft Graph
Article • 03/02/2023
The access reviews API in Microsoft Graph enables organizations to audit and attest to
the access that identities (also called principals) are assigned to resources in the
organization. One of the most efficient and effective methods to manage access
privileges for principals to other resources is through Azure AD security groups. For
example, hundreds of users can be assigned to a security group and the security group
assigned access to a folder. Using the access reviews API, organizations can periodically
attest to principals that have access to such groups and by extension, other resources in
the organization.
Suppose you use Azure AD security groups to assign identities (also called principals)
access to resources in your organization. Periodically, you need to attest that all
members of the security group need their membership and by extension, their access to
the resources assigned to the security group.
This tutorial guides you to use the access reviews API to review access to a security
group in your Azure AD tenant. You can use Graph Explorer or Postman to try out and
test your access reviews API calls before you automate them into a script or an app. This
test environment saves you time by helping you properly define and validate your
queries without repeatedly recompiling your application.
Prerequisites
To complete this tutorial, you need the following resources and privileges:
The response objects shown in this tutorial might be shortened for readability.
Review of Privileged Access Groups will only assign active owners as the reviewers.
Eligible owners are not included. At least one fallback reviewer is required for a
Privileged Access Groups review. If there are no active owners when the review
begins, the fallback reviewers will be assigned to the review.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
Content-Type: application/json
{
"accountEnabled": true,
"displayName": "Adele Vance",
"mailNickname": "AdeleV",
"userPrincipalName": "[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn": true,
"password": "xWwvJ]6NMw+bWH-d"
}
}
Response
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"id": "3b8ceebc-49e6-4e0c-9e14-c906374a7ef6",
"displayName": "Adele Vance",
"userPrincipalName": "[email protected]"
}
Request
From the previous step, you created three test users. One of the users will be the group
owner while the other two will be group members.
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/groups
Content-Type: application/json
{
"description": "Building security",
"displayName": "Building security",
"groupTypes": [],
"mailEnabled": false,
"mailNickname": "buildingsecurity",
"securityEnabled": true,
"[email protected]": [
"https://graph.microsoft.com/beta/users/d3bcdff4-4f80-4418-a65e-
7bf3778c5dca"
],
"[email protected]": [
"https://graph.microsoft.com/beta/users/3b8ceebc-49e6-4e0c-9e14-
c906374a7ef6",
"https://graph.microsoft.com/beta/users/bf59c5ba-5304-4c9b-9192-
e5a4cb8444e7"
]
}
Response
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
"id": "eb75ccd2-59ef-48b7-8f76-cc3f33f899f4",
"description": "Building security",
"displayName": "Building security",
"mailNickname": "buildingsecurity",
"securityEnabled": true
}
From the response, record the ID of the new group to use it later in this tutorial.
Request
In this call, replace the following values:
The scope specifies that the review is applied to all members of the Building
security group. For more options for configuring the scope, see the See also
section.
Value of startDate with today's date and value of endDate with a date five days
from the start date.
The access review has the following settings:
It's a self-review as inferred when you don't specify a value for the reviewers
property. Therefore, each group member will self-attest to their need to maintain
access to the group.
The scope of the review is members (direct and indirect) of the Building security
group.
The reviewer must provide justification for why they need to maintain access to the
group.
The default decision is Deny when the reviewers don't respond to the access
review request before the instance expires. The Deny decision removes the group
members from the group.
It's a one-time access review that ends after five days. Therefore, once access is
granted, the user doesn't need to self-attest again within the access review period.
The principals who are defined in the scope of the review will receive email
notifications and reminders prompting them to self-attest to their need to
maintain access.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions
Content-type: application/json
{
"displayName": "One-time self-review for members of Building
security",
"descriptionForAdmins": "One-time self-review for members of
Building security",
"descriptionForReviewers": "One-time self-review for members of
Building security",
"scope": {
"query": "/groups/eb75ccd2-59ef-48b7-8f76-
cc3f33f899f4/transitiveMembers",
"queryType": "MicrosoftGraph"
},
"instanceEnumerationScope": {
"query": "/groups/eb75ccd2-59ef-48b7-8f76-cc3f33f899f4",
"queryType": "MicrosoftGraph"
},
"settings": {
"mailNotificationsEnabled": true,
"reminderNotificationsEnabled": true,
"justificationRequiredOnApproval": true,
"defaultDecisionEnabled": true,
"defaultDecision": "Deny",
"instanceDurationInDays": 5,
"autoApplyDecisionsEnabled": true,
"recommendationsEnabled": true,
"recurrence": {
"pattern": null,
"range": {
"type": "numbered",
"numberOfOccurrences": 0,
"recurrenceTimeZone": null,
"startDate": "2022-02-11",
"endDate": "2022-02-16"
}
}
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/definitions/$entity",
"id": "2d56c364-0695-4ec6-8b92-4c1db7c80f1b",
"displayName": "One-time self-review for members of Building security",
"createdDateTime": null,
"lastModifiedDateTime": null,
"status": "NotStarted",
"descriptionForAdmins": "One-time self-review for members of Building
security",
"descriptionForReviewers": "One-time self-review for members of Building
security",
"createdBy": {
"id": "bf59c5ba-5304-4c9b-9192-e5a4cb8444e7",
"displayName": "MOD Administrator",
"type": null,
"userPrincipalName": "[email protected]"
},
"scope": {},
"instanceEnumerationScope": {},
"reviewers": [],
"fallbackReviewers": [],
"settings": {
"mailNotificationsEnabled": true,
"reminderNotificationsEnabled": true,
"justificationRequiredOnApproval": true,
"defaultDecisionEnabled": true,
"defaultDecision": "Deny",
"instanceDurationInDays": 5,
"autoApplyDecisionsEnabled": true,
"recommendationsEnabled": true,
"recurrence": {
"pattern": null,
"range": {
"type": "numbered",
"numberOfOccurrences": 0,
"recurrenceTimeZone": null,
"startDate": "2022-02-11",
"endDate": "2022-02-16"
}
},
"applyActions": []
},
"additionalNotificationRecipients": []
}
The status of the above access review is marked as NotStarted. You may retrieve the
access review (GET
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/definitions/2d56c
364-0695-4ec6-8b92-4c1db7c80f1b ) to monitor the status and when it's marked as
InProgress, then instances have been created for the access review and decisions can be
posted. You can also retrieve the access review to see the full settings of the access
review.
Request
In this call, replace 2d56c364-0695-4ec6-8b92-4c1db7c80f1b with the ID of your access
review definition returned in Step 3.
HTTP
HTTP
GET
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/2d56c364-0695-4ec6-8b92-4c1db7c80f1b/instances
Response
In this response, the status of the instance is InProgress because startDateTime is past
and endDateTime is in the future. If startDateTime is in the future, the status will be
NotStarted . On the other hand, if endDateTime is in the past, the status will be
Completed .
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/definitions('2d56c364-0695-4ec6-8b92-4c1db7c80f1b')/instances",
"value": [
{
"id": "2d56c364-0695-4ec6-8b92-4c1db7c80f1b",
"startDateTime": "2022-02-11T17:35:25.24Z",
"endDateTime": "2022-02-16T08:00:00Z",
"status": "InProgress",
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/v1.0/groups/eb75ccd2-59ef-48b7-8f76-
cc3f33f899f4/transitiveMembers/microsoft.graph.user",
"queryType": "MicrosoftGraph",
"queryRoot": null
},
"reviewers": [],
"fallbackReviewers": []
}
]
}
HTTP
HTTP
GET
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/2d56c364-0695-4ec6-8b92-4c1db7c80f1b/instances/2d56c364-0695-4ec6-
8b92-4c1db7c80f1b/contactedReviewers
Response
The following response shows that the two members of the Building security group
were notified of their pending review.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/definitions('2d56c364-0695-4ec6-8b92-4c1db7c80f1b')/instances('2d56c364-
0695-4ec6-8b92-4c1db7c80f1b')/contactedReviewers",
"@odata.count": 2,
"value": [
{
"id": "3b8ceebc-49e6-4e0c-9e14-c906374a7ef6",
"displayName": "Adele Vance",
"userPrincipalName": "[email protected]",
"createdDateTime": "2022-02-11T17:35:34.4092545Z"
},
{
"id": "bf59c5ba-5304-4c9b-9192-e5a4cb8444e7",
"displayName": "Alex Wilber",
"userPrincipalName": "[email protected]",
"createdDateTime": "2022-02-11T17:35:34.4092545Z"
}
]
}
Step 6: Get decisions
You're interested in the decisions taken for the instance of the access review.
Request
In this call, replace 2d56c364-0695-4ec6-8b92-4c1db7c80f1b with the ID of your access
review schedule definition and the instance.
HTTP
HTTP
GET
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/2d56c364-0695-4ec6-8b92-4c1db7c80f1b/instances/2d56c364-0695-4ec6-
8b92-4c1db7c80f1b/decisions
Response
The following response shows the decisions taken on the instance of the review.
Because Building security has two members, two decision items are expected.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/definitions('2d56c364-0695-4ec6-8b92-4c1db7c80f1b')/instances('2d56c364-
0695-4ec6-8b92-4c1db7c80f1b')/decisions",
"@odata.count": 2,
"value": [
{
"id": "4db68765-472d-4aa2-847a-433ea94bcfaf",
"accessReviewId": "2d56c364-0695-4ec6-8b92-4c1db7c80f1b",
"reviewedDateTime": null,
"decision": "NotReviewed",
"justification": "",
"appliedDateTime": null,
"applyResult": "New",
"recommendation": "Approve",
"principalLink":
"https://graph.microsoft.com/v1.0/users/bf59c5ba-5304-4c9b-9192-
e5a4cb8444e7",
"resourceLink":
"https://graph.microsoft.com/v1.0/groups/eb75ccd2-59ef-48b7-8f76-
cc3f33f899f4",
"reviewedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"type": null,
"userPrincipalName": ""
},
"appliedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"type": null,
"userPrincipalName": ""
},
"resource": {
"id": "eb75ccd2-59ef-48b7-8f76-cc3f33f899f4",
"displayName": "Building security",
"type": "group"
},
"principal": {
"@odata.type": "#microsoft.graph.userIdentity",
"id": "bf59c5ba-5304-4c9b-9192-e5a4cb8444e7",
"displayName": "Alex Wilber",
"type": "user",
"userPrincipalName": "[email protected]",
"lastUserSignInDateTime": "2/11/2022 5:31:37 PM +00:00"
}
},
{
"id": "c7de8fba-4d6a-4fab-a659-62ff0c02643d",
"accessReviewId": "2d56c364-0695-4ec6-8b92-4c1db7c80f1b",
"reviewedDateTime": null,
"decision": "NotReviewed",
"justification": "",
"appliedDateTime": null,
"applyResult": "New",
"recommendation": "Approve",
"principalLink":
"https://graph.microsoft.com/v1.0/users/3b8ceebc-49e6-4e0c-9e14-
c906374a7ef6",
"resourceLink":
"https://graph.microsoft.com/v1.0/groups/eb75ccd2-59ef-48b7-8f76-
cc3f33f899f4",
"reviewedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"type": null,
"userPrincipalName": ""
},
"appliedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"type": null,
"userPrincipalName": ""
},
"resource": {
"id": "eb75ccd2-59ef-48b7-8f76-cc3f33f899f4",
"displayName": "Building security",
"type": "group"
},
"principal": {
"@odata.type": "#microsoft.graph.userIdentity",
"id": "3b8ceebc-49e6-4e0c-9e14-c906374a7ef6",
"displayName": "Adele Vance",
"type": "user",
"userPrincipalName": "[email protected]",
"lastUserSignInDateTime": "2/11/2022 4:58:13 PM +00:00"
}
}
]
}
From the call, the decision property has the value of NotReviewed because the group
members haven't completed their self-attestation. Follow Step 7 to learn how each
member can self-attest to their need for access review.
7 Note
Complete this step as one of the two members of the Building security group.
In this step, you'll list your pending access reviews then complete the self-attestation
process. You can complete this step in one of two ways, using the API or using the My
Access portal . The other reviewer won't complete this process and instead, you'll let
the default decisions be applied to their access review.
Start a new incognito, anonymous, or InPrivate browsing browser session, and sign in
as one of the two members of the Building security group. By doing so, you won't
interrupt your current administrator session. We'll sign in as Adele Vance. Alternatively,
you can interrupt your current administrator session by logging out of Graph Explorer
and logging back in as one of the two group members.
Method 1: Use the access reviews API to self-review
pending access
Request
HTTP
GET
https://graph.microsoft.com/v1.0/identitygovernance/accessReviews/definition
s/2d56c364-0695-4ec6-8b92-4c1db7c80f1b/instances/2d56c364-0695-4ec6-8b92-
4c1db7c80f1b/decisions/filterByCurrentUser(on='reviewer')
Response
From the response below, you (Adele Vance) have one pending access review (decision
is NotReviewed ) to self-attest to. The principal and resource properties indicate the
principal that the decision applies to and the resource to which access is under review.
In this case, Adele Vance and the Building security group respectively.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(accessReviewInstanceD
ecisionItem)",
"@odata.count": 1,
"value": [
{
"@odata.type":
"#microsoft.graph.accessReviewInstanceDecisionItem",
"id": "c7de8fba-4d6a-4fab-a659-62ff0c02643d",
"accessReviewId": "2d56c364-0695-4ec6-8b92-4c1db7c80f1b",
"reviewedDateTime": null,
"decision": "NotReviewed",
"justification": "",
"appliedDateTime": null,
"applyResult": "New",
"recommendation": "Approve",
"principalLink":
"https://graph.microsoft.com/v1.0/users/3b8ceebc-49e6-4e0c-9e14-
c906374a7ef6",
"resourceLink":
"https://graph.microsoft.com/v1.0/groups/eb75ccd2-59ef-48b7-8f76-
cc3f33f899f4",
"reviewedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"type": null,
"userPrincipalName": ""
},
"appliedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"type": null,
"userPrincipalName": ""
},
"resource": {
"id": "eb75ccd2-59ef-48b7-8f76-cc3f33f899f4",
"displayName": "Building security",
"type": "group"
},
"principal": {
"@odata.type": "#microsoft.graph.userIdentity",
"id": "3b8ceebc-49e6-4e0c-9e14-c906374a7ef6",
"displayName": "Adele Vance",
"type": "user",
"userPrincipalName": "[email protected]",
"lastUserSignInDateTime": "2/15/2022 9:35:23 AM +00:00"
}
}
]
}
Record a decision
To complete the access review, Adele Vance will confirm the need to maintain access to
the Building security group.
Request
HTTP
PATCH
https://graph.microsoft.com/v1.0/identitygovernance/accessReviews/definition
s/2d56c364-0695-4ec6-8b92-4c1db7c80f1b/instances/2d56c364-0695-4ec6-8b92-
4c1db7c80f1b/decisions/c7de8fba-4d6a-4fab-a659-62ff0c02643d
{
"decision": "Approve",
"justification": "As the assistant security manager, I still need access
to the building security group."
}
Response
HTTP
You can now sign out and exit the incognito browser session.
List the pending access reviews. The user can follow one of two ways to get there:
Option 1: Select Review access button from the email notification that they
received in their mail inbox. The email notification is like the following
screenshot. Selecting this button directs them to the pending access review.
Option 2: Go to the My Access portal portal. Select the Access reviews menu
and select the Groups and Apps tab.
From the list of access reviews, select the access review for which you want to post
the decision. Select Yes to post the decision that you still need access to Building
security. Enter a reason, then select Submit.
You can now sign out and exit the incognito browser session.
Step 8: Confirm the decisions and the status of
the access review
Back in the main browser session where you're still logged in as a global administrator,
repeat Step 4 to see that the decision property for Adele Vance is now Approve . When
the access review ends or expires, the default decision of Deny will be recorded for Alex
Wilber. The decisions will then be automatically applied because the
autoApplyDecisionsEnabled was set to true and the period of the access review
instance will have ended. Adele will then maintain access to the Building security group
and Alex will automatically be removed from the group.
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/beta/groups/eb75ccd2-59ef-48b7-8f76-
cc3f33f899f4
Response
HTTP
HTTP/1.1 204 No Content
Request
HTTP
HTTP
DELETE
https://graph.microsoft.com/beta/identityGovernance/accessReviews/defini
tions/2d56c364-0695-4ec6-8b92-4c1db7c80f1b
Response
HTTP
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/beta/users/3b8ceebc-49e6-4e0c-9e14-
c906374a7ef6
Response
HTTP
Conclusion
You've created an access review in which the principals have self-attested to their need
to maintain their access to a resource, in this case, the Building security group.
This tutorial has demonstrated one of the scenarios by the Azure AD access reviews API.
The access reviews API supports different scenarios through a combination of resources,
principals, and reviewers to suit your access attestation needs. For more information, see
the access reviews API.
See also
What are Azure AD access reviews?
Review access for yourself to groups or applications in Azure AD access reviews
Review guest access to your Microsoft
365 groups using the access reviews API
in Microsoft Graph
Article • 03/02/2023
The access reviews API in Microsoft Graph enables organizations to audit and attest to
the access that identities (also called principals) are assigned to resources in the
organization. In cross-tenant collaboration, external users can have access resources
such as files, notes, calendars, and even Teams conversations. This access can be
efficiently managed through Microsoft 365 groups. Using the access reviews API,
organizations can therefore periodically attest to principals that have access to such
groups and by extension, other resources in the organization.
Let's assume that you've granted access to external users (also called guest users) to
resources in your organization through Microsoft 365 groups. This tutorial will guide
you to review their access to the Microsoft 365 groups in your tenant.
7 Note
The response objects shown in this tutorial might be shortened for readability.
Prerequisites
To complete this tutorial, you need the following resources and privileges:
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
Content-Type: application/json
{
"accountEnabled": true,
"displayName": "Aline Dupuy",
"mailNickname": "AlineD",
"userPrincipalName": "[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn": true,
"password": "xWwvJ]6NMw+bWH-d"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"id": "c9a5aff7-9298-4d71-adab-0a222e0a05e4",
"displayName": "Aline Dupuy",
"userPrincipalName": "[email protected]",
"userType": "Member"
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/invitations
Content-Type: application/json
{
"invitedUserDisplayName": "John Doe (Tailspin Toys)",
"invitedUserEmailAddress": "[email protected]",
"sendInvitationMessage": false,
"inviteRedirectUrl": "https://myapps.microsoft.com"
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#invitations/$entity",
"invitedUser": {
"id": "baf1b0a0-1f9a-4a56-9884-6a30824f8d20"
}
}
1. Create a new Microsoft 365 group named Feel good marketing campaign.
2. Assign yourself as the group owner.
3. Add [email protected] as a group member. Their access to the group is the
subject of review by you, the group owner.
Request
In this call, replace:
response in Step 2.
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/groups
Content-Type: application/json
{
"description": "Feelgood Marketing Campaign with external partners
and vendors.",
"displayName": "Feelgood Marketing Campaign",
"groupTypes": [
"Unified"
],
"mailEnabled": true,
"mailNickname": "FeelGoodCampaign",
"securityEnabled": true,
"[email protected]": [
"https://graph.microsoft.com/v1.0/users/cdb555e3-b33e-4fd5-a427-
17fadacbdfa7"
],
"[email protected]": [
"https://graph.microsoft.com/v1.0/users/baf1b0a0-1f9a-4a56-9884-
6a30824f8d20"
]
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
"id": "59ab642a-2776-4e32-9b68-9ff7a47b7f6a",
"displayName": "Feelgood Marketing Campaign",
"groupTypes": [
"Unified"
]
}
Request
In this call, replace the following values:
as a backup reviewer.
Value of startDate with today's date and value of endDate with a date one year
from the start date.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions
Content-type: application/json
{
"displayName": "Group owners review guest across Microsoft 365
groups in the tenant (Quarterly)",
"descriptionForAdmins": "",
"descriptionForReviewers": "",
"scope": {
"query": "./members/microsoft.graph.user/?$count=true&$filter=
(userType eq 'Guest')",
"queryType": "MicrosoftGraph"
},
"instanceEnumerationScope": {
"query": "/groups?$filter=
(groupTypes/any(c:c+eq+'Unified'))&$count=true",
"queryType": "MicrosoftGraph"
},
"reviewers": [
{
"query": "./owners",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
],
"fallbackReviewers": [
{
"query": "/users/c9a5aff7-9298-4d71-adab-0a222e0a05e4",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
],
"settings": {
"mailNotificationsEnabled": true,
"reminderNotificationsEnabled": true,
"justificationRequiredOnApproval": true,
"defaultDecisionEnabled": true,
"defaultDecision": "Approve",
"instanceDurationInDays": 0,
"autoApplyDecisionsEnabled": true,
"recommendationsEnabled": true,
"recurrence": {
"pattern": {
"type": "absoluteMonthly",
"interval": 3,
"month": 0,
"dayOfMonth": 0,
"daysOfWeek": [],
"firstDayOfWeek": "sunday",
"index": "first"
},
"range": {
"type": "numbered",
"numberOfOccurrences": 0,
"recurrenceTimeZone": null,
"startDate": "2021-02-10",
"endDate": "2022-12-21"
}
},
"applyActions": [
{
"@odata.type":
"#microsoft.graph.removeAccessApplyAction"
}
]
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/definitions/$entity",
"id": "c22ae540-b89a-4d24-bac0-4ef35e6591ea",
"displayName": "Group owners review guest across Microsoft 365 groups in
the tenant (Quarterly)",
"status": "NotStarted",
"createdBy": {
"id": "cdb555e3-b33e-4fd5-a427-17fadacbdfa7",
"displayName": "MOD Administrator",
"userPrincipalName": "[email protected]"
},
"scope": {
"query": "./members/microsoft.graph.user/?$count=true&$filter=
(userType eq 'Guest')",
"queryType": "MicrosoftGraph"
},
"instanceEnumerationScope": {
"query": "/groups?$filter=
(groupTypes/any(c:c+eq+'Unified'))&$count=true",
"queryType": "MicrosoftGraph"
},
"reviewers": [
{
"query": "./owners",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
],
"fallbackReviewers": [
{
"query": "/users/c9a5aff7-9298-4d71-adab-0a222e0a05e4",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
],
"settings": {
"defaultDecisionEnabled": true,
"defaultDecision": "Approve",
"autoApplyDecisionsEnabled": true,
"recommendationsEnabled": true,
"recurrence": {
"pattern": {
"type": "absoluteMonthly",
"interval": 3,
"month": 0,
"dayOfMonth": 0,
"daysOfWeek": [],
"firstDayOfWeek": "sunday",
"index": "first"
},
"range": {
"type": "numbered",
"numberOfOccurrences": 0,
"recurrenceTimeZone": null,
"startDate": "2021-02-10",
"endDate": "2022-12-21"
}
},
"applyActions": [
{
"@odata.type": "#microsoft.graph.removeAccessApplyAction"
}
]
}
}
Request
In this call, replace c22ae540-b89a-4d24-bac0-4ef35e6591ea with the ID of your access
review definition returned in Step 4.
HTTP
HTTP
GET
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/c22ae540-b89a-4d24-bac0-4ef35e6591ea/instances
Response
In this response, the scope includes a group identified by 59ab642a-2776-4e32-9b68-
9ff7a47b7f6a (the Feel good marketing campaign group created in Step 3) because it
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/definitions('c22ae540-b89a-4d24-bac0-4ef35e6591ea')/instances",
"value": [
{
"id": "6392b1a7-9c25-4844-83e5-34e23c88e16a",
"startDateTime": "2021-02-10T17:00:36.96Z",
"endDateTime": "2021-02-10T17:00:36.96Z",
"status": "InProgress",
"scope": {
"query": "/groups/59ab642a-2776-4e32-9b68-
9ff7a47b7f6a/members/microsoft.graph.user/?$count=true&$filter=(userType eq
'Guest')",
"queryType": "MicrosoftGraph"
}
}
]
}
In this response, the access review instance is currently InProgress . Because it's a
quarterly review, a new review instance is created automatically every three months and
the reviewers can apply new decisions.
Request
In this call:
Replace c22ae540-b89a-4d24-bac0-4ef35e6591ea with the ID of your access review
definition returned in Step 4.
Replace 6392b1a7-9c25-4844-83e5-34e23c88e16a with the ID of your access review
instance returned in Step 5.
HTTP
HTTP
GET
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/c22ae540-b89a-4d24-bac0-4ef35e6591ea/instances/6392b1a7-9c25-4844-
83e5-34e23c88e16a/decisions
Response
The following response shows the decision taken for the instance of the review.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/definitions('c22ae540-b89a-4d24-bac0-4ef35e6591ea')/instances('6392b1a7-
9c25-4844-83e5-34e23c88e16a')/decisions",
"@odata.count": 1,
"value": [
{
"id": "0e76ee07-b4c6-469e-bc9d-e73fc9a8d660",
"accessReviewId": "6392b1a7-9c25-4844-83e5-34e23c88e16a",
"reviewedDateTime": "2021-02-10T17:06:26.147Z",
"decision": "Approve",
"justification": "",
"appliedDateTime": null,
"applyResult": "New",
"recommendation": "Deny",
"reviewedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "AAD Access Reviews",
"userPrincipalName": "AAD Access Reviews"
},
"appliedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"userPrincipalName": ""
},
"target": {
"@odata.type":
"#microsoft.graph.accessReviewInstanceDecisionItemUserTarget",
"userId": "baf1b0a0-1f9a-4a56-9884-6a30824f8d20",
"userDisplayName": "John Doe (Tailspin Toys)",
"userPrincipalName": "[email protected]"
},
"principal": {
"@odata.type": "#microsoft.graph.userIdentity",
"id": "baf1b0a0-1f9a-4a56-9884-6a30824f8d20",
"displayName": "John Doe (Tailspin Toys)",
"userPrincipalName": "[email protected]"
}
}
]
}
In a quarterly review like this one, and as long as the access review is still active:
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/groups/59ab642a-2776-4e32-9b68-
9ff7a47b7f6a
Response
HTTP
Request
HTTP
HTTP
DELETE
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/c22ae540-b89a-4d24-bac0-4ef35e6591ea
Response
HTTP
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/users/baf1b0a0-1f9a-4a56-9884-
6a30824f8d20
Response
HTTP
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/users/c9a5aff7-9298-4d71-adab-
0a222e0a05e4
Response
HTTP
Congratulations! You've created an access review for guest users in Microsoft 365
groups in your tenant, and scheduled it quarterly. The group owners will review access
during these cycles, choosing either to approve or deny access.
See also
Access reviews API
What are Azure AD access reviews?
Review access to groups and applications in Azure AD access reviews
Review access to privileged roles using
the access reviews API in Microsoft
Graph
Article • 03/02/2023
The access reviews API in Microsoft Graph enables organizations to audit and attest to
the access that identities (also called principals) are assigned to resources in the
organization. One of the most sensitive resources in an organization is privileged roles.
With a privileged role, a principal can perform administrative operations. Depending on
the privileged role, some operations might have a greater effect on the security posture
of the organization. Using the access reviews API, organizations can periodically attest
to principals that have access to privileged roles as per the organization policy.
Contoso Limited is a growing service provider that has delegated various Azure AD
administrator privileges to users, groups, and service principals in the organization. The
company needs to ensure only the right assignees have access to privileged roles. The
system auditors should also audit the access review history to report on the
effectiveness of Contoso's internal controls.
In this tutorial, you'll use the access reviews API to periodically review users and groups
with access to privileged roles in Contoso. This access includes both active and eligible
roles.
Prerequisites
To complete this tutorial, you need the following resources and privileges:
The response objects shown in this tutorial might be shortened for readability.
The following access review schedule definition has the following settings:
The scope of the review is principals (principalScopes property) with access to the
resource specified in the resourceScopes property. In this case, the principals are
both groups and users while the resource is the User Administrator role.
Both active and eligible assignments to the User Administrator role resource are in
review.
An individual user is selected as a reviewer. In this example, you'll be the reviewer.
The approver must provide justification before they approve access to the
privileged role.
The default decision is None when the reviewers don't respond to the access
review request before the instance expires.
autoApplyDecisionsEnabled isn't set and defaults to false . In this case, after the
review completes, the decisions aren't automatically applied so you must manually
apply them.
The review recurs every three months over a period of three days and doesn't end.
Request
In the following request, replace the f674a1c9-4a40-439c-bfa3-4b61a9f29d85 with the
value of your user ID. The roleDefinitionId fe930be7-5e62-47db-91af-98c3a49a38b1 is the
global template identifier for the User Administrator role in Azure AD.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions
Content-type: application/json
{
"displayName": "Review access of users and groups to privileged
roles",
"descriptionForAdmins": "Review access of users and groups to
privileged roles",
"scope": {
"@odata.type":
"#microsoft.graph.principalResourceMembershipsScope",
"principalScopes": [
{
"@odata.type":
"#microsoft.graph.accessReviewQueryScope",
"query": "/users",
"queryType": "MicrosoftGraph"
},
{
"@odata.type":
"#microsoft.graph.accessReviewQueryScope",
"query": "/groups",
"queryType": "MicrosoftGraph"
}
],
"resourceScopes": [
{
"@odata.type":
"#microsoft.graph.accessReviewQueryScope",
"query":
"/roleManagement/directory/roleDefinitions/fe930be7-5e62-47db-91af-
98c3a49a38b1",
"queryType": "MicrosoftGraph"
}
]
},
"reviewers": [
{
"query": "/users/f674a1c9-4a40-439c-bfa3-4b61a9f29d85",
"queryType": "MicrosoftGraph"
}
],
"settings": {
"mailNotificationsEnabled": true,
"reminderNotificationsEnabled": true,
"justificationRequiredOnApproval": true,
"defaultDecisionEnabled": false,
"defaultDecision": "None",
"instanceDurationInDays": 3,
"recommendationsEnabled": false,
"recurrence": {
"pattern": {
"type": "absoluteMonthly",
"interval": 3
},
"range": {
"type": "noEnd",
"startDate": "2022-03-02"
}
}
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/definitions/$entity",
"id": "57457d7c-af59-470c-ae71-aa72c657fe0f",
"displayName": "Review access of users and groups to privileged roles",
"createdDateTime": null,
"lastModifiedDateTime": null,
"status": "NotStarted",
"descriptionForAdmins": "Review access of users and groups to privileged
roles",
"descriptionForReviewers": null,
"instanceEnumerationScope": null,
"createdBy": {
"id": "f674a1c9-4a40-439c-bfa3-4b61a9f29d85",
"displayName": "Alex Wilber",
"type": null,
"userPrincipalName": "[email protected]"
},
"scope": {
"@odata.type": "#microsoft.graph.principalResourceMembershipsScope",
"principalScopes": [
{
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/users",
"queryType": "MicrosoftGraph",
"queryRoot": null
},
{
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/groups",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
],
"resourceScopes": [
{
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query":
"/roleManagement/directory/roleDefinitions/roleManagement/directory/roleDefi
nitions/fe930be7-5e62-47db-91af-98c3a49a38b1",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
]
},
"reviewers": [
{
"query": "/users/f674a1c9-4a40-439c-bfa3-4b61a9f29d85",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
],
"fallbackReviewers": [],
"settings": {
"mailNotificationsEnabled": true,
"reminderNotificationsEnabled": true,
"justificationRequiredOnApproval": true,
"defaultDecisionEnabled": false,
"defaultDecision": "None",
"instanceDurationInDays": 3,
"autoApplyDecisionsEnabled": false,
"recommendationsEnabled": false,
"recurrence": {
"pattern": {
"type": "absoluteMonthly",
"interval": 3,
"month": 0,
"dayOfMonth": 0,
"daysOfWeek": [],
"firstDayOfWeek": "sunday",
"index": "first"
},
"range": {
"type": "noEnd",
"numberOfOccurrences": 0,
"recurrenceTimeZone": null,
"startDate": "2022-03-02",
"endDate": null
}
},
"applyActions": []
},
"additionalNotificationRecipients": []
}
Step 2: Retrieve instances of the access review
Each access review instance represents each recurrence with each unique resource that is
under review. In Step 1, only the User Administrator role resource was defined in the
scope. Because you defined a recurring access review, the ID of the instance is different
from the ID of the schedule definition in Step 1.
Request
In the following request, replace 57457d7c-af59-470c-ae71-aa72c657fe0f with the value
of the access review that you created in Step 1.
HTTP
HTTP
GET
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/57457d7c-af59-470c-ae71-aa72c657fe0f/instances
Response
In this response, the instance object shows the end date as three days after the start
date; this period was defined in Step 1 in the instanceDurationInDays property of the
accessReviewScheduleDefinition object. Only one instance is returned representing the
first recurrence of only one resource under review.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/definitions('57457d7c-af59-470c-ae71-aa72c657fe0f')/instances",
"@odata.count": 1,
"value": [
{
"id": "ad0dd148-5d16-4cfd-86e9-ab502f819aaf",
"startDateTime": "2022-03-02T15:31:14.607Z",
"endDateTime": "2022-03-05T15:31:14.607Z",
"status": "InProgress",
"scope": {
"@odata.type":
"#microsoft.graph.principalResourceMembershipsScope",
"principalScopes": [
{
"@odata.type":
"#microsoft.graph.accessReviewQueryScope",
"query": "/v1.0/users",
"queryType": "MicrosoftGraph",
"queryRoot": null
},
{
"@odata.type":
"#microsoft.graph.accessReviewQueryScope",
"query": "/v1.0/groups",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
],
"resourceScopes": [
{
"@odata.type":
"#microsoft.graph.accessReviewQueryScope",
"query":
"/beta/roleManagement/directory/roleDefinitions/fe930be7-5e62-47db-91af-
98c3a49a38b1",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
]
},
"reviewers": [
{
"query": "/v1.0/users/f674a1c9-4a40-439c-bfa3-
4b61a9f29d85",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
],
"fallbackReviewers": []
}
]
}
The status of this access review instance is InProgress . An InProgress status means that
the review instance is open for reviewers to submit decisions, and the period for this
access review instance hasn't expired. You've also received an email notification from
Microsoft Azure requesting you to perform the access review.
Request
In the following request, replace the following values:
created in Step 1.
ad0dd148-5d16-4cfd-86e9-ab502f819aaf with the value of the access review instance
HTTP
HTTP
GET
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/57457d7c-af59-470c-ae71-aa72c657fe0f/instances/ad0dd148-5d16-4cfd-
86e9-ab502f819aaf/decisions
Response
The following response shows two decision items each corresponding to a decision per
a principal's access to the resource.
The principal property shows that two principals have access to the User
Administrator role—a group named IT Helpdesk (User) and a user named Aline
Dupuy.
The NotReviewed value of the decision property indicates that the reviewers
haven't reviewed and posted their decisions.
No recommendations are available because recommendations weren't enabled in
the accessReviewScheduleDefinition in Step 1.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/definitions('57457d7c-af59-470c-ae71-aa72c657fe0f')/instances('ad0dd148-
5d16-4cfd-86e9-ab502f819aaf')/decisions",
"@odata.count": 2,
"value": [
{
"id": "4d79fbf6-36e6-430b-ba0a-2a727a480303",
"accessReviewId": "ad0dd148-5d16-4cfd-86e9-ab502f819aaf",
"reviewedDateTime": null,
"decision": "NotReviewed",
"justification": "",
"appliedDateTime": null,
"applyResult": "New",
"recommendation": "NoInfoAvailable",
"principalLink":
"https://graph.microsoft.com/v1.0/users/339143ab-541e-484f-b017-
e1707e962d34",
"resourceLink":
"https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions/f
e930be7-5e62-47db-91af-98c3a49a38b1",
"reviewedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"type": null,
"userPrincipalName": ""
},
"appliedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"type": null,
"userPrincipalName": ""
},
"resource": {
"id": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"displayName": "User Administrator",
"type": "directoryRole"
},
"principal": {
"@odata.type": "#microsoft.graph.userIdentity",
"id": "339143ab-541e-484f-b017-e1707e962d34",
"displayName": "Aline Dupuy",
"type": "user",
"userPrincipalName": "[email protected]",
"lastUserSignInDateTime": ""
}
},
{
"id": "62fd1c5b-04b8-4703-9fd7-dce6232c3775",
"accessReviewId": "ad0dd148-5d16-4cfd-86e9-ab502f819aaf",
"reviewedDateTime": null,
"decision": "NotReviewed",
"justification": "",
"appliedDateTime": null,
"applyResult": "New",
"recommendation": "NoInfoAvailable",
"principalLink":
"https://graph.microsoft.com/v1.0/groups/b5260fca-6d64-4d5a-92df-
0c482d40bc4d",
"resourceLink":
"https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions/f
e930be7-5e62-47db-91af-98c3a49a38b1",
"reviewedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"type": null,
"userPrincipalName": ""
},
"appliedBy": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "",
"type": null,
"userPrincipalName": ""
},
"resource": {
"id": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"displayName": "User Administrator",
"type": "directoryRole"
},
"principal": {
"id": "b5260fca-6d64-4d5a-92df-0c482d40bc4d",
"displayName": "IT Helpdesk (User)",
"type": "group"
}
}
]
}
As the reviewer, you can now submit your decisions for the access review instance.
The company policy requires that access to privileged roles be granted to only groups
and not individual users. In compliance with the company policy, you'll deny Aline
Dupuy access while approving access for the group.
Request
In the following request, you approve access for the IT Helpdesk group.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/57457d7c-af59-470c-ae71-aa72c657fe0f/instances/ad0dd148-5d16-4cfd-
86e9-ab502f819aaf/decisions/62fd1c5b-04b8-4703-9fd7-dce6232c3775
Content-type: application/json
{
"decision": "Approve",
"justification": "The IT Helpdesk requires continued access to the
User Administrator role to manage user account support requests,
lifecycle, and access to resources"
}
Response
Request
In the following request, you deny access for Aline Dupuy.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/57457d7c-af59-470c-ae71-aa72c657fe0f/instances/ad0dd148-5d16-4cfd-
86e9-ab502f819aaf/decisions/4d79fbf6-36e6-430b-ba0a-2a727a480303
Content-type: application/json
{
"decision": "Deny",
"justification": "Aline Dupuy should join an allowed group to
maintain access to the User Administrator role. For more details, refer
to the company policy '#132487: Privileged roles'"
}
Response
When you retrieve the access review decisions (repeat Step 3), they have the following
settings:
The access review decision for the IT Helpdesk group is Approve while for Aline is
Deny .
While you've recorded all the pending decisions for this instance, the decisions haven't
been applied to the resource and principal objects. For example, Aline still has access to
the privileged role. You can verify this assignment by running the following query
https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments?
$filter=roleDefinitionId eq 'fe930be7-5e62-47db-91af-98c3a49a38b1' . This behavior is
because the autoApplyDecisionsEnabled was set to false , you haven't stopped the
review, and the instance period hasn't ended.
In this tutorial, you won't stop the instance manually, but you'll let it end automatically
and then apply the decisions.
Tip
1. Until the status of the access review instance is marked as Completed , you can
still change the decisions. Rerun step 4 to apply different decisions for the
principals.
2. You can also manually stop the access review instance so that you can
expedite your progress to Step 5.
Step 5: Apply access review decisions
As an admin, after the status of the access review instance is set to Completed , you can
apply the decisions.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/57457d7c-af59-470c-ae71-aa72c657fe0f/instances/ad0dd148-5d16-4cfd-
86e9-ab502f819aaf/applyDecisions
Response
Aline has now lost access to the User Administrator role while the IT Helpdesk group has
maintained its access. You can verify this state of role assignment by running the
following query GET
https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments?
$filter=roleDefinitionId eq 'fe930be7-5e62-47db-91af-98c3a49a38b1' .
Access reviews will apply the decisions automatically when the instance expires, or you
can apply the decisions manually by running the following query: POST
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/definitions/57457
d7c-af59-470c-ae71-aa72c657fe0f/instances/ad0dd148-5d16-4cfd-86e9-
ab502f819aaf/applydecisions .
After the decisions have been applied, the status of the access review instance will be
Applied . Also, because we created a recurring access review in Step 1, a new instance
will be started. Its start date will be three months from when the current review period is
marked as having ended.
Step 6: Retrieve access review history
definitions
Contoso's auditors also want to review the access review history for the last quarter. In
this example, you'll generate an access review history report for all
accessReviewScheduleDefinition objects scoped to directory role assignments
(roleAssignmentScheduleInstances). In this query, the decisions property is empty and
therefore defaults to include all decisions in the history report.
First, you'll define the scope of the history report. Then, you generate a download URI
that the auditors will use to download the report. The download URI is active for only 24
hours. So, after expiry, you can regenerate another download URI from the previously
defined history report.
Request
HTTP
POST
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/historyDef
initions
{
"displayName": "Last quarter's access reviews for privileged roles -
User Administrator",
"decisions": [],
"reviewHistoryPeriodStartDateTime": "2022-03-01T00:00:00Z",
"reviewHistoryPeriodEndDateTime": "9999-12-31T00:00:00Z",
"scopes": [
{
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"queryType": "MicrosoftGraph",
"query": "/identityGovernance/accessReviews/definitions?
$filter=contains(scope/query, 'roleAssignmentScheduleInstances')"
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/historyDefinitions/$entity",
"id": "17ecffa9-e60d-4b6d-9313-78b50860bbcd",
"displayName": "Last quarter's access reviews for privileged roles -
User Administrator",
"reviewHistoryPeriodStartDateTime": "2022-03-01T00:00:00Z",
"reviewHistoryPeriodEndDateTime": "9999-12-31T00:00:00Z",
"decisions": [
"approve",
"deny",
"dontKnow",
"notReviewed",
"notNotified"
],
"status": "requested",
"createdDateTime": "2022-09-29T12:22:57.9953455Z",
"createdBy": {
"id": "10a08e2e-3ea2-4ce0-80cb-d5fdd4b05ea6",
"displayName": "MOD Administrator",
"type": null,
"userPrincipalName": "[email protected]"
},
"scopes": [
{
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/identityGovernance/accessReviews/definitions?
$filter=contains(scope/query, 'roleAssignmentScheduleInstances')",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
]
}
Request
HTTP
POST
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/historyDef
initions/983db508-b77b-427d-ab90-a4041efa658d/instances
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#identityGovernance/accessReviews
/historyDefinitions('17ecffa9-e60d-4b6d-9313-78b50860bbcd')/instances",
"value": [
{
"id": "17ecffa9-e60d-4b6d-9313-78b50860bbcd",
"reviewHistoryPeriodStartDateTime": "2022-03-01T00:00:00Z",
"reviewHistoryPeriodEndDateTime": "9999-12-31T00:00:00Z",
"status": "inprogress",
"runDateTime": "2022-09-29T12:22:57.9953455Z",
"fulfilledDateTime": null,
"downloadUri": null
}
]
}
Request
HTTP
POST
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/historyDef
initions/57457d7c-af59-470c-ae71-aa72c657fe0f/instances/983db508-b77b-427d-
ab90-a4041efa658d/generateDownloadUri()
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#accessReviewHistoryInstance",
"@odata.type": "#microsoft.graph.accessReviewHistoryInstance",
"id": "17ecffa9-e60d-4b6d-9313-78b50860bbcd",
"reviewHistoryPeriodStartDateTime": "2022-03-01T00:00:00Z",
"reviewHistoryPeriodEndDateTime": "9999-12-31T00:00:00Z",
"status": "done",
"runDateTime": "2022-09-29T12:22:57.9953455Z",
"fulfilledDateTime": "2022-09-29T12:24:08.1146032Z",
"downloadUri": "https://ermconsolreportweu.blob.core.windows.net/erm-
reports/Last quarter's access reviews for privileged roles - User
Administrator-17ecffa9-e60d-4b6d-9313-78b50860bbcd.csv?skoid=4ad0868b-7b78-
4869-abb7-8f29151d8428&sktid=33e01921-4d64-4f8c-a055-5bdaffd5e33d&skt=2022-
09-29T12:24:56Z&ske=2022-09-29T12:26:56Z&sks=b&skv=2020-04-08&sv=2020-04-
08&st=2022-09-29T12:24:56Z&se=2022-09-
30T12:24:56Z&sr=b&sp=r&sig=ivZ9B%2BQragSwvOd8J2g8ny9n4sqdzww9uVkl96uo1k4%3D"
}
The downloadUri property contains a link to download the history report in an Excel file
format. This link is active for only 24 hours.
Request
HTTP
HTTP
DELETE
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/57457d7c-af59-470c-ae71-aa72c657fe0f
Response
HTTP
Conclusion
You've learned how to review access to privileged roles in Azure AD and generate an
auditable access review history report for compliance reporting. Your organization can
use the access reviews API to continually govern privileged access to its resources
including both Azure AD roles and Azure resource roles. In addition to users and groups,
you can also review access by applications and service principals to privileged roles.
See also
Access reviews API Reference
Configure the scope of your access review definition using the Microsoft Graph API
Learn about privileged access management
Configure the scope of your access
review using the Microsoft Graph API
Article • 03/22/2023
The Azure AD access reviews API allows you to programmatically review the access that
users, service principals, or groups have to your Azure AD resources. The API can help
you to automate proactive review and keep control over access to resources in your
organization.
In this article, you'll learn how to scope your access review using these three derived
resource types.
HTTP
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/groups/{groupId}/transitiveMembers",
"queryType": "MicrosoftGraph"
}
Example scenario: Suppose group A has three direct members - users AU1 and AU2 and
group G1. Group G1 on the other hand has two members - users GU1 and GU2. Users
GU1 and GU2 are therefore transitive members of the nested group G1. Four objects will
be included in the review: users AU1, AU2, GU1, and GU2.
HTTP
"scope": {
"@odata.type": "#microsoft.graph.accessReviewInactiveUsersQueryScope",
"inactiveDuration": "P30D",
"query": "/groups/{groupId}/transitiveMembers",
"queryType": "MicrosoftGraph"
}
This example also scopes the review to both direct and transitive members of the group
who are inactive users.
HTTP
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/groups/{groupId}/transitiveMembers/?$filter=(userType eq
'Guest')",
"queryType": "MicrosoftGraph"
}
HTTP
"scope": {
"query": "/groups/{groupId}/members",
"queryType": "MicrosoftGraph"
}
Example scenario: Suppose group A has three direct members - users AU1 and AU2 and
group G1. Group G1 on the other hand has two members - users GU1 and GU2. Users
GU1 and GU2 are therefore transitive members of the nested group G1. Only three
objects are targeted in the above review, users AU1 and AU2, and group G1.
HTTP
"instanceEnumerationScope": {
"query": "/groups?$filter=(groupTypes/any(c:c eq 'Unified'))",
"queryType": "MicrosoftGraph"
},
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "./members/microsoft.graph.user",
"queryType": "MicrosoftGraph"
}
Additionally, because this review is applied on all Microsoft 365 groups, configure the
instanceEnumerationScope to specify the Microsoft 365 groups to review. Dynamic
groups and role-assignable groups aren't included in this review.
HTTP
"instanceEnumerationScope": {
"query": "/groups?$filter=(groupTypes/any(c:c eq 'Unified'))",
"queryType": "MicrosoftGraph"
},
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "./members/microsoft.graph.user/?$filter=(userType eq
'Guest')",
"queryType": "MicrosoftGraph"
}
Additionally, because this review is applied on all Microsoft 365 groups, configure the
instanceEnumerationScope to specify the Microsoft 365 groups to review. Dynamic
groups and role-assignable groups aren't included in this review.
Review all inactive guest users assigned to all Microsoft 365 groups
The following example scopes the review to direct members of all Microsoft 365 who
are inactive guest users.
HTTP
"instanceEnumerationScope": {
"query": "/groups?$filter=(groupTypes/any(c:c eq 'Unified'))",
"queryType": "MicrosoftGraph"
},
"scope": {
"@odata.type": "#microsoft.graph.accessReviewInactiveUsersQueryScope",
"query": "./members/microsoft.graph.user/?$filter=(userType eq
'Guest')",
"queryType": "MicrosoftGraph",
"inactiveDuration": "P30D"
}
HTTP
"instanceEnumerationScope": {
"query": "/groups?$filter=(groupTypes/any(c:c eq 'Unified') and
resourceProvisioningOptions/Any(x:x eq 'Team')')",
"queryType": "MicrosoftGraph"
},
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "./members/microsoft.graph.user/?$filter=(userType eq
'Guest')",
"queryType": "MicrosoftGraph"
}
Additionally, because this review is applied on all Teams-enabled Microsoft 365 groups,
configure the instanceEnumerationScope to specify the Teams-enabled Microsoft 365
groups to review. Dynamic groups and role-assignable groups aren't included in this
review.
This review won't include B2B direct connect users in teams with shared channels. To
include B2B direct connect users in teams with shared channels, see Example 11: Review
all users assigned to a team, including B2B direct connect users in a team with shared
channels.
The following example scopes the review to direct members of all teams who are
inactive guest users.
HTTP
"instanceEnumerationScope": {
"query": "/groups?$filter=(groupTypes/any(c:c eq 'Unified') and
resourceProvisioningOptions/Any(x:x eq 'Team')')",
"queryType": "MicrosoftGraph"
},
"scope": {
"@odata.type": "#microsoft.graph.accessReviewInactiveUsersQueryScope",
"query": "./members/microsoft.graph.user/?$filter=(userType eq
'Guest')",
"queryType": "MicrosoftGraph",
"inactiveDuration": "P30D"
}
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query":
"/identityGovernance/entitlementManagement/accessPackageAssignments?$filter=
(accessPackageId eq '{package id}' and assignmentPolicyId eq '{id}' and
catalogId eq 'id')",
"queryType": "MicrosoftGraph"
}
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/roleManagement/directory/roleAssignmentScheduleInstances?
$expand=principal&$filter=
(isof(principal,'microsoft.graph.servicePrincipal') and roleDefinitionId eq
'{role ID}')",
"queryType": "MicrosoftGraph"
}
Review all users assigned to a privileged role (all active and eligible
assignments included)
HTTP
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/roleManagement/directory/roleDefinitions/{role ID}",
"queryType": "MicrosoftGraph"
}
HTTP
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/roleManagement/directory/roleEligibilityScheduleInstances?
$expand=principal&$filter=(isof(principal,'microsoft.graph.user') and
roleDefinitionId eq '{role ID}')",
"queryType": "MicrosoftGraph"
}
HTTP
"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/roleManagement/directory/roleAssignmentScheduleInstances?
$expand=principal&$filter=(assignmentType eq 'Assigned' and
isof(principal,'microsoft.graph.user') and roleDefinitionId eq '{role
ID}')",
"queryType": "MicrosoftGraph"
}
Use principalResourceMembershipsScope to
configure scope
The principalResourceMembershipsScope exposes the principalScopes and
resourceScopes properties to support more tailored configuration options for the scope
of the accessReviewScheduleDefinition object. The capabilities include reviewing access
for multiple principals or groups of principals to multiple resources.
"scope": {
"@odata.type": "#microsoft.graph.principalResourceMembershipsScope",
"principalScopes": [
{
"@odata.type":
"#microsoft.graph.accessReviewInactiveUsersQueryScope",
"query": "/users?$filter=(userType eq 'Guest')",
"queryType": "MicrosoftGraph",
"inactiveDuration": "P30D"
}
],
"resourceScopes": [
{
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/groups",
"queryType": "MicrosoftGraph"
}
]
}
HTTP
"scope": {
"@odata.type": "#microsoft.graph.principalResourceMembershipsScope",
"principalScopes": [
{
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/users",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
],
"resourceScopes": [
{
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/groups/{groupId}/transitiveMembers",
"queryType": "MicrosoftGraph",
"queryRoot": null
},
{
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/teams/{groupId}/channels?$filter=(membershipType eq
'shared')",
"queryType": "MicrosoftGraph",
"queryRoot": null
}
]
}
To review B2B direct connect users and teams within shared channels, you must specify
the /teams/{groupId}/channels?$filter=(membershipType eq 'shared') query pattern in
the resourceScopes object. An all teams review, such as Example 6, won't include B2B
direct connect users and teams within shared channels.
7 Note
Access review of B2B direct connect users and teams is only supported in single-
stage access reviews and not in multi-stage access reviews.
"scope": {
"@odata.type": "#microsoft.graph.principalResourceMembershipsScope",
"principalScopes": [
{
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/users?$filter=(userType eq 'Guest')",
"queryType": "MicrosoftGraph"
}
],
"resourceScopes": [
{
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/roleManagement/directory/roleDefinitions/{role id}",
"queryType": "MicrosoftGraph"
}
]
}
Next steps
Assign reviewers to your access review definition
Try out tutorials to learn how to use the access reviews API to review access to
Azure AD resources
Create an access review
Assign reviewers to your access review
using the Microsoft Graph API
Article • 02/10/2023
The Azure AD access reviews API allows you to programmatically review the access that
users, service principals, or groups have to your Azure AD resources.
The primary reviewers are configured in the reviewers property of the access reviews
accessReviewScheduleDefinition resource. In addition, you can specify fallback reviewers
by using the fallbackReviewers property. These properties are not required when you
create a self-review (where users review their own access).
To configure the reviewers and fallback reviewers, set the values of query, queryRoot,
and queryType properties of accessReviewReviewerScope. For descriptions of these
properties, see the accessReviewReviewerScope resource type.
7 Note
Review of groups whose membership is governed through PIM for groups will only
assign active owners as the reviewers. Eligible owners are not included. At least one
fallback reviewer is required to review these groups. If there are no active owners
when the review begins, the fallback reviewers will be assigned to the review.
Example 1: A self-review
HTTP
"reviewers": []
If the corresponding access review scope targets B2B direct connect users and teams
with shared channels, the team owner will be assigned to review access for the B2B
direct connect users.
"reviewers": [
{
"query": "/groups/{groupId}/transitiveMembers",
"queryType": "MicrosoftGraph"
}
]
HTTP
"reviewers": [
{
"query": "/groups/{groupId}/owners",
"queryType": "MicrosoftGraph"
}
]
When the access review is scoped to a group and to assign only the group owners from
a specific country as reviewers:
HTTP
"reviewers": [
{
"query": "/groups/{groupId}/owners?
$filter=microsoft.graph.user/userType eq 'Member' and
microsoft.graph.user/country eq 'USA'",
"type": "MicrosoftGraph”
}
]
When the access review is scoped to all groups, for example, Example 4: Review all users
assigned to all Microsoft 365 groups, Example 5: Review all guest users assigned to all
Microsoft 365 groups, and Example 6: Review all guest users assigned to all teams.
HTTP
"reviewers": [
{
"query": "./owners",
"queryType": "MicrosoftGraph"
}
]
"reviewers": [
{
"query": "./manager",
"queryType": "MicrosoftGraph",
"queryRoot": "decisions"
}
]
Because ./manager is a relative query, specify the queryRoot property with the value
decisions .
If the corresponding access review scope targets B2B direct connect users and teams
with shared channels, the team owner will be assigned to review access for the B2B
direct connect users.
"reviewers": [
{
"query": "/servicePrincipals/{servicePrincipalId}/owners",
"queryType": "MicrosoftGraph"
}
]
Next steps
Configure the scope of your access review definition
Try out tutorials to learn how to use the access reviews API to review access to
Azure AD resources
Create an access review
Overview of rules for Azure AD roles in
privileged identity management (PIM)
APIs in Microsoft Graph
Article • 03/14/2023
In Privileged Identity Management, each Azure AD role has settings that can fall in one
of three categories: Activation settings, assignment settings, and notification settings.
Such settings include whether multifactor authentication (MFA) is required to activate an
eligible role, or whether you can create permanent assignments to the role.
When using the privileged identity management APIs in Microsoft Graph, these Azure
AD settings are managed through policies and rules.
To group the rules into activation, assignment, and notification rules, Microsoft Graph
defines the unifiedRoleManagementPolicyRule resource type abstract type. This abstract
type is inherited by five resources. Each of these five derived types then defines rule
configurations that can be one or more of 17 rules. The 17 rules are identified by unique
and immutable rule IDs.
This article provides a mapping of the Azure portal Azure AD role settings to the
corresponding rules in Microsoft Graph.
Number Azure portal Microsoft Graph Rule ID / Derived resource type Enforced
UX for caller
Description
Require ticket
information
on activation
Require
justification on
activation
Assignment rules
The following image shows the assignment role settings on the Azure portal, mapped to
rules and resource types in the PIM API in Microsoft Graph.
Number Azure portal UX Microsoft Graph Rule ID / Derived Enforced
Description resource type for caller
Require justification on
active assignment
Require justification on
active assignment
Notification rules
The following image shows the notification role settings on the Azure portal, mapped to
rules and resource types in the PIM API in Microsoft Graph.
The following article provides examples for using Microsoft Graph APIs to update
different rules that are assigned to Azure AD roles through Privileged Identity
Management (PIM). To understand the structure of role settings in PIM, see Overview of
rules for Azure AD roles in privileged identity management (PIM) APIs in Microsoft
Graph.
When updating the rules, you must include the @odata.type for the derived type in the
request body. For example, to update an activation rule of ID
Enablement_EndUser_Assignment , you must include "@odata.type":
"#microsoft.graph.unifiedRoleManagementPolicyEnablementRule" .
Prerequisites
Have an understanding of privileged identity management APIs for managing
Azure AD roles.
Sign in to an API client such as Graph Explorer , Postman, or create your own
client app to call Microsoft Graph. To call Microsoft Graph APIs in this tutorial, you
need to use an account with the Global Administrator or Privileged Role
Administrator roles.
Grant yourself the RoleManagementPolicy.ReadWrite.Directory delegated
permission.
HTTP
PATCH
https://graph.microsoft.com/v1.0/policies/roleManagementPolicies/Directo
ryRole_38d49456-54d4-455d-a8d6-c383c71e0a6d_59d351b1-e819-4262-b298-
236f5f9b1a67/rules/Expiration_EndUser_Assignment
Content-Type: application/json
{
"@odata.type":
"#microsoft.graph.unifiedRoleManagementPolicyExpirationRule",
"id": "Expiration_EndUser_Assignment",
"isExpirationRequired": true,
"maximumDuration": "PT1H45M",
"target": {
"@odata.type":
"microsoft.graph.unifiedRoleManagementPolicyRuleTarget",
"caller": "EndUser",
"operations": [
"All"
],
"level": "Assignment",
"inheritableSettings": [],
"enforcedSettings": []
}
}
HTTP
PATCH
https://graph.microsoft.com/v1.0/policies/roleManagementPolicies/Directo
ryRole_38d49456-54d4-455d-a8d6-c383c71e0a6d_59d351b1-e819-4262-b298-
236f5f9b1a67/rules/Enablement_EndUser_Assignment
Content-Type: application/json
{
"@odata.type":
"#microsoft.graph.unifiedRoleManagementPolicyEnablementRule",
"id": "Enablement_EndUser_Assignment",
"enabledRules": [
"Justification",
"MultiFactorAuthentication",
"Ticketing"
],
"target": {
"@odata.type":
"microsoft.graph.unifiedRoleManagementPolicyRuleTarget",
"caller": "EndUser",
"operations": [
"All"
],
"level": "Assignment",
"inheritableSettings": [],
"enforcedSettings": []
}
}
HTTP
PATCH
https://graph.microsoft.com/v1.0/policies/roleManagementPolicies/Directo
ryRole_38d49456-54d4-455d-a8d6-c383c71e0a6d_59d351b1-e819-4262-b298-
236f5f9b1a67/rules/Approval_EndUser_Assignment
Content-Type: application/json
{
"@odata.type":
"#microsoft.graph.unifiedRoleManagementPolicyApprovalRule",
"id": "Approval_EndUser_Assignment",
"target": {
"@odata.type":
"microsoft.graph.unifiedRoleManagementPolicyRuleTarget",
"caller": "EndUser",
"operations": [
"All"
],
"level": "Assignment",
"inheritableSettings": [],
"enforcedSettings": []
},
"setting": {
"@odata.type": "microsoft.graph.approvalSettings",
"isApprovalRequired": true,
"isApprovalRequiredForExtension": false,
"isRequestorJustificationRequired": true,
"approvalMode": "SingleStage",
"approvalStages": [
{
"@odata.type": "microsoft.graph.unifiedApprovalStage",
"approvalStageTimeOutInDays": 1,
"isApproverJustificationRequired": true,
"escalationTimeInMinutes": 0,
"primaryApprovers": [
{
"@odata.type": "#microsoft.graph.singleUser",
"userId": "10a08e2e-3ea2-4ce0-80cb-d5fdd4b05ea6"
},
{
"@odata.type": "#microsoft.graph.groupMembers",
"groupId": "14f2746d-7d6f-4ac6-acd8-
8cac318b041b"
}
],
"isEscalationEnabled": false,
"escalationApprovers": []
}
]
}
}
HTTP
PATCH
https://graph.microsoft.com/v1.0/policies/roleManagementPolicies/Directo
ryRole_38d49456-54d4-455d-a8d6-c383c71e0a6d_59d351b1-e819-4262-b298-
236f5f9b1a67/rules/Expiration_Admin_Eligibility
Content-Type: application/json
{
"@odata.type":
"#microsoft.graph.unifiedRoleManagementPolicyExpirationRule",
"id": "Expiration_Admin_Eligibility",
"isExpirationRequired": true,
"maximumDuration": "P90D",
"target": {
"@odata.type":
"microsoft.graph.unifiedRoleManagementPolicyRuleTarget",
"caller": "Admin",
"operations": [
"All"
],
"level": "Eligibility",
"inheritableSettings": [],
"enforcedSettings": []
}
}
HTTP
PATCH
https://graph.microsoft.com/v1.0/policies/roleManagementPolicies/Directo
ryRole_38d49456-54d4-455d-a8d6-c383c71e0a6d_59d351b1-e819-4262-b298-
236f5f9b1a67/rules/Expiration_Admin_Assignment
Content-Type: application/json
{
"@odata.type":
"#microsoft.graph.unifiedRoleManagementPolicyExpirationRule",
"id": "Expiration_Admin_Assignment",
"isExpirationRequired": true,
"maximumDuration": "P90D",
"target": {
"@odata.type":
"microsoft.graph.unifiedRoleManagementPolicyRuleTarget",
"caller": "Admin",
"operations": [
"All"
],
"level": "Assignment",
"inheritableSettings": [],
"enforcedSettings": []
}
}
Example 6: Set the justification and MFA
requirements for active assignment
Category of rule: Assignment rule
Microsoft Graph rule type: unifiedRoleManagementPolicyExpirationRule
Microsoft Graph rule ID: Enablement_Admin_Assignment
HTTP
PATCH
https://graph.microsoft.com/v1.0/policies/roleManagementPolicies/Directo
ryRole_38d49456-54d4-455d-a8d6-c383c71e0a6d_59d351b1-e819-4262-b298-
236f5f9b1a67/rules/Enablement_Admin_Assignment
Content-Type: application/json
{
"@odata.type":
"#microsoft.graph.unifiedRoleManagementPolicyEnablementRule",
"id": "Enablement_Admin_Assignment",
"enabledRules": [
"Justification",
"MultiFactorAuthentication"
],
"target": {
"@odata.type":
"microsoft.graph.unifiedRoleManagementPolicyRuleTarget",
"caller": "Admin",
"operations": [
"All"
],
"level": "Assignment",
"inheritableSettings": [],
"enforcedSettings": []
}
}
See also
Overview of role management through the privileged identity management (PIM)
API
Overview of rules for Azure AD roles in privileged identity management (PIM) APIs
in Microsoft Graph
Configure Azure AD role settings in Privileged Identity Management - Azure portal
Assign Azure AD roles through
Privileged Identity Management (PIM)
APIs in Microsoft Graph
Article • 03/02/2023
In this tutorial, a fictitious company called Contoso Limited wishes to have its IT
Helpdesk manage the lifecycle of employees’ access. The company has identified the
Azure AD User Administrator role as the appropriate privileged role required by IT
Helpdesk, and will use the PIM API to assign the role.
You'll create a role-assignable security group for IT Helpdesk and using the PIM API,
assign the security group eligibility to the User Administrator role. By assigning the
eligible role to a security group, Contoso has a more efficient way to manage
administrator access to resources such as Azure AD roles. For example:
7 Note
The response objects shown in this tutorial might be shortened for readability.
Prerequisites
To complete this tutorial, you need the following resources and privileges:
A working Azure AD tenant with an Azure AD Premium P2 or EMS E5 license
enabled.
Sign in to an API client such as Graph Explorer , Postman, or create your own
client app to call Microsoft Graph. To call Microsoft Graph APIs in this tutorial, you
need to use an account with the Global Administrator role.
[Optional] Start a new session in another browser. You'll sign in later in this
tutorial.
Grant yourself the following delegated permissions: User.ReadWrite.All ,
Group.ReadWrite.All , Directory.Read.All ,
RoleEligibilitySchedule.ReadWrite.Directory , and
RoleAssignmentSchedule.ReadWrite.Directory , and
RoleManagement.ReadWrite.Directory .
Authenticator app installed on your phone to register a user for multifactor
authentication (MFA).
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
Content-Type: application/json
{
"accountEnabled": true,
"displayName": "Aline Dupuy",
"mailNickname": "AlineD",
"userPrincipalName": "[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn": true,
"password": "xWwvJ]6NMw+bWH-d"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"@odata.id": "https://graph.microsoft.com/v2/29a4f813-9274-4e1b-858d-
0afa98ae66d4/directoryObjects/7146daa8-1b4b-4a66-b2f7-
cf593d03c8d2/Microsoft.DirectoryServices.User",
"id": "7146daa8-1b4b-4a66-b2f7-cf593d03c8d2",
"displayName": "Aline Dupuy",
"userPrincipalName": "[email protected]"
}
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/groups
Content-type: application/json
{
"description": "IT Helpdesk to support Contoso employees",
"displayName": "IT Helpdesk (User)",
"mailEnabled": false,
"mailNickname": "userHelpdesk",
"securityEnabled": true,
"isAssignableToRole": true,
"[email protected]": [
"https://graph.microsoft.com/v1.0/users/1ed8ac56-4827-4733-8f80-
86adc2e67db5"
],
"[email protected]": [
"https://graph.microsoft.com/v1.0/users/1ed8ac56-4827-4733-8f80-
86adc2e67db5",
"https://graph.microsoft.com/v1.0/users/7146daa8-1b4b-4a66-b2f7-
cf593d03c8d2"
]
}
Response
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
"@odata.id": "https://graph.microsoft.com/v2/29a4f813-9274-4e1b-858d-
0afa98ae66d4/directoryObjects/e77cbb23-0ff2-4e18-819c-
690f58269752/Microsoft.DirectoryServices.Group",
"id": "e77cbb23-0ff2-4e18-819c-690f58269752",
"description": "IT Helpdesk to support Contoso employees",
"displayName": "IT Helpdesk (User)",
"groupTypes": [],
"isAssignableToRole": true,
"mailEnabled": false,
"mailNickname": "userHelpdesk",
"securityEnabled": true,
"securityIdentifier": "S-1-12-1-3883711267-1310199794-258579585-
1385637464",
"visibility": "Private",
"onPremisesProvisioningErrors": []
}
Step 3: Create a
unifiedRoleEligibilityScheduleRequest
Now that you have a security group, assign it as eligible for the User Administrator role.
In this step:
Request
Replace e77cbb23-0ff2-4e18-819c-690f58269752 with the value of the id of the IT
Helpdesk (User) security group. This principalId identifies the assignee of eligibility to
the User Administrator role. The roleDefinitionId fe930be7-5e62-47db-91af-98c3a49a38b1
is the global template identifier for the User Administrator role in Azure AD.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/roleManagement/directory/roleEligibilit
yScheduleRequests
Content-type: application/json
{
"action": "AdminAssign",
"justification": "Assign User Admin eligibility to IT Helpdesk
(User) group",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/",
"principalId": "e77cbb23-0ff2-4e18-819c-690f58269752",
"scheduleInfo": {
"startDateTime": "2021-07-01T00:00:00Z",
"expiration": {
"endDateTime": "2022-06-30T00:00:00Z",
"type": "AfterDateTime"
}
}
}
Response
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#roleManagement/directory/roleEli
gibilityScheduleRequests/$entity",
"id": "64a8bd54-4591-4f6a-9c77-3e9cb1fdd29b",
"status": "Provisioned",
"createdDateTime": "2021-09-03T20:45:28.3848182Z",
"completedDateTime": "2021-09-03T20:45:39.1194292Z",
"action": "AdminAssign",
"principalId": "e77cbb23-0ff2-4e18-819c-690f58269752",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/",
"isValidationOnly": false,
"targetScheduleId": "64a8bd54-4591-4f6a-9c77-3e9cb1fdd29b",
"justification": "Assign User Admin eligibility to IT Helpdesk (User)
group",
"createdBy": {
"user": {
"id": "1ed8ac56-4827-4733-8f80-86adc2e67db5"
}
},
"scheduleInfo": {
"startDateTime": "2021-09-03T20:45:39.1194292Z",
"expiration": {
"type": "afterDateTime",
"endDateTime": "2022-06-30T00:00:00Z"
}
},
"ticketInfo": {}
}
Request
In the following request, replace 7146daa8-1b4b-4a66-b2f7-cf593d03c8d2 with the value
of Aline's id.
HTTP
HTTP
GET
https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignment
s?$filter=principalId eq '7146daa8-1b4b-4a66-b2f7-cf593d03c8d2'
Response
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#roleManagement/directory/roleAss
ignments",
"value": []
}
The empty response object shows that Aline has no existing Azure AD roles in Contoso.
Aline will now activate their eligible User Administrator role for a limited time.
First, start the Authenticator app on your phone and open Aline Dupuy's account.
Sign in to Graph Explorer as Aline. You may use the another browser for this step. By
doing so, you won't interrupt your current session as a user in the Global Administrator
role. Alternatively, you can interrupt your current session by signing out of Graph
Explorer and signing back in as Aline.
Signed in as Aline, you'll first change your password because this was specified during
account creation. Then, because the administrator configured your account for MFA,
you'll be prompted to set up your account in the Authenticator app and be challenged
for MFA sign-in. This is because PIM requires that MFA for all active role assignments.
After signing in, activate your User Administrator role for five hours.
Request
To activate a role, call the roleAssignmentScheduleRequests endpoint. In this request, the
UserActivate action allows you to activate your eligible assignment, in this case for five
hours.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignment
ScheduleRequests
Content-type: application/json
{
"action": "SelfActivate",
"principalId": "7146daa8-1b4b-4a66-b2f7-cf593d03c8d2",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/",
"justification": "Need to invalidate all app refresh tokens for
Contoso users.",
"scheduleInfo": {
"startDateTime": "2021-09-04T15:13:00.000Z",
"expiration": {
"type": "AfterDuration",
"duration": "PT5H"
}
},
"ticketInfo": {
"ticketNumber": "CONTOSO:Security-012345",
"ticketSystem": "Contoso ICM"
}
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#roleManagement/directory/roleAss
ignmentScheduleRequests/$entity",
"id": "295edd40-4646-40ca-89b8-ab0b46b6f60e",
"status": "Granted",
"createdDateTime": "2021-09-03T21:10:49.6670479Z",
"completedDateTime": "2021-09-04T15:13:00Z",
"action": "SelfActivate",
"principalId": "7146daa8-1b4b-4a66-b2f7-cf593d03c8d2",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/",
"isValidationOnly": false,
"targetScheduleId": "295edd40-4646-40ca-89b8-ab0b46b6f60e",
"justification": "Need to invalidate all app refresh tokens for Contoso
users.",
"createdBy": {
"user": {
"id": "7146daa8-1b4b-4a66-b2f7-cf593d03c8d2"
}
},
"scheduleInfo": {
"startDateTime": "2021-09-04T15:13:00Z",
"expiration": {
"type": "afterDuration",
"endDateTime": null,
"duration": "PT5H"
}
},
"ticketInfo": {
"ticketNumber": "CONTOSO:Security-012345",
"ticketSystem": "Contoso ICM"
}
}
Back in the global administrator session, you have received notifications of both the
eligible assignment and the role activation. This allows the global administrator to be
aware of all elevations to administrator privileges across your organization.
Request
Replace e77cbb23-0ff2-4e18-819c-690f58269752 with the id of IT Support (Users) group.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/roleManagement/directory/roleEligibilit
yScheduleRequests
Content-type: application/json
{
"action": "AdminRemove",
"principalId": "e77cbb23-0ff2-4e18-819c-690f58269752",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/"
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#roleManagement/directory/roleEli
gibilityScheduleRequests/$entity",
"id": "dcd11a1c-300f-4d17-8c7a-523830400ec8",
"status": "Revoked",
"action": "AdminRemove",
"principalId": "e77cbb23-0ff2-4e18-819c-690f58269752",
"roleDefinitionId": "fe930be7-5e62-47db-91af-98c3a49a38b1",
"directoryScopeId": "/"
}
Delete the IT Support (Users) group
Request
Replace e77cbb23-0ff2-4e18-819c-690f58269752 with the id of IT Support (Users) group.
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/groups/e77cbb23-0ff2-4e18-819c-
690f58269752
Response
HTTP
Request
Replace 7146daa8-1b4b-4a66-b2f7-cf593d03c8d2 with the value of Aline's id.
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/users/7146daa8-1b4b-4a66-b2f7-
cf593d03c8d2
Response
HTTP
Microsoft School Data Sync , combined with the industry data API, addresses this
challenge for application developers and schools. The following are some of the
scenarios that the industry data API enables:
School Data Sync helps automate the process of importing and synchronizing student
identity and roster data from an SIS. A system integrator who configures the integration
of a SIS of a school with School Data Sync can use the industry data API to set up
synchronization from either a CSV file or a supported SIS API connector.
API reference
Looking for the API reference for this service?
Next steps
To learn more about the industry data APIs as tailored to the education sector, see
Use the industry data API as an extract, transform, and load (ETL) engine.
Learn more about education scenarios in Microsoft Graph.
Set up an education demo developer tenant, School Data Sync, and Microsoft
Teams.
Try the industry data APIs in Graph Explorer.
Outlook mail API overview
Article • 10/06/2022
Outlook is a messaging communication hub in Microsoft 365. It also lets you manage
contacts, schedule meetings, find information about users in an organization, initiate
online conversations, share files, and collaborate in groups.
https://www.youtube-nocookie.com/embed/L-gm25wusIQ
Using Microsoft Graph, you can integrate with Outlook by writing an app just once and
reach more than hundreds of millions of consumers, and tens of millions of organization
customers who choose Outlook as their email client. You can write apps that focus on
mail scenarios, or connect to a wealth of other Outlook and non-Outlook relationships,
resources, and intelligence, and realize scenarios supported by the Microsoft cloud.
Customers organize their messages in different ways - some leave all messages in
the Inbox and simply search for them, others file their messages in folders. They
like Outlook's flexible and intuitive approach that supports both flat and folder-
based organizations. Apps can conveniently filter, search, or sort messages in
specific folders or the user's entire mailbox.
Additionally, app users can change the importance of a message (or event or task),
or flag a message for follow-up. (Flagging is currently in preview in Microsoft
Graph.)
The rules API takes message organization to the next level. Apps can set up Inbox
rules to promptly handle incoming messages and reduce email clutter. For
example, an app can automatically move messages to another folder if their
subject lines contain certain keywords, and assign categories and importance to
make them easier for later follow-up.
Many customers use email clients that send and receive messages in MIME format.
Even though Outlook does not save messages in MIME format, apps can get the
body of an Outlook message in MIME format, send Outlook messages in MIME
format, attach S/MIME digital signatures, and encrypt message content in S/MIME.
Integrate with Focused Inbox and @-mentions (preview) and let your app users
read and respond to what's relevant to them first.
Check mail tips while still composing a message to get useful status information
about a recipient (such as the recipient sending an auto-reply or has a full
mailbox). Mail tips can alert apps of certain conditions so to take more efficient
follow-up actions instead.
Make use of the people API to provide interactive controls such as a people picker
in your app. The people API can suggest persons most relevant to a user, based on
the user’s communication and collaboration patterns and business relationships.
Offer app users a smart file picker and suggest files that they have recently
interacted with, to add as attachments when composing a message. Insights use
advanced analytics to suggest files that are trending around a user, recently viewed
or edited by the user, or shared with the user.
If you need to add and subsequently update custom data, you can store the data in
individual resource instances. If appropriate, as an alternative, you can extend the
schema, add custom properties, and store typed data in Microsoft Graph resources. You
can make such schema extensions discoverable and shareable.
The API does not support accessing in-place archive mailboxes, not on Exchange Online
nor on Exchange Server.
API reference
Looking for the API reference for this service?
Next steps
Select and try Outlook mail sample queries in Graph Explorer. Choose Show more
samples in the column on the left. Use the menu to turn on Outlook Mail.
Learn about:
Creating and sending messages
Ways to organize messages
Getting the MIME content of a message
Attaching large files to Outlook messages or events
Getting shared messages
How to send mail from another user
Getting immutable identifiers for Outlook resources
Sending emails with MIME contents
Find out more about using the mail API and its use cases in Microsoft Graph v1.0.
Automate creating, sending, and
processing messages
Article • 07/09/2022
Similarly, when responding to an email, you can create and send the response in the
same action (reply, reply-all, or forward). Or, you can create a draft for the response
(reply, reply-all, or forward), add content, and then send the draft at a later time.
To distinguish between a draft and a sent message programmatically, check the isDraft
property.
By default, draft messages are saved in the Drafts folder, sent messages are saved in
the Sent Items folder. For convenience, you can identify the Drafts folder and SentItems
folder by their corresponding well-known folder names.
The from property can be changed if the Exchange administrator has assigned
sendAs rights of the mailbox to some other users. The administrator can do this by
selecting Mailbox Permissions of the mailbox owner in the Azure portal, or by
using the Exchange Admin Center or a Windows PowerShell Add-ADPermission
cmdlet. Then, you can programmatically set the from property to one of these
users who have sendAs rights for that mailbox.
The sender property can be changed if the mailbox owner has delegated one or
more users to be able to send messages from that mailbox. The mailbox owner can
delegate in Outlook. When a delegate sends a message on behalf of the mailbox
owner, Outlook sets the sender property to the delegate’s account, and the from
property remains as the mailbox owner. Programmatically, you can set the sender
property to a user who has got delegate permissions for that mailbox.
HTTP
GET /me/messages/AAMkADhMGAAA=
Or, you can get the messages in a specific folder. For example, to read messages in the
signed-in user's Drafts folder:
HTTP
GET /me/mailfolders('Drafts')
The body of an Outlook message can be either HTML or text, with HTML as the default
message body type returned in a GET response.
When getting a message, you can specify the following request header to return the
body and uniqueBody properties in text format:
HTTP
Prefer: outlook.body-content-type="text"
You can specify the following header, or, just skip the header, to get the message body
in HTML format:
HTTP
Prefer: outlook.body-content-type="html"
When you specify either header, a successful response would include the corresponding
Preference-Applied header:
If the body is HTML, by default, Outlook removes any potentially unsafe HTML (for
example, JavaScript) embedded in the body property before returning the body content
in a REST response.
To get the entire, original HTML content, include the following HTTP request header:
HTTP
Prefer: outlook.allow-unsafe-html
Next steps
Why integrate with Outlook mail
Get MIME content (preview)
Get shared messages
Send Outlook messages from another user
Get immutable identifiers for Outlook resources
Using the mail API and its use cases in Microsoft Graph v1.0.
Organize Outlook messages
Article • 06/22/2022
Outlook lets customers organize their messages the way they like it, be it leaving all
messages in the same Inbox folder, or organizing messages in a tree-like folder
structure under the Inbox to fit their specific needs. You can conveniently filter, search,
or sort messages in the user's entire mailbox or in specific folders.
Each mailFolder is identified by its folder ID, and has a writable displayName property.
Outlook creates a few other folders for customers by default. You can reference these
default folders by their folder IDs, or by their well-known names. For a list of available
well-known folder names, see mailFolder resource type.
For a custom, non-default folder, if you know its folder path, you can access the folder
by first using the /users/{id}/mailfolders shortcut to get to the root level and get all
the top level folders:
HTTP
GET https://graph.microsoft.com/v1.0/users/{id}/mailFolders
Then, specify the appropriate folder ID ( {folder_id} ) as you navigate each level of the
folder tree:
HTTP
GET
https://graph.microsoft.com/v1.0/users/{id}/mailFolders/{folder_id}/childfol
ders
Repeat until you finally get to the custom folder in the tree.
At the contents level, totalItemCount and unreadItemCount respectively tell you the
number of items and number of unread items in a mail folder. At the child folders level,
you can list the child folders under the Inbox or any other folder. The childFolderCount
property represents the number of immediate child folders.
Be aware that Outlook mail folders can contain messages and non-message items such
as events and contacts. In general, Outlook folders can contain heterogeneous items.
Notifications are delivered via webhooks asynchronously when the changes happen,
saving apps the overhead to poll frequently. You can subscribe to change notifications
about additions, updates, or deletions to a user's mail data. For example, you can create
a subscription to messages in a specific folder (i.e., /me/mailFolders('{folderId'}') ), or
at the root level (i.e., /me/messages ). The subscription specifies a notificationUrl where
Microsoft Graph notifies the app when the requested types of changes happen.
To initially synchronize a user's mailbox, first do delta query for mail folders starting at
the root level to synchronize all mail folders, followed by delta query for messages in
each folder to synchronize individual messages.
To find the exact entities that have been changed without reading the entire resource
with every notification, you can use delta query to track those changes that matter to
you, and synchronize your local store with those changes. You can track changes to
messages in a specific folder. You can also track changes to mail folders at the root level
(i.e., /me/mailfolders ).
Next steps
Why integrate with Outlook mail
Use the mail API and its use cases in Microsoft Graph v1.0
Get MIME content of a message
Article • 07/09/2022
MIME is an industry email standard. Many email applications create messages in MIME
format and save them in files with the .EML extension.
Even though Outlook does not save messages in MIME format, there are two ways you
can get an Outlook message body in MIME format:
In either case, your app must have the appropriate permissions to access the Outlook
item or group post in order to apply the get-message or get-attachment operation.
You can then save the message body content in a .EML file and attach the file to records
in business systems, such as those for CRM, ERP, and bug tracking.
What is MIME?
MIME is a standard used by internet email to transmit the following types of content via
SMTP:
The following are typical MIME headers in a message. For more information, see RFC
2045 .
Content-Type - Indicates the media type of the message or a part of the message,
represented by a type and subtype. It also includes a boundary field which specifies
a string as the MIME boundary or as the encapsulation boundary, depending on
the location of Content-Type .
Content-Disposition - Provides details of an attachment such as its presentation
style ( inline or attachment ), filenames, and creation and last modification dates.
Content-Transfer-Encoding - Specifies the encoding method to represent binary
data.
HTTP
GET /users/{id}/messages/{id}/$value
Example
The following is an example that requests a message in the signed-in user's mailbox to
be returned with its MIME content.
HTTP
GET
https://graph.microsoft.com/v1.0/me/messages/4aade2547798441eab5188a7a2436bc
1/$value
The following is the response. The MIME content begins with the MIME-Version header.
HTTP
```http
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="_004_4aade2547798441eab5188a7a2436bc1contoso_"
--_004_4aade2547798441eab5188a7a2436bc1contoso_
Content-Type: multipart/alternative;
boundary="_000_4aade2547798441eab5188a7a2436bc1contoso_"
--_000_4aade2547798441eab5188a7a2436bc1contoso_
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
--_000_4aade2547798441eab5188a7a2436bc1contoso_
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Diso-8859-=
1">
<style type=3D"text/css" style=3D"display:none;"><!-- P {margin-top:0;margi=
n-bottom:0;} --></style>
</head>
<body dir=3D"ltr">
<div id=3D"divtagdefaultwrapper" style=3D"font-size:12pt;color:#000000;font=
-family:Calibri,Helvetica,sans-serif;" dir=3D"ltr">
<p>The attachment is an email.</p>
</div>
</body>
</html>
--_000_4aade2547798441eab5188a7a2436bc1contoso_--
--_004_4aade2547798441eab5188a7a2436bc1contoso_
Content-Type: application/octet-stream; name="Attachment email.eml"
Content-Description: Attachment email.eml
Content-Disposition: attachment; filename="Attachment email.eml"; size=408;
creation-date="Mon, 04 Sep 2017 09:59:43 GMT";
modification-date="Mon, 04 Sep 2017 09:59:43 GMT"
Content-Transfer-Encoding: base64
RnJvbToJQWRtaW5pc3RyYXRvciA8YWRtaW5AdGVuYW50LUVYSEItMTQ3MS5jb20+DQpTZW50OglN
b25kYXksIFNlcHRlbWJlciA0LCAyMDE3IDM6MjYgUE0NClRvOglTcml2YXJkaGFuIEhlYmJhcg0K
U3ViamVjdDoJQXR0YWNobWVudCBlbWFpbA0KDQpJIHdpbGwgYXR0YWNoIHRoaXMgZW1haWwgdG8g
YW5vdGhlciBtYWlsLg0K
--_004_4aade2547798441eab5188a7a2436bc1contoso_--
To do that, identify the message attachment, and append the $value segment when
getting that attachment. The following shows a few common ways to access an
attachment. See get attachment for more information.
HTTP
GET /users/{id}/events/{id}/attachments/{id}/$value
HTTP
GET /users/{id}/messages/{id}/attachments/{id}/$value
If the message is attached to an Outlook task in the user's default task folder:
HTTP
GET /users/{id}/outlook/tasks/{id}/attachments/{id}/$value
If the message is attached to the specified group post:
HTTP
GET /groups/{id}/threads/{id}/posts/{id}/attachments/{id}/$value
Example
The following is an example that gets a message that has been attached to another
message, and returns the body in MIME format.
HTTP
GET https://graph.microsoft.com/v1.0/me/messages/AAMkAGUAAA7XW-
lAAA=/attachments/AAMkAGUAAA7XW-lAAABEgAQAFBZJBq4EN5FlCSvNV-M-FI=/$value
The following is the response. The MIME content begins with the MIME-Version header.
HTTP
<MWHPR22MB100769D1513B3DC0F007B2ECD4220@MWHPR22MB1007.namprd22.prod.outlook.
com>
Accept-Language: en-US
Content-Language: en-US
X-MS-Exchange-Organization-AuthAs: Internal
X-MS-Exchange-Organization-AuthMechanism: 04
X-MS-Exchange-Organization-AuthSource:
MWHPR22MB1007.namprd22.prod.outlook.com
X-MS-Has-Attach:
X-MS-Exchange-Organization-Network-Message-Id:
88bed46b-a860-40fb-591e-08d6c75b76c1
X-MS-Exchange-Organization-SCL: -1
X-MS-TNEF-Correlator:
X-MS-Exchange-Organization-RecordReviewCfmType: 0
x-ms-publictraffictype: Email
authentication-results: contoso.OnMicrosoft.com; dkim=none (message not
signed) header.d=none;contoso.OnMicrosoft.com; dmarc=none action=none
header.from=contoso.OnMicrosoft.com;
x-originating-ip: [2001:4898:80e8:9:9607:7cf8:4576:961c]
x-ms-office365-filtering-correlation-id: 88bed46b-a860-40fb-591e-
08d6c75b76c1
x-microsoft-antispam:
BCL:0;PCL:0;RULEID:(2390118)(7020095)(4652040)(7021145)(8989299)
(4534185)(7022145)(4603075)(4627221)(201702281549075)(8990200)(5600141)
(711020)(4605104)(2017052603328)(7177060)(7171020)(7173020)
(7193020);SRVR:MWHPR22MB0302;
x-ms-traffictypediagnostic: MWHPR22MB0302:
X-Microsoft-Antispam-Mailbox-Delivery:
ucf:0;jmr:0;ex:0;auth:0;dest:I;ENG:(750119)(520011016)(706158)
(944506303)(944626516);
X-Microsoft-Antispam-Message-Info:
twccJ5SmB7ZvueSjaTBdmtD3489zlRiHPqiO3DBEil1jBx5xhl/5G/fK2GLgdH0klkE2uoUAAvdv
pmxiJezwxCtmn11Nq3kvaOuypDL2TDVdYvWkTfSt4SYfVTp34iBoDlvOEbTh8LTl5J/dz98cgvoR
diE7TUJBXTGvUyVTQX1LG7Xg1hNXMu6XLng6Axdn/ka2NUhmzOa3hEl9yoUI8g3G66Vq3zzVRQFp
S+P5+/d1LcbKHsuYMgZNBzBeM6dLnMnwOH9rKXqjV+d72YDnQw4SkbULkoEsQs2Vq0e4URDtkzQw
HqcoPv1W2HE4pypmiqkl4M6lJtBccF3MWPP/xNxl6NL5gLSpZCILbg8gQ1UxxX8Kdhd4KWbDa3ay
HLHBr11hMNFbGftcUZbZ6jrAtiIGYtGzaAxHqlYC3lUHXZIMdygT76enIJJwklQ1VIp4
Content-Type: multipart/alternative;
boundary="_000_MWHPR22MB100769D1513B3DC0F007B2ECD4220MWHPR22MB1007namp_"
MIME-Version: 1.0
--_000_MWHPR22MB100769D1513B3DC0F007B2ECD4220MWHPR22MB1007namp_
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
The press conference will be on May 15. We arranged to have the press gathe=
r at 2pm outside the main entrance.
--_000_MWHPR22MB100769D1513B3DC0F007B2ECD4220MWHPR22MB1007namp_
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Diso-8859-=
1">
<style type=3D"text/css" style=3D"display:none;"><!-- P {margin-top:0;margi=
n-bottom:0;} --></style>
</head>
<body dir=3D"ltr">
<div id=3D"divtagdefaultwrapper" style=3D"font-size:12pt;color:#000000;font=
-family:Calibri,Helvetica,sans-serif;" dir=3D"ltr">
<p style=3D"margin-top:0;margin-bottom:0">The press conference will be on M=
ay 15. We arranged to have the press gather at 2pm outside the main entranc=
e.</p>
</div>
</body>
</html>
--_000_MWHPR22MB100769D1513B3DC0F007B2ECD4220MWHPR22MB1007namp_--
Next steps
Find out more about:
Get the MIME content of an item attachment to an event, message, Outlook task,
or group post
Why integrate with Outlook mail
Use the mail API and its use cases in Microsoft Graph v1.0
Send messages with MIME content
Article • 11/11/2022
Many email clients can send messages through Exchange in a MIME message format
and communicate across multiple email platforms.
The Outlook mail API supports the following actions on messages with MIME content:
Send messages.
Send reply or reply-all messages.
Forward messages.
Create draft messages.
Attach S/MIME signatures to a messages.
Encrypt message content using S/MIME.
) Important
S/MIME provides two key features: digital signatures to verify sender and
email contents, and message encryption to prevent third parties from viewing
email contents.
Add S/MIME digital signatures and encrypted content to emails only in their
MIME message format.
For more information on MIME format, see getting MIME content of a message.
Use cases
Use cases API method
When specifying the body in MIME format, provide the applicable Internet message
headers and the MIME content , and encode them in base64 format in the request
body. Microsoft Graph does not support editing or updating MIME properties
individually.
Example
The following is an example of MIME content with Internet message headers (before
encoding):
HTTP
D6MmQr/iMMh8YKca2AzC01HqbkKpy3zv5phXo3gGGNXPCyg2KU3OYDhr7eL30FBv0urF1J4B7mf9
5gtd+vKIdqsYNpvdfV4eJ292mys5pOSmk78/yGSxrHlbOU4gfJ0uGktj1eRoS7rRTDY8J1J2Zch4
t/vnfdXgwbrP/lRbTijN1pE93hAPVVMWLyrTk1PczF8McAB/+BkHfFkjEVFjmjeMhZezxyi/Ho5I
lfjSrcOasYXgTVkxd6+dUWTXgCueiBIK0tH+FMG+QrIAgSZA7a8F6Os7q1E3yV57sDpbdLDEiynd
Y9R4ryXRtFjjtqlkDOo0Ss4DGADRYQcs1jmqYrhUwfJuVH97idgW5iVk+MJhpc3Y66MLIkpnjR1j
h0XgDOGBLyyocIhhs8PMLpewKxzKzAty85YKUfoqWdr2bLbYWgYdT86F+EWjmbR2mi/tfk6wzQdO
CFyDGM2vUVM8EAs+Z34Q5bXAOhlSDgjirgrwgkmUSFR8xvaEws5bbYHzKRiDXw8BD8N9gaLFD8vy
lIVxCqvmYg9P0+Tol3PzZN/FLOIUNPJrmR67r2qT4QIcGNh2O06dskhCvwWL/imEaqaKbdmBiyjt
+jQQ2QvksNSDO8Q97YS5ylTjt2cQyA99
Content-Type: multipart/mixed;
boundary="_004_MN2PR13MB3152FA5D970E0F158DF41456D5579MN2PR13MB3152namp_"
MIME-Version: 1.0
--_000_MN2PR13MB3152B5FCA9912BEA2E490189D5589MN2PR13MB3152namp_
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Hello Alex,
Kind regards,
Adele
--_000_MN2PR13MB3152B5FCA9912BEA2E490189D5589MN2PR13MB3152namp_
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Diso-8859-=
1">
<style type=3D"text/css" style=3D"display:none;"> P {margin-top:0;margin-bo=
ttom:0;} </style>
</head>
<body dir=3D"ltr">
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
Hello Alex, </div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
We are testing the Graph MIME feature. </div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
Kind regards,</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div style=3D"font-family: Calibri, Arial, Helvetica, sans-serif; font-size=
: 12pt; color: rgb(0, 0, 0);">
Adele</div>
</body>
</html>
--_000_MN2PR13MB3152B5FCA9912BEA2E490189D5589MN2PR13MB3152namp_--
HTTP
UmVjZWl2ZWQ6IGZyb20gY29udG9zby5jb20gKDEwLjE5NC4yNDEuMTk3KSBieSAKY29udG9zby5j
b20gKDEwLjE5NC4yNDEuMTk3KSB3aXRoIHdpdGggSFRUUFM7IFRodSwgNiBNYXkgMjAyMQogMjI6
NDc6MTggKzAwMDAKUmVjZWl2ZWQ6IGZyb20gY29udG9zby5jb20gKDEwLjE5NC4yNDEuMTk3KQog
YnkgY29udG9zby5jb20gKDEwLjE5NC4yNDEuMTk3KSB3aXRoCiBTTVRQIFNlcnZlciAodmVyc2lv
bj1UTFMxXzIsIApjaXBoZXI9VExTX0VDREhFX1JTQV9XSVRIX0FFU18yNTZfQ0JDX1NIQTM4NF9Q
MjU2KSBpZCAxNS4xLjEzNzQuMCB2aWEgTWFpbGJveDsgVGh1LCA2IE1heQogMjAyMSAyMjo0Nzox
NSArMDAwMApSZWNlaXZlZDogZnJvbSBjb250b3NvLmNvbSAKKGZlODA6OjViZjo1MDU5OjRjYTA6
NTAxNykgYnkgY29udG9zby5jb20gCihmZTgwOjo1YmY6NTA1OTo0Y2EwOjUwMTclMTIpIHdpdGgg
bWFwaSBpZCAxNS4wMS4xMzc0LjAwMDsgVGh1LCA2IE1heSAyMDIxCiAyMjo0NzoxNCArMDAwMApG
cm9tOiBBZGVsZSBWYW5jZSA8QWRlbGVWQGNvbnRvc28uY29tPgpUbzogQWxleCBXaWxiZXIgPEFs
ZXhXQGNvbnRvc28uY29tPgpDQzogQ2hyaXN0aWUgQ2xpbmUgPENocmlzdGllQ0Bjb250b3NvLmNv
bT4KU3ViamVjdDogVGhpcyBpcyBhIHRlc3QgaW4gR3JhcGggLSBNSU1FClRocmVhZC1Ub3BpYzog
VGhpcyBpcyBhIHRlc3QgaW4gR3JhcGggLSBNSU1FClRocmVhZC1JbmRleDogQVFIVEpXU0hTeXdN
elN6OG8wT0p1ZDQ4bkc1MEdRPT0KRGF0ZTogVGh1LCA2IE1heSAyMDIxIDIyOjQ3OjE0ICswMDAw
Ck1lc3NhZ2UtSUQ6Cgk8NGFhZGUyNTQ3Nzk4NDQxZWFiNTE4OGE3YTI0MzZiYzFAY29udG9zby5j
b20+CkFjY2VwdC1MYW5ndWFnZTogZW4tVVMKQ29udGVudC1MYW5ndWFnZTogZW4tVVMKWC1NUy1F
eGNoYW5nZS1Pcmdhbml6YXRpb24tQXV0aEFzOiBJbnRlcm5hbApYLU1TLUV4Y2hhbmdlLU9yZ2Fu
aXphdGlvbi1BdXRoTWVjaGFuaXNtOiAwNApYLU1TLUV4Y2hhbmdlLU9yZ2FuaXphdGlvbi1BdXRo
U291cmNlOiBjb250b3NvLmNvbQpYLU1TLUhhcy1BdHRhY2g6ClgtTVMtRXhjaGFuZ2UtT3JnYW5p
emF0aW9uLU5ldHdvcmstTWVzc2FnZS1JZDoKCTBmZmRiNDAyLWVjMDMtNDJjOC01ZDMyLTA4ZDRm
MzdiYjUxNwpYLU1TLUV4Y2hhbmdlLU9yZ2FuaXphdGlvbi1TQ0w6IC0xClgtTVMtVE5FRi1Db3Jy
ZWxhdG9yOgpYLU1TLUV4Y2hhbmdlLU9yZ2FuaXphdGlvbi1SZWNvcmRSZXZpZXdDZm1UeXBlOiAw
CngtbXMtcHVibGljdHJhZmZpY3R5cGU6IEVtYWlsCngtb3JpZ2luYXRpbmctaXA6IFsxMjMuNDU2
Ljc4OS4wMTJdCngtbXMtdHJhZmZpY3R5cGVkaWFnbm9zdGljOiBBU0RGRzEySEozNDU2OgpYLU1p
Y3Jvc29mdC1BbnRpc3BhbS1NYWlsYm94LURlbGl2ZXJ5OgoJdWNmOjA7am1yOjA7YXV0aDowO2Rl
c3Q6STtFTkc6KDc1MDEyOSkoNTIwMDExMDE2KSg3MDYxNTgpKDk0NDUwNjQ1OCkoOTQ0NjI2NjA0
KTsKWC1NaWNyb3NvZnQtQW50aXNwYW0tTWVzc2FnZS1JbmZvOgoJYzRVNno4NjhlZWNha1JUdFBH
NzZQemlwTlJJR2w2YWZST1B3TnFHSU1zaW0wWExKaE5vV3BNNks4SzZJNjJvZ0RBalF5cFlPN3Bp
bmlpVmY5Sm9OWnF1N3pMY3NOUkhrZTBzcWZNYjZzeTRSanhBdzVBekZoQ0duTTJIYmN2cEJQZzhP
Wi94ZWNxOXd0WXdlNzFYMFJQN3lvdmFIbFlBVUcvMEo4azhmUEdGWWNKa1lHU2xWaXNqQ0ZLMzNB
V3BMYm8xb1luRVdlaUtncTU2ZE96QXdSTnVpNzhsNHRQdzBrSW9mYWZnRXBkbnlnekdLYkF1WGkx
WXE5T0FCRUNkYzBqRUNjY1VmMUREMFZaVk5sdDE3eHFDUE5UaTYzay9YYkpwUUM2aXdwMHRuSnhJ
ZUhmWjJweG1WdkZGYnJDYWgvamRmTlpTdkN3WkdWNWNqbEFMUWFiYWZacW1mU1VtZW85Nmx4Nks4
cHBBOUlVd2hUV3REYkhpTXorU1BxWDBmeUZDbVlSNDlaYktFRnlKanRoODdqU2MwejJPbGNSZC8v
V0tySFBJeFZxSEJqbFJEWTJ1M08vOFNreXhOY1ZxcXVsRm5vQ011UjF3ZXFDSzJQYXBkUGJqMllM
N0FzWnJNNms0SENnblgvVzZ6NGhGYnlsWkNiUlpUczZBWFJPbSt5VDN1bEdobENja0lLL2ZmNHZF
VFRzZksyT3lVREoraGc1NVFWdE81Nit1Y1g1d1hqdDVYazVWZisxQlZTTVNuRzYxVEtKd1hHV21R
WnArdTQvc1YrN1k5VzIwZTlWUFNBL1NnWkhOTVVSRXNSbWtBSWs4VURkVHdGTU53SEpHYQpDb250
ZW50LVR5cGU6IG11bHRpcGFydC9hbHRlcm5hdGl2ZTsKCWJvdW5kYXJ5PSJfMDAwX01OMlBSMTNN
QjMxNTJCNUZDQTk5MTJCRUEyRTQ5MDE4OUQ1NTg5TU4yUFIxM01CMzE1Mm5hbXBfIgpNSU1FLVZl
cnNpb246IDEuMAoKLS1fMDAwX01OMlBSMTNNQjMxNTJCNUZDQTk5MTJCRUEyRTQ5MDE4OUQ1NTg5
TU4yUFIxM01CMzE1Mm5hbXBfCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD0iaXNv
LTg4NTktMSIKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogcXVvdGVkLXByaW50YWJsZQoKSGVs
bG8gQWxleCwKCldlIGFyZSB0ZXN0aW5nIHRoZSBHcmFwaCBNSU1FIGZlYXR1cmUuCgpLaW5kIHJl
Z2FyZHMsCgpBZGVsZQoKLS1fMDAwX01OMlBSMTNNQjMxNTJCNUZDQTk5MTJCRUEyRTQ5MDE4OUQ1
NTg5TU4yUFIxM01CMzE1Mm5hbXBfCkNvbnRlbnQtVHlwZTogdGV4dC9odG1sOyBjaGFyc2V0PSJp
c28tODg1OS0xIgpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBxdW90ZWQtcHJpbnRhYmxlCgo8
aHRtbD4KPGhlYWQ+CjxtZXRhIGh0dHAtZXF1aXY9M0QiQ29udGVudC1UeXBlIiBjb250ZW50PTNE
InRleHQvaHRtbDsgY2hhcnNldD0zRGlzby04ODU5LT0KMSI+CjxzdHlsZSB0eXBlPTNEInRleHQv
Y3NzIiBzdHlsZT0zRCJkaXNwbGF5Om5vbmU7Ij4gUCB7bWFyZ2luLXRvcDowO21hcmdpbi1ibz0K
dHRvbTowO30gPC9zdHlsZT4KPC9oZWFkPgo8Ym9keSBkaXI9M0QibHRyIj4KPGRpdiBzdHlsZT0z
RCJmb250LWZhbWlseTogQ2FsaWJyaSwgQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgZm9u
dC1zaXplPQo6IDEycHQ7IGNvbG9yOiByZ2IoMCwgMCwgMCk7Ij4KSGVsbG8gQWxleCwmbmJzcDs8
L2Rpdj4KPGRpdiBzdHlsZT0zRCJmb250LWZhbWlseTogQ2FsaWJyaSwgQXJpYWwsIEhlbHZldGlj
YSwgc2Fucy1zZXJpZjsgZm9udC1zaXplPQo6IDEycHQ7IGNvbG9yOiByZ2IoMCwgMCwgMCk7Ij4K
PGJyPgo8L2Rpdj4KPGRpdiBzdHlsZT0zRCJmb250LWZhbWlseTogQ2FsaWJyaSwgQXJpYWwsIEhl
bHZldGljYSwgc2Fucy1zZXJpZjsgZm9udC1zaXplPQo6IDEycHQ7IGNvbG9yOiByZ2IoMCwgMCwg
MCk7Ij4KV2UgYXJlIHRlc3RpbmcgdGhlIEdyYXBoIE1JTUUgZmVhdHVyZS4mbmJzcDs8L2Rpdj4K
PGRpdiBzdHlsZT0zRCJmb250LWZhbWlseTogQ2FsaWJyaSwgQXJpYWwsIEhlbHZldGljYSwgc2Fu
cy1zZXJpZjsgZm9udC1zaXplPQo6IDEycHQ7IGNvbG9yOiByZ2IoMCwgMCwgMCk7Ij4KPGJyPgo8
L2Rpdj4KPGRpdiBzdHlsZT0zRCJmb250LWZhbWlseTogQ2FsaWJyaSwgQXJpYWwsIEhlbHZldGlj
YSwgc2Fucy1zZXJpZjsgZm9udC1zaXplPQo6IDEycHQ7IGNvbG9yOiByZ2IoMCwgMCwgMCk7Ij4K
S2luZCByZWdhcmRzLDwvZGl2Pgo8ZGl2IHN0eWxlPTNEImZvbnQtZmFtaWx5OiBDYWxpYnJpLCBB
cmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU9CjogMTJwdDsgY29sb3I6IHJn
YigwLCAwLCAwKTsiPgo8YnI+CjwvZGl2Pgo8ZGl2IHN0eWxlPTNEImZvbnQtZmFtaWx5OiBDYWxp
YnJpLCBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU9CjogMTJwdDsgY29s
b3I6IHJnYigwLCAwLCAwKTsiPgpBZGVsZTwvZGl2Pgo8L2JvZHk+CjwvaHRtbD4KCi0tXzAwMF9N
TjJQUjEzTUIzMTUyQjVGQ0E5OTEyQkVBMkU0OTAxODlENTU4OU1OMlBSMTNNQjMxNTJuYW1wXy0t
To include a file attachment, append the file metadata and Content-Transfer-Encoding
header in base64 to the MIME content:
HTTP
--_004_MN2PR13MB3152FA5D970E0F158DF41456D5579MN2PR13MB3152namp_
Content-Type: application/vnd.openxmlformats-
officedocument.wordprocessingml.document;
name="Proposed_agenda_topics.docx"
Content-Description: Proposed_agenda_topics.docx
Content-Disposition: attachment; filename="Proposed_agenda_topics.docx";
size=707560; creation-date="Fri, 07 May 2021 14:06:45 GMT";
modification-date="Fri, 07 May 2021 14:07:28 GMT"
Content-Transfer-Encoding: base64
UEsDBBQABgAIAAAAIQA9xUZS1AEAALMLAAATAAgCW0NvbnRlbnRfVHlwZXNdLnhtbCCiBAIooAAC
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ZW0yLnhtbC5yZWxzUEsBAi0AFAAGAAgAAAAhAHvzAqPDAAAAKAEAAB4AAAAAAAAAAAAAAAAAVbgK
AGN1c3RvbVhtbC9fcmVscy9pdGVtMy54bWwucmVsc1BLAQItABQABgAIAAAAIQCyOUr/vAYAAIIe
AAATAAAAAAAAAAAAAAAAAFy6CgBjdXN0b21YbWwvaXRlbTIueG1sUEsFBgAAAAAhACEAwwgAAHHB
CgAAAA==
--_004_MN2PR13MB3152FA5D970E0F158DF41456D5579MN2PR13MB3152namp_--
MIME content malformed, POST, PUT 400 Invalid base64 string for MIME
missing content.
Next steps
Why integrate with Outlook mail
Use the mail API and its use cases in Microsoft Graph v1.0
Send Outlook messages from another
user
Article • 06/22/2022
Exchange Online provides mailbox permissions that allow a user to send mail that
appears to be sent from another user, distribution list, group, resource, or shared
mailbox. Microsoft Graph supports this feature as well, but the end result varies
depending on the exact permissions granted in Exchange Online and which API you use
to send the mail.
Permissions
Two types of permissions apply to sending messages from another user:
7 Note
Applications that use application tokens instead of user tokens and have the
Mail.Send permission consented by an administrator can send mail as any user in
the organization by sending the mail normally through the user's mailbox.
Mailbox permissions
Two permissions affect the end result of sending a message from another user: Send on
Behalf and Send As. The user that is signed in to your application with the
Mail.Send.Shared permission MUST have at least one of these permissions granted to
the mailbox, group, or distribution list that the mail is from.
7 Note
It's not currently possible to use Microsoft Graph to query which mailboxes the
authenticated user has permissions for.
Send on Behalf
With this permission, the recipient of the email has an indication in their email client that
the message was sent by the user of your application on behalf of another user.
This is exposed in Microsoft Graph as the sender (user that actually sent the message)
and from (user/group/etc. that the message appears to be from) properties.
JSON
{
"id": "AAMkAGE1...",
"subject": "Send mail test",
"sender": {
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
},
"from": {
"emailAddress": {
"name": "Pradeep Gupta",
"address": "[email protected]"
}
}
}
A user can grant this permission for their own mailbox to another user by using
Outlook . Administrators can grant this permission for any mailbox, group, or
distribution list in the Microsoft 365 admin center.
Send As
With this permission, there is no indication that the message was sent as a different
user. The sender and from properties have the same value.
Users cannot grant this permission to their mailboxes. Admins can grant this permission
in the Microsoft 365 admin center.
In order to send from another user, set the from property on the message sent to the
email address of the user to send from. You don't need to set the sender property -
Microsoft Graph will set it appropriately, based on the mailbox permissions granted to
the user who has signed in.
For example, to send mail from the [email protected] group, configure the message as
follows.
JSON
{
"subject": "January sales report",
"toRecipients": [
{
"emailAddress": {
"address": "[email protected]"
}
}
],
"from": {
"emailAddress": {
"address": "[email protected]"
}
}
}
7 Note
If the message is sent from an address that does not have a mailbox (a distribution
list, for example), there is no Sent Items for the from user.
If your application sends by using the /me endpoint (or /users/{user-id} where
the user-id corresponds to the signed in user), by default, the message will be
saved in the sending user's Sent Items folder.
If your application sends by using the /users/{user-id} where the user-id
corresponds to the from user, by default, the message will be saved in the from
user's Sent Items folder.
) Important
In order to send this way, the sending user must have the Full Access mailbox
permission in addition to either the Send on Behalf or Send As permission.
Administrators can update the from user's mailbox to always save a copy of
messages sent from a delegate to their Sent Items.
By setting the saveToSentItems property to false in a send mail request, you can
prevent the item from being saved to the Sent Items folder. However, if an
administrator has configured the "always save a copy" setting, the message will still
be saved to the from user's Sent Items.
Examples
Request
HTTP
POST /me/sendmail
Content-Type: application/json
{
"message": {
"subject": "Expense reports",
"body": {
"contentType": "text",
"content": "Have you submitted your expense reports yet?"
},
"toRecipients": [
{
"emailAddress": {
"address": "[email protected]"
}
}
],
"from": {
"emailAddress": {
"address": "[email protected]"
}
}
}
}
Response
HTTP
Request
HTTP
POST /me/sendmail
Content-Type: application/json
{
"message": {
"subject": "Support ticket",
"body": {
"contentType": "text",
"content": "I noticed you opened a support ticket yesterday..."
},
"toRecipients": [
{
"emailAddress": {
"address": "[email protected]"
}
}
],
"from": {
"emailAddress": {
"address": "[email protected]"
}
}
}
}
Response
HTTP
{
"error": {
"code": "ErrorSendAsDenied",
"message": "The user account which was used to submit this request does
not have the right to send mail on behalf of the specified sending account.
Cannot submit message.",
"innerError": {
"request-id": "24e7991e-01ae-4cc2-8e06-532a96fd8948",
"date": "2019-01-16T18:53:25"
}
}
}
Next steps
Why integrate with Outlook mail
Use the mail API and its use cases in Microsoft Graph v1.0
Explainer: How does the Microsoft
Graph API send mail?
Article • 08/24/2022
In Microsoft Graph, each of the forward, reply, replyAll, or sendMail methods creates
and sends an email message in the same call. This article summarizes how Outlook and
Exchange Online usually process these API calls to send mail behind the scenes. Most of
the steps (steps 2 to 7) take place after the method has returned.
If the sender provided MIME content, Exchange Online copies it to a single property in
the new draft message. Exchange Online then parses the MIME content and copies
relevant content to message properties, and to the recipients and attachments tables.
When complete, the method returns a 202 Accepted status code.
This step may fail for reasons such as the sender's mailbox is full, or the network
connection to the sender's server is down. If the method fails, it returns a 4xx or 5xx
status code accordingly.
Once step 1 is complete, your app's direct interaction with Microsoft Graph is over.
If step 3 fails, the transport process constructs a non-delivery report message and places
it in the sender's Inbox.
See also
Why integrate with Outlook mail.
Automate creating, sending, and processing messages.
Send messages with MIME content.
Send Outlook messages from another user.
Use the mail API and its use cases in Microsoft Graph v1.0.
Microsoft Graph APIs that create and send a draft in separate calls:
Create draft message
Create draft to reply
Create draft to reply-all
Create draft to forward message
Send draft message
Attach large files to Outlook messages
or events
Article • 03/02/2023
Using the Microsoft Graph API, you can attach files up to 150 MB to an Outlook
message or event item. Depending on the file size, choose one of two ways to attach
the file:
If the file size is under 3 MB, do a single POST on the attachments navigation
property of the Outlook item; see how to do this for a message or for an event.
The successful POST response includes the ID of the file attachment.
If the file size is between 3 MB and 150 MB, create an upload session, and
iteratively use PUT to upload ranges of bytes of the file until you have uploaded
the entire file. A header in the final successful PUT response includes a URL with
the attachment ID.
To attach multiple files to a message, choose the approach for each file based on its file
size and attach the files individually.
This article illustrates the second approach step by step, creating and using an upload
session to add a large file attachment (of size over 3 MB) to an Outlook item. Each step
shows the corresponding code for a message and for an event. Upon successfully
uploading the entire file, the article shows getting a response header that contains an ID
for the file attachment, and then using that attachment ID to get the raw attachment
content or attachment metadata.
) Important
A successful operation returns HTTP 201 Created and a new uploadSession instance,
which contains an opaque URL that you can use in subsequent PUT operations to
upload portions of the file. The uploadSession provides a temporary storage location
where the bytes of the file are saved until you have uploaded the complete file.
Permissions
Make sure to request Mail.ReadWrite permission to create the uploadSession for a
message, and Calendars.ReadWrite for an event.
The opaque URL, returned in the uploadUrl property of the new uploadSession, is pre-
authenticated and contains the appropriate authorization token for subsequent PUT
queries in the https://outlook.office.com domain. That token expires by
expirationDateTime. Do not customize this URL for the PUT operations.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/me/messages/AAMkADI5MAAIT3drCAAA=/attac
hments/createUploadSession
Content-type: application/json
{
"AttachmentItem": {
"attachmentType": "file",
"name": "flower",
"size": 3483322
}
}
Response
The following example response shows the uploadSession resource returned for the
message.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
"uploadUrl": "https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-
95c1-b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?
authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI",
"expirationDateTime": "2019-09-25T01:09:30.7671707Z",
"nextExpectedRanges": [
"0-"
]
}
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/me/events/AAMkADU5CCmSAAA=/attachments/
createUploadSession
Content-type: application/json
{
"AttachmentItem": {
"attachmentType": "file",
"name": "flower",
"size": 3483322
}
}
Response
The following example response shows the uploadSession resource returned for the
event.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
"uploadUrl": "https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-
441d-b7dc-c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJ
lCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw",
"expirationDateTime": "2020-02-22T02:46:56.7410786Z",
"nextExpectedRanges": [
"0-"
]
}
Request headers
Content- Int32 The number of bytes being uploaded in this operation. For better
Length performance, keep the upper limit of the number of bytes for each PUT
operation to 4 MB. Required.
Content- String The 0-based byte range of the file being uploaded in this operation,
Range expressed in the format bytes {start}-{end}/{total} . Required.
Do not specify an Authorization request header. The PUT query uses a pre-
authenticated URL from the uploadUrl property, that allows access to the
https://outlook.office.com domain.
Request body
Specify the actual bytes of the file to be attached, that are in the location range
specified by the Content-Range request header.
Response
A successful upload returns HTTP 200 OK and an uploadSession object. Note the
following in the response object:
The expirationDateTime property indicates the expiration date/time for the auth
token embedded in the uploadUrl property value. This expiration date/time
remains the same as returned by the initial uploadSession in step 1.
The nextExpectedRanges specifies the next byte location to start uploading from,
for example, "nextExpectedRanges":["2097152"] . You must upload bytes in a file in
order.
The uploadUrl property is not explicitly returned, because all PUT operations of an
upload session use the same URL returned when creating the session (step 1).
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
Content-Type: application/octet-stream
Content-Length: 2097152
Content-Range: bytes 0-2097151/3483322
{
<bytes 0-2097151 of the file to be attached, in binary format>
}
Response
The following example response shows in the nextExpectedRanges property the start of
the next byte range that the server expects.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
"@odata.context":"https://outlook.office.com/api/v2.0/$metadata#Users('a8e8e
219-4931-95c1-b73d-62626fd79c32%4072aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA%3D')/AttachmentSessions/$entit
y",
"ExpirationDateTime":"2019-09-25T01:09:30.7671707Z",
"nextExpectedRanges":["2097152"]
}
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJ
lCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw
Content-Type: application/octet-stream
Content-Length: 2097152
Content-Range: bytes 0-2097151/3483322
{
<bytes 0-2097151 of the file to be attached, in binary format>
}
Response
The following example response shows in the nextExpectedRanges property the start of
the next byte range that the server expects.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://outlook.office.com/api/v2.0/$metadata#Users('d3b92
14b-dd8b-441d-b7dc-c446c9fa0e69%4098a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA%3D')/AttachmentSessions/$entity",
"ExpirationDateTime":"2020-02-22T02:46:56.7410786Z",
"nextExpectedRanges":["2097152"]
}
Once the last byte of the file has been successfully uploaded, the final PUT operation
returns HTTP 201 Created and a Location header that indicates the URL to the file
attachment in the https://outlook.office.com domain. You can get the attachment ID
from the URL and save it for later use. Depending on your scenario, you can use that ID
to get the metadata of the attachment, or remove the attachment from the Outlook
item using the Microsoft Graph endpoint.
The following examples show uploading the last byte range of the file to the message
and to the event in the preceding steps.
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
Content-Type: application/octet-stream
Content-Length: 1386170
Content-Range: bytes 2097152-3483321/3483322
{
<bytes 2097152-3483321 of the file to be attached, in binary format>
}
Response
The following example response shows a Location response header from which you can
save the attachment ID ( AAMkADI5MAAIT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0= ) for later
use.
HTTP
Location: https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-
b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/Attachments('AAMkADI5MAAIT3
drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=')
Content-Length: 0
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJ
lCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw
Content-Type: application/octet-stream
Content-Length: 1386170
Content-Range: bytes 2097152-3483321/3483322
{
<bytes 2097152-3483321 of the file to be attached, in binary format>
}
Response
The following example response shows a Location response header from which you can
save the attachment ID ( AAMkADU5CCmSAAANZAlYPeyQByv7Y= ) for later use.
HTTP
HTTP/1.1 201 Created
Location: https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-
b7dc-c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/Attachments('AAMkADU5CCmSAAANZAlYP
eyQByv7Y=')
Content-Length: 0
As an alternative to getting the attachment content in base64 format, you can get
the raw data of the file attachment.
To get the metadata of the file attachment, append a $select parameter to
include only those metadata properties you want, excluding the contentBytes
property which returns the file attachment in base64 format.
Permissions
Use the least privileged delegated or application permission, Calendars.Read , as
appropriate, for this operation. For more information, see calendar permissions.
Request
HTTP
GET https://graph.microsoft.com/v1.0/Users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/Attachments('AAMkADU5CCmSAAANZAlYP
eyQByv7Y=')/$value
Response
HTTP
HTTP/1.1 200 OK
content-length: 3483322
Content-type: image/jpeg
Permissions
Use the least privileged delegated or application permission, Mail.Read , as appropriate,
for this operation. For more information, see mail permissions.
Request
HTTP
GET https://graph.microsoft.com/api/v1.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/Attachments('AAMkADI5MAAIT3
drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=')?
$select=lastModifiedDateTime,name,contentType,size,isInline
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('a8e8e219-4931-95c1-b73d-
62626fd79c32%4072aa88bf-76f0-494f-91ab-
2d7cd730db47')/messages('AAMkADI5MAAIT3drCAAA%3D')/attachments/$entity",
"@odata.type": "#microsoft.graph.fileAttachment",
"@odata.mediaContentType": "image/jpeg",
"id": "AAMkADI5MAAIT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=",
"lastModifiedDateTime": "2019-09-24T23:27:43Z",
"name": "flower",
"contentType": "image/jpeg",
"size": 3640066,
"isInline": false
}
Permissions
Because the initial opaque URL is pre-authenticated and contains the appropriate
authorization token for subsequent queries for that upload session, do not specify an
Authorization request header for this operation.
Request
HTTP
DELETE https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
Response
HTTP
ErrorAttachmentSizeShouldNotBeLessThanMinimumSize
This error is returned when attempting to create an upload session to attach a file
smaller than 3 MB. If the file size is under 3 MB, you should do a single POST on the
attachments navigation property of the message or of the event. The successful POST
response includes the ID of the file attached to the message.
Get Outlook messages in a shared or
delegated folder
Article • 06/22/2022
Outlook lets customers share mail folders with one another and provide read, create,
modify, or delete access to individual folders. Outlook also allows a customer to
delegate another user to act on the customer's behalf, and access specific mail folders
or the customer's entire mailbox; this is also known as "delegation" in Outlook.
Programmatically, Microsoft Graph supports getting messages in mail folders that have
been shared by other users, as well as getting the shared folders themselves. The
support also applies to folders that have been delegated.
As an example, Garth has shared with John and given read access to Garth's Inbox. If
John has signed into your app and provided delegated permissions (Mail.Read.Shared or
Mail.ReadWrite.Shared), your app will be able to access Garth's mail and Garth's Inbox as
described below.
Note that those two permissions do not support subscribing to change notifications on
items in shared or delegated folders. To set up change notification subscriptions on
messages in a shared, delegated, or any other user's mail folder in the tenant, use the
application permission, Mail.Read .
HTTP
HTTP
On successful completion, you'll get HTTP 200 OK and a collection of message instances
in Garth's Inbox.
HTTP
On successful completion, you'll get HTTP 200 OK and a mailFolder instance that
represents Garth's Inbox folder.
The same GET capabilities apply if Garth had delegated John further access to Garth's
Inbox, or if Garth had delegated John his entire mailbox.
If Garth has not shared his Inbox with John, nor has he delegated his mailbox to John,
specifying Garth’s user ID or user principal name in those GET operations will return an
error.
Next steps
Why integrate with Outlook mail
Use the mail API and its use cases in Microsoft Graph v1.0
Obtain immutable identifiers for
Outlook resources
Article • 06/25/2022
Outlook items (messages, events, contacts, tasks) have an interesting behavior that
you've probably either never noticed or has caused you significant frustration: their IDs
change. It doesn't happen often, only if the item is moved, but it can cause real
problems for apps that store IDs offline for later use. Immutable identifiers (IDs) enable
your application to obtain an ID that does not change for the lifetime of the item.
7 Note
Immutable identifiers, like all identifiers in Microsoft Graph, are case-sensitive. Keep
this in mind if you are comparing IDs.
How it works
Immutable ID is an optional feature for Microsoft Graph. To opt in, your application
needs to send an additional HTTP header in your API requests:
HTTP
Prefer: IdType="ImmutableId"
This header only applies to the request it is included with. If you want to always use
immutable IDs, you must include this header with every API request.
Container types (mailFolder, calendar, etc.) do not support immutable ID, but their
regular IDs were already constant.
1. Create a draft message using the Prefer: IdType="ImmutableId" header and save
the id property of the message in the response.
2. Send the message using the ID from the previous step.
3. Get the message using the ID from the first step. This is the copy in Sent Items.
7 Note
Getting the message in Sent Items may not succeed immediately after sending the
message. The copy of the message is not created until the message successfully
sends, which may take time.
with both ID formats, so your application does not need to re-synchronize to take
advantage of immutable ID. You can use the header to get immutable IDs going
forward, and you can update your app's storage separately.
7 Note
Example
The following example translates a normal Microsoft Graph ID to an immutable
Microsoft Graph ID.
Request
HTTP
POST https://graph.microsoft.com/v1.0/me/translateExchangeIds
{
"inputIds" :
[
"AQMkAGM2…"
],
"targetIdType" : "restImmutableEntryId",
"sourceIdType" : "restId"
}
Response
HTTP
HTTP 200 OK
{
"value": [
{
"targetId": "AAkALgAA...",
"sourceId": "AQMkAGM2..."
}
]
}
Change notifications for Outlook
resources in Microsoft Graph
Article • 03/02/2023
The Microsoft Graph API lets you subscribe to changes to a resource—including creation,
update, or deletion of the resource—and receive notifications via webhooks. A subscription
specifies the desired types of changes to monitor for a specific resource, and includes a
URL for an endpoint to receive notifications of those changes.
Setting up a subscription reduces the overhead of otherwise having to query and compare
resources to deduce any changes. You can optionally specify in the subscription request to
encrypt and include as part of a notification the resource data that has changed, saving a
separate subsequent API call to get the resource payload.
There is a maximum limit of 1000 active subscriptions for Outlook resources per mailbox
for all applications. You can subscribe to changes in contacts, events, or messages in the
mailbox.
The following Outlook resources support subscriptions with or without resource data in the
change notification payload.
contact
event
message
Create a subscription
To create a subscription, specify the Outlook resource and the type of changes (creation,
update, or deletion) for which you want to receive notifications. See an example.
Request permissions
Creating and managing (getting, updating, and deleting) a subscription requires a read
scope to the resource. For example, to get change notifications on messages, your app
needs the Mail.Read permission. Outlook change notifications support delegated and
application permission scopes. Note the following limitations:
Depending on the resource, use the least privileged permission specified in the following
table to call this API.
Notifications with resource data for Outlook resources are currently available only in
the Microsoft Graph beta endpoint.
To have resource data included in a change notification, you must specify the following
properties, in addition to those you normally include when creating a subscription:
resource: This property specifies the resource URL. Make sure to use the $select
query parameter to explicitly specify the Outlook resource properties to include in the
notification payload.
7 Note
encryptionCertificate: This property contains only the public key that Microsoft Graph
uses to encrypt resource data. Keep the corresponding private key to decrypt the
content.
encryptionCertificateId: This property is your own identifier for the certificate. Use
this ID to match in each change notification which certificate to use for decryption.
See an example for subscribing to change notifications with resource data for the message
resource.
One common application of $filter is to get notified upon a change in a specific resource
property. For example, you can use $filter to subscribe to unread messages in a folder
(the isRead property is false ), and include all the change types:
If you lose the permission granted earlier for a subscription and the subscription expires
meanwhile, request permission again to create a new subscription.
{
"value": [
{
"subscriptionId": "dfd11b2f-8222-4189-9545-4205c95d6235",
"subscriptionExpirationDateTime": "2021-12-31T16:16:44.9907405+05:30",
"changeType": "created",
"resource": "Users('722effaf-0433-4272-9ac4-
d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"encryptedContent": {
"data": "<<--EncryptedContent-->>",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"dataSignature": "Qw/9ubWeUYJPWWXvNiGgct2FkNG2MXTRm/BLUpJM66k=",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"resourceData": {
"@odata.type": "#microsoft.graph.message",
"@odata.id": "Users('722effaf-0433-4272-9ac4-
d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUR8n\"",
"id": "AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA="
}
}
]
"validationTokens": ["<<--ValidationTokens-->>"]
}
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
JSON
{
"[email protected]":"#DateTimeOffset",
"receivedDateTime":"2021-12-30T10:53:35Z",
"subject":"TEST MESSAGE FOR RICH NOTIFICATIONS",
"bodyPreview":"Hello,\r\n\r\nWhat\u2019s up?\r\n\r\nThanks\r\nMegan",
"[email protected]":"#microsoft.graph.importance",
"importance":"normal",
"from": {
"@odata.type":"#microsoft.graph.recipient",
"emailAddress": {
"@odata.type":"#microsoft.graph.emailAddress",
"name":"Megan Brown",
"address":"[email protected]"
}
}
}
The next example shows the payload of a notification that corresponds to an Outlook
message resource. It includes the resource and resourceData properties, which represent
the resource that triggered the notification. Use the resource and @odata.id properties to
make calls to Microsoft Graph to get the payload of the resource.
7 Note
GET calls always return the current state of the resource. If the resource is changed
between the time the notification is sent and the time the resource is retrieved, the
operation returns the state of the resource on retrieval.
JSON
"value": [
{
"subscriptionId": "c6126aa3-0ed8-412f-a988-71e6cee627c4",
"subscriptionExpirationDateTime": "2022-01-02T03:12:18.2257768+05:30",
"changeType": "created",
"resource": "Users/622eaaff-0683-4862-9de4-
f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIxAAA=",
"resourceData": {
"@odata.type": "#Microsoft.Graph.Message",
"@odata.id": "Users/622eaaff-0683-4862-9de4-
f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIAAA=",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUUXn\"",
"id": "AAMkAGUwNjQ4ZjIxAAA="
},
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}
]
Examples
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"expirationDateTime": "2021-07-07T21:42:18.2257768+00:00",
"clientState": "secretClientState"
}
Response
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "5522bd62-7c96-4530-85b0-00b916f6151a",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientState",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T21:42:18.2257768Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": null,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": null,
"encryptionCertificateId": null,
"notificationUrlAppId": null
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?
$select=Subject,bodyPreview,importance,receivedDateTime,from",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "178eec5f-cf3c-4e7e-8a9c-8640deb5b5c5",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?
$select=Subject,bodyPreview,importance,receivedDateTime,from",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "me/mailfolders('Drafts')/messages?
$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance
eq 'High'",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "239dbc5f-cf3c-4e7e-8c9c-3340abc5b5c5",
"resource": "me/mailfolders('Drafts')/messages?
$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance eq
'High'",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-20T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}
See also
Microsoft Graph change notifications
Set up change notifications that include resource data
Outlook mail API overview
Outlook contacts API overview
Outlook calendar API overview
OneNote API overview
Article • 06/25/2022
OneNote is a digital notebook that lets customers track ideas and notes for home,
school, or work, by typing, sketching, or voice, on the web, phone, tablet, or desktop.
They can freely organize notes, switch devices and pick up where they left off, and
collaborate on notes with others in real time.
https://www.youtube-nocookie.com/embed/VXd4OeQU1ek
Operation URL
API reference
Looking for the API reference for this service?
See also
Find out about a few other OneNote features that are exposed only on the OneNote
service-specific REST endpoint.
OneNote development
Work with class notebooks
Work with asynchronous class notebooks
Work with staff notebooks
Copy notebooks, sections, and pages
Manage permissions on OneNote entities
Use the OneNote save dialog on your webpages
Subscribe to webhooks
Next steps
Use the Microsoft Graph Explorer to try out the OneNote APIs with your own
OneNote notebooks.
To make OneNote API calls from the Graph Explorer, choose Show more samples
in the column on the left. Use the menu to toggle OneNote On. You will also need
to enable the appropriate permissions. Under your account name in the menu on
the left, choose modify permissions. For more information about OneNote
permissions, see Notes permissions.
Get OneNote content and structure
Article • 03/03/2023
To get OneNote content and structure by using the Microsoft Graph OneNote API, you
send a GET request to the target endpoint. For example:
GET ../onenote/pages/{id}
If the request is successful, Microsoft Graph returns a 200 OK HTTP status code and the
entities or content that you requested. OneNote entities are returned as JSON objects
that conform to the OData version 4.0 specification.
By using query string options, you can filter your queries and improve performance.
7 Note
If you're building a solution that supports one of the following scenarios, you will
reach OneNote API limitations:
For backup and restore operations, see Best practices for discovering files and
detecting changes at scale.
https://graph.microsoft.com/v1.0/me/onenote
Then append the endpoint of the resource you want to retrieve. (Resource paths are
shown in the next section.)
Your full request URI will look like one of these examples:
https://graph.microsoft.com/v1.0/me/onenote/notebooks/{id}/sections
https://graph.microsoft.com/v1.0/me/onenote/notes/pages
https://graph.microsoft.com/v1.0/me/onenote/pages?select=title,self
7 Note
Page collection
Page entity
Page preview
Page HTML content
Section collection
Section entity
SectionGroup collection
SectionGroup entity
Notebook collection
Notebook entity
Image or other file resource
Page collection
Get pages (metadata) across all notebooks.
../pages[?filter,orderby,select,expand,top,skip,search,count]
../sections/{section-id}/pages[?
filter,orderby,select,expand,top,skip,search,count,pagelevel]
The search query string option is available for consumer notebooks only.
The default query expands the parent section and selects the section's id , name , and
self properties.
By default, only the top 20 entries are returned for GET pages requests. Requests that
don't specify a top query string option return an @odata.nextLink link in the response
that you can use to get the next 20 entries.
For the pages collection in a section, use pagelevel to return the indentation level of
pages and their order within the section.
Example
GET ../sections/{section-id}/pages?pagelevel=true
Page entity
Get the metadata for a specific page.
../pages/{page-id}[?select,expand,pagelevel]
The default query expands the parent section and selects the section's id , name , and
self properties.
Use pagelevel to return the indentation level of the page and its order within its parent
section.
Example
GET ../pages/{page-id}?pagelevel=true
Page preview
Get text and image preview content for a page.
../pages/{page-id}/preview
The JSON response contains the preview content, which you can use to help users
identify what's in the page.
JSON
"@odata.context":"https://www.onenote.com/api/v1.0/$metadata#Microsoft.OneNo
te.Api.PagePreview",
"previewText":"text-snippet",
"links":{
"previewImageUrl":{
"href":"https://www.onenote.com/api/v1.0/resources/{id}/content?
publicAuth=true&mimeType=image/png"
}
}
}
The previewText property contains a text snippet from the page. Microsoft Graph
returns complete phrases, up to a maximum of 300 characters.
If the page has an image that can be used to build a preview UI, the href property in the
previewImageUrl object contains a link to a public image resource. You can use this link
in HTML. Otherwise, href returns null.
Example
<img src="https://www.onenote.com/api/v1.0/resources/{id}/content?
publicAuth=true&mimeType=image/png" />
../pages/{page-id}/content[?includeIDs]
Use the includeIDs=true query string option to get generated IDs used to update the
page.
Section collection
Get all sections from all notebooks that are owned by the user, including sections in
nested section groups.
../sections[?filter,orderby,select,top,skip,expand,count]
Get all sections that are directly under a specific section group.
../sectionGroups/{sectiongroup-id}/sections[?
filter,orderby,select,top,skip,expand,count]
../notebooks/{notebook-id}/sections[?filter,orderby,select,top,skip,expand,count]
The default query expands the parent notebook and parent section group and selects
their id , name , and self properties.
Section entity
Get a specific section.
../sections/{section-id}[?select,expand]
The default query expands the parent notebook and parent section group and selects
their id , name , and self properties.
SectionGroup collection
Get all section groups from all notebooks that are owned by the user, including nested
section groups.
../sectionGroups[?filter,orderby,select,top,skip,expand,count]
Get all section groups that are directly under a specific notebook.
../notebooks/{notebook-id}/sectionGroups[?
filter,orderby,select,top,skip,expand,count]
The default query expands the parent notebook and parent section group and selects
their id , name , and self properties.
SectionGroup entity
Get a specific section group.
../sectionGroups/{sectiongroup-id}[?select,expand]
Notebook collection
Get all the notebooks that are owned by the user.
../notebooks[?filter,orderby,select,top,skip,expand,count]
Notebook entity
Get a specific notebook.
../notebooks/{notebook-id}[?select,expand]
../resources/{resource-id}/$value
You can find the file's resource URI in the page's output HTML.
For example, an img tag includes endpoints for the original image in the data-fullres-
src attribute and the optimized image in the src attribute.
Example
HTML
<img
src="https://www.onenote.com/api/v1.0/me/notes/resources/{image-
id}/$value"
data-src-type="image/png"
data-fullres-src="https://www.onenote.com/api/v1.0/resources/{image-
id}/$value"
data-fullres-src-type="image/png" ... />
And an object tag includes the endpoint for the file resource in the data attribute.
Example
HTML
<object
data="https://www.onenote.com/api/v1.0/me/notes/resources/{file-
id}/$value"
data-attachment="fileName.pdf"
type="application/pdf" ... />
7 Note
When you get a file resource, you don't need to include an Accept content type in the
request.
For more information about GET requests, see the following resources in the Microsoft
Graph API REST reference:
GET Pages
GET Sections
GET SectionGroups
GET Notebooks
Remember:
}/notes/
expand
Get all notebooks and expand their sections and section groups.
[GET] ../notebooks?expand=sections,sectionGroups
Get a specific section group and expand its sections and section groups.
[GET] ../sectionGroups/{sectiongroup-id}?expand=sections,sectionGroups
Get a page and expand its parent section and parent notebook.
[GET] ../pages/{page-id}?expand=parentSection,parentNotebook
[GET] ../notebooks?expand=sections,sectionGroups(expand=sections)
7 Note
[GET] ../sectionGroups/{sectiongroup-id}?
expand=sections(select=name,self)&select=name,self
Get the name and self link for all sections, and get the name and created time of each
section's parent notebook.
[GET] ../sections?
expand=parentNotebook(select=name,createdTime)&select=name,self
Get the title and ID for all pages, and get the name of the parent section and parent
notebook.
[GET] ../pages?
select=id,title&expand=parentSection(select=name),parentNotebook(select=name
)
[GET] ../notebooks?
expand=sections,sectionGroups(expand=sections,sectionGroups(levels=max;expan
d=sections))
filter
Get all sections that were created in October 2014.
Get the pages that were created by a specific app since January 1, 2015.
[GET] ../notebooks?filter=tolower(name) eq
'school'&expand=sections(select=name,pagesUrl)
[GET] ../sections?
filter=contains(tolower(name),'spring')&select=name,pagesUrl&orderby=lastMod
ifiedTime desc
orderby
Get the first 20 pages ordered by createdByAppId property and then by most recent
created time. The API returns 20 entries by default.
And the next five ( search is available for consumer notebooks only).
7 Note
If both search and filter are applied to the same request, the results include only
those entities that match both criteria.
select
Get the name, created time, and self link for all sections in the user's notebooks.
[GET] ../sections?select=name,createdTime,self
Get the title, created time, and OneNote client links for a specific page.
[GET] ../pages/{page-id}?select=title,createdTime,links
[GET] ../pages?top=50&select=title,self&orderby=title
[GET] ../pages?skip=50&top=50&select=title,self&orderby=title
7 Note
GET requests for pages that retrieve the default number of entries (that is, they
don't specify a top expression) return an @odata.nextLink link in the response that
you can use to get the next 20 entries.
7 Note
For readability, the examples in this article don't use the %20 percent-encoding
required for spaces in the URL query string: filter=isDefault%20eq%20true
Query Example and description
option
count count=true
The count of entities in the collection. The value is returned in the @odata.count
property in the response.
expand expand=sections,sectionGroups
The navigation properties to return inline in the response. The following properties are
supported for expand expressions:
- Pages: parentNotebook, parentSection
- Sections: parentNotebook, parentSectionGroup
- Section groups: sections, sectionGroups, parentNotebook, parentSectionGroup
- Notebooks: sections, sectionGroups
By default, GET requests for pages expands parentSection and select the section's id,
name, and self properties. Default GET requests for sections and section groups expand
both parentNotebook and parentSectionGroup, and select the parents' id, name, and
self properties.
A Boolean expression for whether to include an entry in the result set. Supports the
following OData operators and functions:
- Comparison operators: eq, ne, gt, ge, lt, le
- Logical operators: and, or, not
- String functions: contains, endswith, startswith, length, indexof, substring, tolower,
toupper, trim, concat
The properties to sort by, with an optional asc (default) or desc sort order. You can sort
by any property of the entity in the requested collection.
The default sort order for notebooks, section groups, and sections is name asc , and for
pages is lastModifiedTime desc (last modified page first).
Separate multiple properties with commas, and list them in the order that you want
them applied. Property names are case-sensitive.
Query Example and description
option
The term or phrase to search for in the page title, page body, image alt text, and image
OCR text. By default, search queries return results sorted by relevance.
OneNote uses Bing full-text search to support phrase search, stemming, spelling
forgiveness, relevance and ranking, word breaking, multiple languages, and other full-
text search features. Search strings are case-insensitive.
Applies only to pages in notebooks owned by the user. Indexed content is private and
can only be accessed by the owner. Password-protected pages are not indexed. Applies
only to the pages endpoint.
select select=id,title
The properties to return. Can be used for a single entity or for a collection. Separate
multiple properties with commas. Property names are case-sensitive.
skip skip=10
The number of entries to skip in the result set. Typically used for paging results.
top top=50
The number of entries to return in the result set, up to a maximum of 100. The default
value is 20.
Microsoft Graph also provides the pagelevel query string option you can use to get the
level and order of pages within the parent section. Applies only to queries for pages in a
specific section or queries for a specific page.
Examples
GET ../sections/{section-id}/pages?pagelevel=true
GET ../pages/{page-id}?pagelevel=true
Spaces in the URL query string must be replaced with the %20 encoding.
Example: filter=isDefault%20eq%20true
eq createdByAppId eq '{app-id}'
(equal to)
ne userRole ne 'Owner'
(not equal to)
gt createdTime gt 2014-02-23
(greater than)
ge lastModifiedTime ge 2014-05-05T07:00:00Z
(greater than or equal to)
lt createdTime lt 2014-02-23
(less than)
le lastModifiedTime le 2014-02-23
(less than or equal to)
String Example
function
contains contains(tolower(title),'spring')
endswith endswith(tolower(title),'spring')
startswith startswith(tolower(title),'spring')
length length(title) eq 19
indexof indexof(tolower(title),'spring') eq 1
String Example
function
Example
../sections?filter=createdTime ge 2015-01-
01&select=name,pagesUrl&orderby=lastModifiedTime desc
For the list of properties and property types, see the following resources in the
Microsoft Graph API REST reference:
GET Pages
GET Sections
GET SectionGroups
GET Notebooks
The expand query string option can be used with the following navigation properties:
Authorization Bearer {token} , where {token} is a valid OAuth 2.0 access token for your
header registered app.
If missing or invalid, the request fails with a 401 status code. See
Authentication and permissions.
Response Description
data
Response An OData representation of the entity or entity set in JSON format, the page
body HTML, or file resource binary data.
Errors If the request fails, the API returns errors in the @api.diagnostics object in the
response body.
X- A GUID that uniquely identifies the request. You can use this value along with the
CorrelationId value of the Date header when working with Microsoft support to troubleshoot
header issues.
https://graph.microsoft.com/{version}/me/onenote/
The version segment in the URL represents the version of Microsoft Graph that you
want to use. Use v1.0 for stable production code. Use beta to try out a feature that's in
development. Features and functionality in beta may change, so you shouldn't use it in
your production code.
Use me for OneNote content that the current user can access (owned and shared). Use
users/{id} for OneNote content that the specified user (in the URL) has shared with the
The following scopes allow GET requests to Microsoft Graph. Choose the lowest level of
permissions that your app needs to do its work.
Choose from:
Notes.read
Notes.ReadWrite
Notes.ReadWrite.All
For more information about permission scopes and how they work, see Microsoft Graph
permissions reference.
See also
Input and output HTML for OneNote pages
Integrate with OneNote
OneNote Developer Blog
OneNote development questions on Microsoft Q&A
OneNote GitHub repos
Open the OneNote client
Article • 03/03/2023
You can use the links property of a page or notebook to open a OneNote application to
a particular page or notebook.
The links property is a JSON object that contains two URLs. The URLs will open the page
or notebook in the OneNote client application or in OneNote on the web.
JSON
{
"links": {
"oneNoteClientUrl": {
"href": "onenote:https://..."
},
"oneNoteWebUrl": {
"href": "https://..."
}
}
}
oneNoteClientUrl
Opens the OneNote client if it is already installed on the device. This URL
includes the onenote prefix.
Opens the language-specific version if one is installed on the device. Otherwise,
uses the platform language setting.
oneNoteWebUrl
Opens OneNote on the web if the default browser on the device supports it.
Uses the browser language setting.
The OneNote API returns the links property in the HTTP response for the following
operations:
iOS example
The following example gets the OneNote client URLs from the JSON response. It uses
the AFNetworking library ( https://afnetworking.com/ ) to extract the two URLs. In the
example, created is a pointer to the ONSCPSStandardResponse object used to store
the response values, and responseObject holds the parsed JSON.
Objective-C
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if(delegate) {
int status = [returnResponse statusCode];
ONSCPSStandardResponse *standardResponse = nil;
if (status == 201) {
ONSCPSCreateSuccessResponse *created =
[[ONSCPSCreateSuccessResponse alloc] init];
created.httpStatusCode = status;
NSError *jsonError;
NSDictionary *responseObject =
[NSJSONSerialization
JSONObjectWithData:returnData options:0 error:&jsonError];
if(responseObject && !jsonError) {
created.oneNoteClientUrl = ((NSDictionary *)
((NSDictionary
*)responseObject[@"links"])[@"oneNoteClientUrl"])[@"href"];
created.oneNoteWebUrl = ((NSDictionary *)
((NSDictionary
*)responseObject[@"links"])[@"oneNoteWebUrl"])[@"href"];
}
standardResponse = created;
}
else {
ONSCPSStandardErrorResponse *error =
[[ONSCPSStandardErrorResponse alloc] init];
error.httpStatusCode = status;
error.message = [[NSString alloc]
initWithData:returnData
encoding:NSUTF8StringEncoding];
standardResponse = error;
}
// Send the response back to the client.
if (standardResponse) {
[delegate
exampleServiceActionDidCompleteWithResponse: standardResponse];
}
}
}
After you parse the URLs from the response, you can open OneNote by using the
following code. Use oneNoteClientUrl to open the installed OneNote client or
oneNoteWebURL to open OneNote on the web.
Objective-C
Android example
First, check for the success status code, and then parse the JSON. The example assumes
a POST request was sent, so it checks for a 201 Created status code. If you made a GET
request, check for a 200 status code instead.
Java
/* Create a new JSON object, and an object to hold the response URLs. */
JSONObject responseObject = null;
ApiResponse response = new ApiResponse();
try {
"links").getJSONObject("oneNoteClientUrl").getString("href");
String webUrl = responseObject.getJSONObject(
"links").getJSONObject("oneNoteWebUrl").getString("href");
response.setOneNoteClientUrl(clientUrl);
response.setOneNoteWebUrl(webUrl);
}
} catch (JSONException ex) {
Using the response properties, your app can open OneNote on the web, as shown in the
following example.
Java
if (response.getResponseCode() == 201) {
Uri uriUrl = Uri.parse(response.getOneNoteWebUrl);
Intent launchBrowser = new Intent(Intent.ACTION_VIEW, uriUrl);
startActivity(launchBrowser);
}
Or your app can open the OneNote client on an Android device. When using the
oneNoteClientUrl property, you must surround the GUID strings with braces { } before
Java
if (response.getResponseCode() == 201) {
See also
Get OneNote content and structure
Create OneNote pages
Create OneNote pages
Article • 03/03/2023
To create a OneNote page, you send a POST request to a pages endpoint. For example:
POST ../notes/sections/{id}/pages
Send the HTML that defines the page in the message body. If the request is successful,
Microsoft Graph returns a 201 HTTP status code.
7 Note
To learn about the POST requests you can send to create sections, section groups,
and notebooks, see our interactive REST reference .
https://graph.microsoft.com/v1.0/me/onenote
.../pages?sectionName=DefaultSection
.../sections/{section-id}/pages
If you're creating pages in the user's personal notebook, Microsoft Graph also provides
endpoints that you can use to create pages in the default notebook:
../pages
Your full request URI will look like one of these examples:
https://graph.microsoft.com/v1.0/me/onenote/sections/{id}/pages
https://graph.microsoft.com/v1.0/me/onenote/pages?sectionName=Homework
Only top-level sections can be referenced (not sections within section groups).
If a section with the specified name doesn't exist in the default notebook, the API
creates it. These characters are not allowed for section names: ? * \ / : < > | & #
" % ~
Section names are case-insensitive for matching, but case is preserved when
sections are created. So "My New Section" will display like that, but "my new
section" would also match on subsequent posts.
The sectionName parameter is valid only with the ../notes/pages route (not
../notes/sections/{id}/pages ).
Because sections are created if they don't exist, it's safe to use this call with every page
your app creates. Users might rename sections, but the API will create a new section
with the section name that you supply.
7 Note
The links returned by the API for pages in a renamed section will still reach those
older pages.
Send the input HTML in the message body of the POST request. You can send the input
HTML directly in the message body using the application/xhtml+xml or text/html
content type, or you can send it in the "Presentation" part of a multipart request.
The following example sends the input HTML directly in the message body.
HTML
POST https://graph.microsoft.com/v1.0/me/onenote/pages
Authorization: Bearer {token}
Content-Type: application/xhtml+xml
<!DOCTYPE html>
<html>
<head>
<title>A page with a block of HTML</title>
<meta name="created" content="2015-07-22T09:00:00-08:00" />
</head>
<body>
<p>This page contains some <i>formatted</i> <b>text</b> and an image.
</p>
<img src="https://..." alt="an image on the page" width="500" />
</body>
</html>
7 Note
To simplify programming and consistency in your app, you can use multipart
requests to create all pages. It's a good idea to use a library to construct multipart
messages. This reduces the risk of creating malformed payloads.
Input HTML should be UTF-8 encoded and well-formed XHTML. All container start
tags require matching closing tags. All attribute values must be surrounded by
double- or single-quote marks.
The following list shows the basic element types that Microsoft Graph supports:
Microsoft Graph preserves the semantic content and basic structure of the input HTML
when it creates pages, but it converts the input HTML to use the supported set of HTML
and CSS. Features that don't exist in OneNote have nothing to be translated to, so they
might not be recognized in the source HTML.
Example request
This example multipart request creates a page that contains images and an embedded
file. The required Presentation part contains the input HTML that defines the page. The
imageBlock1 part contains the binary image data, and fileBlock1 contains the binary file
data. Data parts can also contain HTML, in which case Microsoft Graph renders the
HTML as an image on the OneNote page.
HTML
POST https://graph.microsoft.com/v1.0/me/onenote/pages
Authorization: Bearer {token}
Content-Type: multipart/form-data; boundary=MyPartBoundary198374
--MyPartBoundary198374
Content-Disposition:form-data; name="Presentation"
Content-Type:text/html
<!DOCTYPE html>
<html>
<head>
<title>A page with rendered images and an attached file</title>
<meta name="created" content="2015-07-22T09:00:00-08:00" />
</head>
<body>
<p>Here's an image from an <i>online source</i>:</p>
<img src="https://..." alt="an image on the page" width="500" />
<p>Here's an image uploaded as <b>binary data</b>:</p>
<img src="name:imageBlock1" alt="an image on the page" width="300" />
<p>Here's a file attachment:</p>
<object data-attachment="FileName.pdf" data="name:fileBlock1"
type="application/pdf" />
</body>
</html>
--MyPartBoundary198374
Content-Disposition:form-data; name="imageBlock1"
Content-Type:image/jpeg
--MyPartBoundary198374
Content-Disposition:form-data; name="fileBlock1"
Content-Type:application/pdf
--MyPartBoundary198374--
For more examples that show how to create pages that contain images and other files,
see Add images and files, our tutorials, and our samples . Also, learn how to create
absolute positioned elements, use note tags, and extract data for business card captures
and online recipe and product listings.
Microsoft Graph is strict about some formats, such as CRLF newlines in a multipart
message body. To reduce the risk of creating malformed payloads, you should use a
library to construct multipart messages.
If you do receive a 400 status for a malformed payload, check the formatting of newlines
and whitespaces, and check for encoding issues. For example, try using charset=utf-8
(example: Content-Type: text/html; charset=utf-8 ).
See requirements and limitations for input HTML and size limits for POST requests.
Request and response information for POST
pages requests
Request Description
data
Authorization Bearer {token} , where {token} is a valid OAuth 2.0 access token for your
header registered app.
If missing or invalid, the request fails with a 401 status code. See Authentication
and permissions.
Content-Type text/html or application/xhtml+xml for the HTML content, whether it's sent
header directly in the message body or in the required "Presentation" part of multipart
requests.
Multipart requests are required when sending binary data, and use the
multipart/form-data; boundary=part-boundary content type, where {part-
boundary} is a string that signals the start and end of each data part.
Accept application/json
header
Response Description
data
Errors If the request fails, the API returns errors in the @api.diagnostics object in the
response body.
X- A GUID that uniquely identifies the request. You can use this value along with the
CorrelationId value of the Date header when working with Microsoft support to troubleshoot
header issues.
https://graph.microsoft.com/{version}/me/onenote/
The version segment in the URL represents the version of Microsoft Graph that you
want to use. Use v1.0 for stable production code. Use beta to try out a feature that's in
development. Features and functionality in beta may change, so you shouldn't use it in
your production code.
Use me for OneNote content that the current user can access (owned and shared). Use
users/{id} for OneNote content that the specified user (in the URL) has shared with the
current user. Use Microsoft Graph to get user IDs.
Permissions
To create OneNote pages, you'll need to request appropriate permissions. Choose the
lowest level of permissions that your app needs to do its work.
Choose from:
Notes.Create
Notes.ReadWrite
Notes.ReadWrite.All
For more information about permission scopes and how they work, see Microsoft Graph
permissions reference.
See also
Add images and files
Create absolute positioned elements
Extract data
Use note tags
Integrate with OneNote
OneNote Developer Blog
OneNote development questions on Microsoft Q&A
OneNote GitHub repos
Update OneNote page content
Article • 12/10/2022
To update the content of a OneNote page, you send a PATCH request to the page's
content endpoint:
PATCH ../notes/pages/{id}/content
Send a JSON change object in the message body. If the request is successful, Microsoft
Graph returns a 204 HTTP status code.
https://graph.microsoft.com/v1.0/me/onenote
../pages/{id}/content
Get the page HTML, all defined data-id values, and all generated id values
../pages/{page-id}/content?includeIDs=true
The data-id and id values are used as target identifiers for the elements you want to
update.
https://graph.microsoft.com/v1.0/me/onenote/pages/{id}/content
Your changes are sent in the message body as an array of JSON change objects. Each
object specifies the target element, new HTML content, and what to do with the content.
The following array defines two changes. The first inserts an image above a paragraph
as a sibling, and the second appends an item to a list as a last child.
7 Note
When updating an image on a OneNote page, you can't use www links. The service
won't try to download random resources. Instead, the image must be part of the
request, either by an image-data-url or a part-name of a multipart request.
JSON
[
{
'target':'#para-id',
'action':'insert',
'position':'before',
'content':'<img src="image-data-url-or-part-name" alt="Image above the
target paragraph" />'
},
{
'target':'#list-id',
'action':'append',
'content':'<li>Item at the end of the list</li>'
}
]
target
The element to update. The value must be one of the following identifiers:
Identifier Description
#{data-id} This ID is optionally defined on elements in the input HTML when creating a page or
updating a page. Prefix the value with a #.
Example:
'target':'#intro' targets the element <div data-id="intro" ...>
id This is the generated ID from Microsoft Graph, and is required for most replace
operations. Do not prefix with a #.
Example:
'target':'div:{33f8a2...}{37}' targets the element <div id="div:{33f8a2...}{37}"
...>
Don't confuse these with any id values defined in the input HTML. All id values sent
in the input HTML are discarded.
body The keyword that targets the first div on the page. Do not prefix with a #.
title The keyword that targets the page title. Do not prefix with a #.
action
The action to perform on the target element. See supported actions for elements.
Action Description
append Adds the supplied content to the target as a first or last child, as determined by the
position attribute.
insert Adds the supplied content as a sibling before or after the target, as determined by the
position attribute.
prepend Adds the supplied content to the target as a first child. Shortcut for append + before.
Most replace actions require using the generated ID for the target (except img and
object elements within a div, which also support using data-id).
position
The location to add the supplied content, relative to the target element. Defaults to
after if omitted.
Position Description
after (default) With append: The last child of the target element.
content
A string of well-formed HTML to add to the page, and any image or file binary data. If
the content contains binary data, the request must be sent using the multipart/form-
data content type with a "Commands" part (see an example).
Generated IDs
Microsoft Graph generates id values for the elements on the page that can be updated.
To get generated IDs, use the includeIDs=true query string expression in your GET
request:
GET ../notes/pages/{page-id}/content?includeIDs=true
7 Note
The API discards all id values that are defined in the input HTML of create-page
and update-page requests.
The following example shows generated IDs for a paragraph and an image in the output
HTML of a page.
HTML
Generated id values might change after a page update, so you should get the current
values before building a PATCH request that uses them.
You can specify target elements by using the data-id or id value, as follows:
For append and insert actions, you can use either ID as the target value.
For replace actions, you must use the generated ID for all elements except for the
page title and images and objects that are within a div.
To replace a title, use the title keyword.
To replace images and objects that are within a div, use either data-id or id.
The following example uses the id value for the target. Don't use the # prefix with a
generated ID.
JSON
[
{
'target':'p:{33f8a242-7c33-4bb2-90c5-8425a68cc5bf}{40}',
'action':'insert',
'position':'before',
'content':'<p>This paragraph goes above the target paragraph.</p>'
}
]
body no yes no
(targets first div on the page)
div no yes no
(absolute positioned)
title yes no no
Example requests
An update request contains one or more changes represented as JSON change objects.
These objects can define different targets on the page and different actions and content
for the targets.
The following examples include JSON objects used in PATCH requests and complete
PATCH requests:
Append to a div
The following example adds two child nodes to the div1 element. It adds an image as
the first child and a paragraph as the last child.
JSON
[
{
'target':'#div1',
'action':'append',
'position':'before',
'content':'<img data-id="first-child" src="image-url-or-part-name" />'
},
{
'target':'#div1',
'action':'append',
'content':'<p data-id="last-child">New paragraph appended to the
div</p>'
}
]
The following example adds two paragraphs as the first child and the last child to the
first div on the page. Don't use a # with the body target. This example uses the prepend
action as a shortcut for append + before.
JSON
[
{
'target':'body',
'action':'prepend',
'content':'<p data-id="first-child">New paragraph as first child in the
first div</p>'
},
{
'target':'body',
'action':'append',
'content':'<p data-id="last-child">New paragraph as last child in the
first div</p>'
}
]
Append to a list
The following example adds a list item as a last child to the target list. The list-style-type
property is defined because the item uses a non-default list style.
JSON
[
{
'target':'#circle-ul',
'action':'append',
'content':'<li style="list-style-type:circle">Item at the end of the
list</li>'
}
]
Insert siblings
The following example adds two sibling nodes to the page. It adds an image above the
para1 element and a paragraph below the para2 element.
JSON
[
{
'target':'#para1',
'action':'insert',
'position':'before',
'content':'<img src="image-data-url-or-part-name" alt="Image inserted
above the target" />'
},
{
'target':'#para2',
'action':'insert',
'content':'<p data-id="next-sibling">Paragraph inserted below the
target</p>'
}
]
Replace elements
You can use either the data-id or generated id as the target value to replace img and
object elements that are within a div. To replace the page title, use the title keyword. For
all other elements that support replace, you must use the generated ID.
Replace an image
The following example replaces an image with a div by using the image's data-id as the
target.
JSON
[
{
'target':'#img1',
'action':'replace',
'content':'<div data-id="new-div"><p>This div replaces the image</p>
</div>'
}
]
Update a table
This example shows how to update a table by using its generated ID. Replacing tr and td
elements is not supported, but you can replace the entire table.
JSON
[
{
'target':'table:{de3e0977-94e4-4bb0-8fee-0379eaf47486}{11}',
'action':'replace',
'content':'<table data-id="football">
<tr><td><p><b>Brazil</b></p></td><td><p>Germany</p></td></tr>
<tr><td><p>France</p></td><td><p><b>Italy</b></p></td></tr>
<tr><td><p>Netherlands</p></td><td><p><b>Spain</b></p></td></tr>
<tr><td><p>Argentina</p></td><td><p><b>Germany</b></p></td></tr>
</table>'
}
]
[
{
'target':'title',
'action':'replace',
'content':'New title'
}
]
The following example uses the replace action to change a to-do check box item to a
completed state.
JSON
[
{
'target':'p:{33f8a242-7c33-4bb2-90c5-8425a68cc5bf}{40}',
'action':'replace',
'content':'<p data-tag="to-do:completed" data-id="task1">First task</p>'
}
]
See Use note tags for more about using the data-tag attribute.
The following example shows a PATCH request that uses the application/json content
type. You can use this format when your content doesn't contain binary data.
HTTP
PATCH https://graph.microsoft.com/v1.0/me/onenote/notebooks/pages/{page-
id}/content
Content-Type: application/json
Authorization: Bearer {token}
[
{
'target':'#para-id',
'action':'insert',
'position':'before',
'content':'<img src="image-data-url" alt="New image from a URL" />'
},
{
'target':'#list-id',
'action':'append',
'content':'<li>Item at the bottom of the list</li>'
}
]
HTTP
PATCH https://graph.microsoft.com/v1.0/me/onenote/notebooks/pages/{page-
id}/content
--PartBoundary123
Content-Disposition: form-data; name="Commands"
Content-Type: application/json
[
{
'target':'img:{2998967e-69b3-413f-a221-c1a3b5cbe0fc}{42}',
'action':'replace',
'content':'<img src="name:image-part-name" alt="New binary image" />'
},
{
'target':'#list-id',
'action':'append',
'content':'<li>Item at the bottom of the list</li>'
}
]
--PartBoundary123
Content-Disposition: form-data; name="image-part-name"
Content-Type: image/png
Authorization Bearer {token} , where {token} is a valid OAuth 2.0 access token for your
header registered app.
If missing or invalid, the request fails with a 401 status code. See Authentication
and permissions.
Content-Type application/json for the array of JSON change objects, whether sent directly in
header the message body or in the required "Commands" part of multipart requests.
Multipart requests are required when sending binary data, and use the
multipart/form-data; boundary=part-boundary content type, where {part-
boundary} is a string that signals the start and end of each data part.
Response Description
data
Success A 204 HTTP status code. No JSON data is returned for a PATCH request.
code
Errors Read Error codes for OneNote APIs in Microsoft Graph to learn about OneNote
errors that Microsoft Graph can return.
https://graph.microsoft.com/{version}/me/onenote/
The version segment in the URL represents the version of Microsoft Graph that you
want to use. v1.0 is for stable production code. beta is to try out a feature that's in
development. Features and functionality in beta may change, so you shouldn't use it in
your production code.
me is for OneNote content that the current user can access (owned and shared).
users/{id} is for OneNote content that the specified user (in the URL) has shared with
the current user. Use the users API.
7 Note
Permissions
To update OneNote pages, you'll need to request appropriate permissions. Choose the
lowest level of permissions that your app needs to do its work.
Notes.ReadWrite
Notes.ReadWrite.All
For more information about permission scopes and how they work, see OneNote
permission scopes.
See also
Add images and files
Integrate with OneNote
OneNote Developer Blog
OneNote development questions on Microsoft Q&A
OneNote GitHub repos
Add images, videos, and files to
OneNote pages
Article • 06/25/2022
You can use img, object, and iframe elements to add images, videos, and files to a
OneNote page when you're creating or updating the page.
Adding images
Images can be added by URL reference or by sending raw data. Microsoft Graph
supports the following methods of adding images, logos, and photos to OneNote
pages.
Use img with src="https://image-url" and specify the URL of a publicly accessible
image. Renders the image on the OneNote page.
Use img with src="name:image-block-name" and send the image file in a data part of a
multipart request. Renders the image on the OneNote page.
Use img with data-render-src="name:html-block-name" and send HTML in the data part
of a multipart request. Renders the HTML as an image on the OneNote page.
Use <img data-render-src="name:part-name" /> and send the PDF file in the data part of
a multipart request. Renders each PDF page as a separate image on the OneNote page.
Add an image file as a file attachment
7 Note
To get images on a OneNote page, first send a GET request for the page content.
This returns the URLs to the image resources on the page. You then separate GET
requests to the image resources.
Image attributes
An img element can optionally include alt, height, and width attributes, and the style
attributes max-width and max-height.
Microsoft Graph supports TIFF, PNG, GIF, JPEG, and BMP image types. To capture an
image that uses a different format that you don't want to convert, send the binary data
in a multipart request. You don't need to use Base64 or otherwise encode the binary
data that you send.
7 Note
The API detects the original input image type, and returns it as the data-fullres-src-
type attribute in the output HTML. The API also returns the image type of the
optimized image in data-src-type.
See limitations that apply when creating pages that contain media.
HTML
<!DOCTYPE html>
<html>
<head>
<title>A page with an image: Public URL</title>
<meta name="created" value="2015-11-11T12:45:00.000-8:00"/>
</head>
<body>
<p>This page displays an image from the web.</p>
<img src="https://..." width="300"/>
</body>
</html>
--MyAppPartBoundary--
request that contains the binary image data. Just send the binary data, don't use Base64
or otherwise encode it.
HTML
--MyAppPartBoundary
Content-Disposition: form-data; name="Presentation"
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<title>A page with an image: Image binary data</title>
<meta name="created" value="2015-11-11T12:45:00.000-8:00"/>
</head>
<body>
<p>This page displays the uploaded image.</p>
<img src="name:image-block-name" alt="a cool image" width="500"/>
</body>
</html>
--MyAppPartBoundary
Content-Disposition: form-data; name="MyAppPictureId"
Content-Type: image/jpeg
... image binary data ...
--MyAppPartBoundary--
In the input HTML of your request, include <img src="https://..." /> and specify the
URL of the webpage you want to insert for the src attribute.
HTML
--MyAppPartBoundary
Content-Disposition: form-data; name="Presentation"
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<title>A page with an image: Webpage capture</title>
<meta name="created" value="2015-11-11T12:45:00.000-8:00"/>
</head>
<body>
<p>This page displays an image of the webpage.</p>
<img data-render-src="https://www.onenote.com" width="200"/>
</body>
</html>
--MyAppPartBoundary--
HTML
--MyAppPartBoundary
Content-Disposition: form-data; name="Presentation"
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<title>A page with an image: HTML block</title>
<meta name="created" value="2015-11-11T12:45:00.000-8:00"/>
</head>
<body>
<p>This page displays the block of HTML as an image.</p>
<img data-render-src="name:html-block-name" alt="a cool image"
width="500"/>
</body>
</html>
--MyAppPartBoundary
Content-Disposition: form-data; name="html-block-name"
Content-Type: text/html
<html>
<body>
<h1>This HTML will render as an image</h1>
<p><b>Don't</b> try to embed another <i>data-render-src</i> type-image
inside the HTML part--
it won't work. Instead, use URL-based real images like this:</p>
<img src="https://cdn.onenote.net/1664161560_Images/OneNote.ico" />
</body>
</html>
--MyAppPartBoundary--
request that contains the binary image data. Just send the binary data, don't use Base64
or otherwise encode it.
HTML
--MyAppPartBoundary
Content-Disposition: form-data; name="Presentation"
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<title>A page with an image: Binary image data as file
attachment</title>
<meta name="created" value="2015-11-11T12:45:00.000-8:00"/>
</head>
<body>
<p>This page contains the image as a file attachment.</p>
<object data-attachment="image-file.jpg" data="name:image-block-name"
type="image/jpeg" />
</body>
</html>
--MyAppPartBoundary
Content-Disposition: form-data; name="logo1-file"
Content-Type: image/jpeg
--MyAppPartBoundary--
Adding videos
You can embed videos in OneNote pages using <iframe data-original-
src="https://..." /> in the input HTML.
iframe attributes
data-original-src
Example: data-original-src="https://www.youtube.com/watch?v=3Ztr44aKmQ8"
width
Optional. The width of the iframe that contains the video. Default is 480.
Example: width="300"
height
Optional. The height of the iframe that contains the video. Default is 360.
Example: height="300"
Example
In the input HTML of your request, include <iframe data-original-src="https://..." />
and specify the URL of the video for the data-original-src attribute.
HTML
--MyAppPartBoundary
Content-Disposition: form-data; name="Presentation"
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<title>A page with an embedded video</title>
</head>
<body>
<iframe data-original-src="https://www.youtube.com/watch?
v=3Ztr44aKmQ8" width="340" height="280"/>
</body>
</html>
--MyAppPartBoundary--
Adding files
You can add file attachments to OneNote pages using an object element in the input
HTML. If you're adding a PDF file, you can use an img element to render the PDF pages
as images.
Use <object .../> and send the file in a data part of a multipart request. Adds a file
attachment that displays a file icon on the OneNote page.
Use <img data-render-src="name:part-name" /> and send a PDF file in the data part of a
multipart request. Renders each PDF page as a separate image on the OneNote page.
File attributes
The object element requires the following attributes.
data-attachment
Example: data-attachment="filename.docx"
data
The name of the body part in the multipart request that contains the binary file data.
Microsoft Graph does not support passing a URL reference here.
Example: data="name:part-name"
type
The file media type, used to determine the file icon to use on the page, and which
application starts when the user activates the file on the device from OneNote.
Example: type="application/pdf"
File media types
Microsoft Graph uses predefined file-types icon for attached files, or a generic icon
when the API doesn't recognize the file type. The following table shows some common
file types that are recognized by the API.
application/pdf
application/vnd.openxmlformats-officedocument.wordprocessingml.document
application/vnd.openxmlformats-officedocument.presentationml.presentation
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
image/png
image/jpeg
image/gif
audio/wav
video/mp4
application/msword
application/mspowerpoint
application/excel
See limitations that apply when creating pages that contain media.
subtype" /> , where part-name is the unique identifier for the data part in your multipart
request that contains the binary file data. Just send the binary data, don't use Base64 or
otherwise encode it.
HTML
--MyAppPartBoundary
Content-Disposition: form-data; name="Presentation"
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<title>A page with an image file attachment</title>
</head>
<body>
<p>This is an image file attachment.</p>
<object data-attachment="Logo.jpg" data="name:logo1-file"
type="image/jpeg" />
</body>
</html>
--MyAppPartBoundary
Content-Disposition: form-data; name="logo1-file"
Content-Type: image/jpeg
--MyAppPartBoundary--
in your multipart request that contains the binary file data. Just send the binary data,
don't use Base64 or otherwise encode it.
HTML
--MyAppPartBoundary
Content-Disposition: form-data; name="Presentation"
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<title>A page with images of the pages of a PDF file</title>
</head>
<body>
<p>The pages of this PDF file render as images.</p>
<img data-render-src="name:file-part" alt="PDF file as images"
width="500"/>
</body>
</html>
--MyAppPartBoundary
Content-Disposition: form-data; name="file-part"
Content-Type: application/pdf
--MyAppPartBoundary--
Size limitations for POST pages requests
When sending image and file data, be aware of these limitations:
The Microsoft Graph REST API has a 4 MB request limit. Anything above this will
fail with the error message "request too large (413)".
The request limit of the underlying OneNote REST API is higher, but you cannot
access it via the Microsoft Graph API.
The total POST size limit is ~70 MB, including images, files, and other data. The
actual limit is affected by downstream encoding, so there's no fixed byte-count
limit. Requests that exceed the limit might produce unreliable results.
The limit for each data part is 25 MB, including the part headers. Data parts that
exceed the limit are rejected by Microsoft Graph.
The maximum number of images per page is 150. When using the
src="https://..." attribute, the API ignores img tags beyond the limit.
The maximum number of data parts is 6 per POST, including the required
Presentation part.
Each request can contain up to five img elements that use data-render-src and
one object elements that uses data-render-src. Additional image and file
references are ignored.
The maximum number of images in a single POST is 30, no matter which method
you use to send them to the API. Additional images are ignored. If you want to
capture a webpage that contains a lot of images, consider capturing the whole
page as a snapshot.
Complex HTML is probably best sent to the rendering engine via data-render-src,
rather than attempting to modify the HTML to fit into what Microsoft Graph can
accept. This is also true when your HTML includes tags that aren't supported
supported.
Accurate page rendering to preserve the layout and look of the page is probably
best done with the rendering engine via data-render-src.
Directly-editable text is often best done with inserting the HTML directly onto the
page. The rendered images are scanned by an optical character recognition (OCR)
system, but it's just not the same.
Snapshot-in-time for historical or archival purposes is usually best done with the
data-render-src method.
Marking-up a web page design for revisions is one place the data-render-src truly
shines. Using OneNote's inking capabilities, you can draw on the image to indicate
changes or call out important areas. Having the web page as an image makes that
a lot easier.
Very large images, or images in formats that OneNote doesn't directly accept, can
sometimes be thumbnailed and converted with the data-render-src attribute more
easily than by doing it in your own code. Even if the image is also available online,
embedding the data in your POST can sometimes make the captured page
available to OneNote users sooner, by reducing the total number of round-trips
needed to build the OneNote page.
Sometimes, the best way to determine which method will work best for your users is to
try it both ways as you develop your app.
Permissions
To create or update OneNote pages, you'll need to request appropriate permissions.
Choose the lowest level that your app needs to do its work.
For more information about permission scopes and how they work, see OneNote
permission scopes.
See also
Integrate with OneNote
OneNote Developer Blog
OneNote development questions on Microsoft Q&A
OneNote GitHub repos
Create absolute positioned elements on
OneNote pages
Article • 06/25/2022
The body of a OneNote page can contain multiple direct div , img , and object child
elements that can be positioned independently on the page.
Only div , img , and object elements can be absolute positioned elements.
Absolute positioned elements must be direct children of the body element. Any
direct children of the body that aren't absolute positioned div , img , or object
elements are rendered as static content inside the absolute positioned _default
div.
Absolute positioned elements are positioned at their specified top and left
coordinates, relative to the 0:0 starting position at the top, left corner of the page
above the title area.
If an absolute positioned element omits the top or left coordinate, the missing
coordinate is set to its default value: top:120px or left:48px . These default
coordinates specify a position just below the title area. Be aware that omitting
coordinates can result in elements that are stacked on top of each other.
Example
The following example contains a direct p child, an absolute positioned div, and a non-
absolute positioned div.
Input HTML
HTML
<body data-absolute-enabled="true">
<p>This content will appear in the _default div.</p>
<div style="position:absolute;top:175px;left:100px" data-id="div1">
<p>This content will appear in an absolute positioned div.</p>
</div>
<div>
<p>This content will also appear in the _default div.</p>
</div>
</body>
The API renders the non-absolute positioned div in the default div. Note that the nested
<div> tags are discarded because they do not define any semantic information (such as
data-id ).
Output HTML
HTML
Example
The following example creates a page that contains one absolute positioned div and
one absolute positioned image.
Input HTML
HTML
<html>
<head>
<title>Page Title</title>
</head>
<body data-absolute-enabled="true">
<div style="position:absolute;width:280px;top:120px;left:68px">
<p>Some text</p>
<img style="width:120px"
src="https://officeimg.vo.msecnd.net/files/018/949/ZA103278226.png" />
<div>
<p>More text inside a regular, nested div</p>
</div>
</div>
<img style="position:absolute;width:360px;top:350px;left:300px"
src="https://officeimg.vo.msecnd.net/files/018/949/ZA103278226.png" />
</body>
</html>
The OneNote API evaluates the input HTML and preserves all semantic content and any
structural information that is supported by OneNote. The resulting page renders as
shown in the following image (but without the visible borders for the div and image).
Notice the changes to the non-contributing, nested div from the input HTML. The API
preserves the div's content but discards the <div> tags because the div doesn't define
semantic information (such as data-id ).
For more information about how the OneNote API handles input and output HTML, see
Input and output HTML for OneNote pages.
HTML
<img style="position:absolute;top:140px;left:95px;width:480px;height:665px"
src="..." />
top div, img, The y-axis coordinate of the element's top border, in pixels only.
object Default is 120 pixels.
Example: top:140px
left div, img, The x-axis coordinate of the element's left border, in pixels only. Default
object is 48 pixels.
Example: left:95px
Example: width:480px
height img The height of the element, in pixels only. For divs, height is calculated
at runtime and any specified height value is ignored.
Example: height:665px
Other position attributes, such as z-index , are ignored. Absolute positioned images can
use either the data-render-src or src attribute.
Response information
The OneNote API returns the following information in the response.
Response Description
data
Success A 201 HTTP status code for a successful POST request, and a 204 HTTP status code
code for a successful PATCH request.
Errors Read Error codes for OneNote APIs in Microsoft Graph to learn about OneNote
errors that Microsoft Graph can return.
Permissions
To create or update OneNote pages, you'll need to request appropriate permissions.
Choose the lowest level of permissions that your app needs to do its work.
Notes.Create
Notes.ReadWrite
Notes.ReadWrite.All
For more information about permission scopes and how they work, see OneNote
permission scopes.
See also
Create OneNote pages
Update OneNote page content
Integrate with OneNote
OneNote Developer Blog
OneNote development questions on Microsoft Q&A
OneNote GitHub repos
Use OneNote API div tags to extract
data from captures
Article • 06/25/2022
Use the OneNote API to extract business card data from an image, or recipe and
product data from a URL.
Extraction attributes
To extract and transform data, simply include a div that specifies the source content,
extraction method, and fallback behavior in your create-page or update-page request.
The API renders extracted data on the page in an easy-to-read format.
HTML
<div
data-render-src="image-or-url"
data-render-method="extraction-method"
data-render-fallback="fallback-action">
</div>
data-render-src
The content source. This can be an image of a business card or an absolute URL from
many popular recipe or product websites. Required.
For best results when specifying a URL, use the canonical URL defined in the HTML of
the source webpage, if one is defined. For example, a canonical URL might be defined in
the source webpage like this:
data-render-method
The extraction method to run. Required.
Value Description
data-render-fallback
The fallback behavior if the extraction fails. Defaults to render if omitted.
Value Description
render Renders the source image or a snapshot of the recipe or product webpage.
This option is useful if you want to always include a snapshot of the business card or
webpage on the page in addition to any extracted content. Be sure to send a separate
img element in the request, as shown in the examples.
Name
Title
Organization
Phone and fax numbers
Mailing and physical addresses
Email addresses
Websites
A vCard (.VCF file) with the extracted contact information is also embedded in the page.
The vCard is a convenient way to get the contact information when retrieving page
HTML content.
HTML
<div
data-render-src="name:scanned-card-image"
data-render-method="extract.businesscard"
data-render-fallback="none">
</div>
<img src="name:scanned-card-image" />
HTML
<div
data-render-src="name:scanned-card-image"
data-render-method="extract.businesscard">
</div>
For business card extractions, the image is sent as a named part in a multipart request.
See Add images and files for examples that show how to send an image in a request.
Recipe extractions
The OneNote API tries to find and render the following information based on a recipe's
URL.
Hero image
Rating
Ingredients
Instructions
Prep, cook, and total times
Servings
The API is optimized for recipes from many popular sites such as Allrecipes.com,
FoodNetwork.com, and SeriousEats.com.
Specify the extract.recipe method and the none fallback. Also send an img element
with the data-render-src attribute set to the recipe URL. If the API is unable to extract
any content, it renders a snapshot of the recipe webpage only.
This scenario potentially provides the most information because the webpage may
include additional information, such as customer reviews and suggestions.
HTML
<div
data-render-src="https://allrecipes.com/recipe/guacamole/"
data-render-method="extract.recipe"
data-render-fallback="none">
</div>
<img data-render-src="https://allrecipes.com/recipe/guacamole/" />
Specify the extract.recipe method and use the default render fallback. If the API is
unable to extract any content, it renders a snapshot of the recipe webpage instead.
HTML
<div
data-render-src="https://www.foodnetwork.com/recipes/alton-brown/creme-
brulee-recipe.html"
data-render-method="extract.recipe">
</div>
HTML
<div
data-render-src="https://www.seriouseats.com/recipes/2014/09/diy-spicy-
kimchi-beef-instant-noodles-recipe.html"
data-render-method="extract.recipe"
data-render-fallback="none">
</div>
<a href="https://www.seriouseats.com/recipes/2014/09/diy-spicy-kimchi-beef-
instant-noodles-recipe.html">Recipe URL</a>
The API is optimized for products from many popular sites such as Amazon.com and
HomeDepot.com.
Specify the extract.product method and the none fallback. Also send an img element
with the data-render-src attribute set to the product URL. If the API is unable to extract
any content, it renders a snapshot of the product webpage only.
This scenario potentially provides the most information because the webpage may
include additional information, such as customer reviews and suggestions.
HTML
<div
data-render-src="https://www.amazon.com/Microsoft-Band-
Small/dp/B00P2T2WVO"
data-render-method="extract.product"
data-render-fallback="none">
</div>
<img data-render-src="https://www.amazon.com/Microsoft-Band-
Small/dp/B00P2T2WVO" />
HTML
<div
data-render-src="https://www.sears.com/craftsman-19hp-42-8221-turn-
tight-174-hydrostatic-yard-tractor/p-07120381000P"
data-render-method="extract.product">
</div>
Specify the extract.product method and the none fallback. Also send an a element
with the src attribute set to the product URL (or you can send any other information
you want to add to the page). If the API is unable to extract any content, only the page
link is rendered.
HTML
<div
data-render-src="https://www.homedepot.com/p/Active-Ventilation-5-Watt-
Solar-Powered-Exhaust-Attic-Fan-RBSF-8-WT/204203001"
data-render-method="extract.product"
data-render-fallback="none">
</div>
<a href="https://www.homedepot.com/p/Active-Ventilation-5-Watt-Solar-
Powered-Exhaust-Attic-Fan-RBSF-8-WT/204203001">Product URL</a>
Unknown content type extractions
If you don't know the content type (business card, recipe, or product) that you're
sending, you can use the unqualified extract method and let the OneNote API
automatically detect the type. You might want to do this if your app sends different
capture types.
7 Note
If you do know the content type that you're sending, you should use the
extract.businesscard , extract.recipe , or extract.product method. In some cases,
HTML
<div
data-render-src="some image or url"
data-render-method="extract">
</div>
Response information
Response Description
data
Success A 201 HTTP status code for a successful POST request, and a 204 HTTP status code
code for a successful PATCH request.
Errors Read Error codes for OneNote APIs in Microsoft Graph to learn about OneNote
errors that Microsoft Graph can return.
Permissions
To create or update OneNote pages, you'll need to request appropriate permissions.
Choose the lowest level of permissions that your app needs to do its work.
For more information about permission scopes and how they work, see Microsoft Graph
permissions reference.
See also
Create OneNote pages
Update OneNote page content
Add images and files
Integrate with OneNote
OneNote Developer Blog
OneNote development questions on Microsoft Q&A
OneNote GitHub repos
Use note tags on OneNote pages
Article • 12/20/2022
Use the data-tag attribute to add and update check boxes, stars, and other built-in note
tags on a OneNote page, as shown in the following image.
A data-tag value is composed of a shape, and sometimes a status (see all supported
values).
Property Description
status The status of check box note tags. This is used only to set check boxes as completed.
HTML
<p data-tag="important">...</p>
Separate multiple note tags with commas:
HTML
p
ul, ol, li (see more about note tags on lists)
img
h1 - h6
title
See Built-in note tags for a list of note tags that you can use with Microsoft Graph.
Adding or updating custom tags using Microsoft Graph is not supported.
Examples
Here's a simple to-do list with the first item completed.
HTML
For example, the following request marks the second to-do item as completed.
HTTP
PATCH https://graph.microsoft.com/v1.0/me/onenote/notebooks/pages/{page-
id}/content
Content-Type: application/json
Authorization: Bearer {token}
[
{
'target':'p:{33f8a242-7c33-4bb2-90c5-8425a68cc5bf}{40}',
'action':'replace',
'content':'<p data-tag="to-do:completed" data-id="spring">Plant peas
and spinach</p>'
}
]
The following request creates a page that contains all built-in note tags.
HTML
POST https://graph.microsoft.com/v1.0/me/onenote/notebooks/pages
Content-Type: text/html
Authorization: Bearer {token}
<!DOCTYPE html>
<html>
<head>
<title data-tag="to-do:completed">All built-in note tags</title>
</head>
<body>
<h1 data-tag="important">Paragraphs with built-in note tags</h1>
<p data-tag="to-do">to-do</p>
<p data-tag="important">important</p>
<p data-tag="question">question</p>
<p data-tag="definition">definition</p>
<p data-tag="highlight">highlight</p>
<p data-tag="contact">contact</p>
<p data-tag="address">address</p>
<p data-tag="phone-number">phone-number</p>
<p data-tag="web-site-to-visit">web-site-to-visit</p>
<p data-tag="idea">idea</p>
<p data-tag="password">password</p>
<p data-tag="critical">critical</p>
<p data-tag="project-a">project-a</p>
<p data-tag="project-b">project-b</p>
<p data-tag="remember-for-later">remember-for-later</p>
<p data-tag="movie-to-see">movie-to-see</p>
<p data-tag="book-to-read">book-to-read</p>
<p data-tag="music-to-listen-to">music-to-listen-to</p>
<p data-tag="source-for-article">source-for-article</p>
<p data-tag="remember-for-blog">remember-for-blog</p>
<p data-tag="discuss-with-person-a">discuss-with-person-a</p>
<p data-tag="discuss-with-person-b">discuss-with-person-b</p>
<p data-tag="discuss-with-manager">discuss-with-manager</p>
<p data-tag="send-in-email">send-in-email</p>
<p data-tag="schedule-meeting">schedule-meeting</p>
<p data-tag="call-back">call-back</p>
<p data-tag="to-do-priority-1">to-do-priority-1</p>
<p data-tag="to-do-priority-2">to-do-priority-2</p>
<p data-tag="client-request">client-request</p>
<h1 data-tag="important">Paragraphs with check boxes marked with
"completed" status</h1>
<p data-tag="to-do:completed">to-do:completed</p>
<p data-tag="discuss-with-person-a:completed">discuss-with-person-
a:completed</p>
<p data-tag="discuss-with-person-b:completed">discuss-with-person-
b:completed</p>
<p data-tag="discuss-with-manager:completed">discuss-with-
manager:completed</p>
<p data-tag="schedule-meeting:completed">schedule-meeting:completed</p>
<p data-tag="call-back:completed">call-back:completed</p>
<p data-tag="to-do-priority-1:completed">to-do-priority-1:completed</p>
<p data-tag="to-do-priority-2:completed">to-do-priority-2:completed</p>
<p data-tag="client-request:completed">client-request:completed</p>
<h1 data-tag="important">Multiple note tags</h1>
<p data-tag="project-a, client-request:completed">Two note tags:
project-a, client-request:completed</p>
<p data-tag="idea, send-in-email, question">Three note tags: idea,
send-in-email, question</p>
<h1 data-tag="important">Using note tags with other elements</h1>
<p><b>Note tag on a list item:</b></p>
<ul>
<li data-tag="to-do-priority-1:completed">Make a to-do list</li>
</ul>
<p><b>Note tag on an image:</b></p>
<img data-tag="source-for-article" src="https://placecorgi.com/200" />
<p><b>Note tag with embedded style:</b></p>
<p data-tag="important">Next time, <b>don't</b> forget to invite <span
style="background-color:yellow">Dan</span>.</p>
</body>
</html>
For more information about creating pages, see Create OneNote pages. For more about
updating pages, see Update OneNote pages.
Use p elements for to-do lists. They don't display a bullet or number, and they're
easier to update.
To create or update lists that display the same note tag for all list items, define
data-tag on the ul or ol . To update the entire list, you'll need to redefine data-
tag on the ul or ol .
To create or update lists that display a unique note tag for some or all list items,
define data-tag on li elements, and don't nest the li elements in a ul or ol . To
update the entire list, you'll need to remove the ul that's returned in the output
HTML and provide only the unnested li elements.
To update specific li elements, target the li elements individually and define the
data-tag on the li element. Any individually addressed li element can be
updated to display a unique note tag, no matter how the list was originally
defined.
The guidelines are based on the following rules that are applied by Microsoft
Graph:
Unique data-tag settings are honored for list items under the following
conditions:
In output HTML, all data-tag list settings are defined on span elements on the list
items.
The following code shows how some of these rules are applied. The input HTML creates
two lists with note tags. The output HTML is what's returned for the lists when you
retrieve page content.
Input HTML
HTML
<!--To display the same note tag on all list items, define note tags on the
ul or ol.-->
<ul data-tag="project-a" data-id="agenda">
<li>An item with a Project A note tag</li>
<li>An item with a Project A note tag</li>
</ul>
<!--To display unique note tags on list items, don't nest li elements in a
ul or ol.-->
<li data-tag="idea" data-id="my-idea">An item with an Idea note tag</li>
<li data-tag="question" data-id="my-question">An item with a Question note
tag</li>
Output HTML
HTML
<ul>
<li><span data-tag="project-a">An item with a Project A note tag</span>
</li>
<li><span data-tag="project-a">An item with a Project A note tag</span>
</li>
</ul>
<br />
<ul>
<li style="..."><span data-tag="idea">An item with an Idea note tag</span>
</li>
<li style="..."><span data-tag="question">An item with a Question note
tag</span></li>
</ul>
GET ../api/v1.0/pages/{page-id}/content
A data-tag attribute in the output HTML always includes a shape value, and it only
includes a status if it represents a check box note tag that's set to completed. The
following examples show the input HTML used to create some note tags and the output
HTML that's returned.
Input HTML
HTML
<h1>Status meeting</h1>
<p data-tag="important">Next week's meeting has been moved to
<b>Wednesday</b>.</p>
<p data-tag="question">What are the exact dates for the conference?</p>
<p>Upcoming training opportunities. See Katie for more info.</p>
<p data-tag="project-a">Around the room updates.</p>
<ul data-tag="critical">
<li>Design handouts</li>
<li>Plan keynote</li>
</ul>
Output HTML
HTML
Note that the data-tag attribute defined at the list level is pushed to its list items. For
more information about using note tags with lists, see Note tags on lists.
7 Note
In the output HTML, the definition and remember-for-later note tags are both
returned as data-tag="remember-for-later" . The title element doesn't return any
note tag information.
The values you can assign to the data-tag attribute are shown in the following list.
Custom tags are not supported.
shape[:status]
to-do
to-do:completed
important
question
definition
highlight
contact
address
phone-number
web-site-to-visit
idea
password
critical
project-a
project-b
remember-for-later
movie-to-see
book-to-read
music-to-listen-to
source-for-article
remember-for-blog
discuss-with-person-a
discuss-with-person-a:completed
discuss-with-person-b
discuss-with-person-b:completed
discuss-with-manager
discuss-with-manager:completed
send-in-email
schedule-meeting
schedule-meeting:completed
call-back
call-back:completed
to-do-priority-1
to-do-priority-1:completed
to-do-priority-2
to-do-priority-2:completed
client-request
client-request:completed
Response information
Microsoft Graph returns the following information in the response.
Response Description
data
Success A 201 HTTP status code for a successful POST request, and a 204 HTTP status code
code for a successful PATCH request.
Errors Read Error codes for OneNote APIs in Microsoft Graph to learn about OneNote
errors that Microsoft Graph can return.
Permissions
To create or update OneNote pages, you'll need to request appropriate permissions.
Choose the lowest level of permissions that your app needs to do its work.
For more information about permission scopes and how they work, see OneNote
permission scopes.
See also
Create OneNote pages
Update OneNote page content
Integrate with OneNote
OneNote Developer Blog
OneNote development questions on Microsoft Q&A
OneNote GitHub repos
Input and output HTML on OneNote
pages
Article • 06/25/2022
The HTML that defines the page content and structure when you create or update a
OneNote page is called input HTML.
The HTML that's returned when you get page content is called output HTML. Output
HTML won't be the same as input HTML.
The OneNote APIs in Microsoft Graph preserve the semantic content and basic structure
of the input HTML, but convert it to a set of supported HTML elements and CSS
properties. The APIs also add custom attributes that support OneNote features.
This article describes the principal elements and attributes of input and output HTML. It
can be helpful to understand input HTML when you're creating or updating page
content, and output HTML when you're parsing returned page content.
body element
The HTML content in the page body represents the page content and structure,
including image and file resources. The body element can contain the following
attributes in the input and output HTML.
Input attributes
Input Description
attribute
data- Indicates whether the input body supports absolute positioned elements.
absolute-
enabled
style The CSS style properties of the body. In the output HTML, input settings might be
returned inline on appropriate child elements.
Output attributes
data-absolute- Indicates whether the body supports absolute positioned elements. Always
enabled true in output HTML.
div elements
Div elements contain text, images, and other content. A div element can contain the
following attributes in the input and output HTML.
Input attributes
Input Description
attribute
data- The fallback action if the extraction fails: render (default) or none
render-
fallback
style The position, size, font, and color properties for the div:
position (absolute only), left, top, and width (height is auto-configured for
divs)
Used to create an absolute positioned div, only if the div is a direct child of
the body when the body sets data-absolute-enabled="true" .
The OneNote APIs in Microsoft Graph wrap all body content in at least one div. The API
creates a default div (attributed with data-id="_default" ) to contain the body content if:
The input body element's data-absolute-enabled attribute is omitted or set to
false. In this case, all body content is put in the default div.
The input body element's data-absolute-enabled attribute is true, but the input
HTML contains direct children that aren't absolute positioned div, img, or object
elements. In this case, direct children that aren't absolute positioned div, img, or
object elements are put in the default div.
Output attributes
Output Description
attribute
id A unique, generated ID for the element. Returned by GET requests to a page's content
endpoint when the includeIDs=true query option is used.
Non-contributing divs
When a div element in the input HTML does not contribute to the page structure or
carry information that OneNote uses, the API moves the div's content into the parent or
default div. This is illustrated in the following examples.
Input HTML
Contains a non-contributing, nested div.
HTML
<html>
<head>
<title>Page Title</title>
</head>
<body>
<div>
<p>Some text</p>
<div>
<p>More text inside a div that doesn't define page
structure</p>
</div>
</div>
</body>
</html>
Output HTML
7 Note
The div's content was moved to the parent div and the nested <div> tags have
been removed. The div would have been preserved if it defined any semantic
information, such as a data-id (example: <div data-id="keep-me"> ).
HTML
img elements
Images on OneNote pages are represented by img elements. An img element can
contain the following attributes in the input and output HTML.
Input attributes
Input Description
attribute
This method is useful when the webpage is more complex than the OneNote page
can faithfully render, or when the page requires login credentials.
style The position and size properties for the image: position (absolute only), left, top,
width, and height.
Position properties are used to create an absolute positioned image, only if the image
is a direct child of the body when the body sets data-absolute-enabled="true" .
In the output HTML, the image size is returned separately in width and height
attributes.
width, The width or height of the image, in pixels but without the px. Example: width="400"
height
7 Note
The OneNote APIs automatically detect the input image type, and return it as the
data-fullres-src-type in the output HTML. The API also returns the image type of
the optimized image in data-src-type.
Output attributes
Output Description
attribute
data-fullres- The endpoint for the version of the image resource that was originally embedded
src in the page.
data-fullres- The media type of the data-fullres-src resource, for example: image/png or
src-type image/jpeg .
data- The source type: printout for PDF files or splitimage for all others. Applies only to
options split images created with the data-render-src attribute.
data-render- The original source URL of the image, if the source image is from the public
original-src internet and was created with the data-render-src attribute.
data-src- The media type of the src resource, for example: image/png or image/jpeg .
type
src The endpoint for the version of the image resource that has been optimized for
web browsers and mobile and tablet form factors.
HTML
<img
src="https://graph.microsoft.com/v1.0/me/onenote/resources/{image-
id}/$value"
data-src-type="image/png"
data-fullres-
src="https://graph.microsoft.com/v1.0/me/onenote/resources/{image-
id}/$value"
data-fullres-src-type="image/png" ... />
The following examples show the information an img element might contain in the
output HTML.
HTML
<img
src="{web-ready-image-resource-url}/$value"
data-src-type="image/{type}"
data-fullres-src="{high-resolution-image-resource-url}/$value"
data-fullres-src-type="image/{type}"
[data-render-original-src="{original-source-url-or-named-part}"]
[data-id="{image-id}"]
[alt="supplied alt text"]
[width="345"] [height="180"]
[style="..."] />
HTML
<img
src="{web-ready-image-resource-url}/$value"
data-src-type="image/{type}"
data-fullres-src="{high-resolution-image-resource-url}/$value"
data-fullres-src-type="image/{type}"
data-render-original-src="{original-source-url-or-named-part}"
[data-id="{image-id}"]
[data-index="{index-of-split-image}"]
[data-options="{printout-or-splitimage}"]
[alt="supplied alt text"]
[width="1024"] [height="1900"]
[style="..."] />
Split images
Images that are created using the data-render-src attribute (from a webpage URL or a
named part) might be split into multiple component images for performance and
rendering reasons. Component images are all assigned the same data-id value. Each
component image has a zero-based data-index attribute that defines the original
vertical layout.
HTML
<div data-id="multi-component-image"
style="position:absolute;left:48px;top:120px;width:624px">
<img
src="{image-resource0-url}/$value"
data-src-type="image/{type}"
data-fullres-src="{image-resource0-url}/$value"
data-fullres-src-type="image/{type}"
data-index="0"
data-render-original-src="{original-source-url-or-named-part}"
data-id="{same-image-id}" ... />
<img
src="{image-resource1-url}/$value"
data-src-type="image/{type}"
data-fullres-src="{image-resource1-url}/$value"
data-fullres-src-type="image/{type}"
data-index="1"
data-render-original-src="{original-source-url-or-named-part}"
data-id="{same-image-id}" ... />
<img
src="{image-resource2-url}/$value"
data-src-type="image/{type}"
data-fullres-src="{image-resource2-url}/$value"
data-fullres-src-type="image/{type}"
data-index="2"
data-render-original-src=""{original-source-url-or-named-part}"
data-id="{same-image-id}" ... />
</div>
Because users can move the images on the page, the returned indexes might be out of
order. Ordering should be in top to bottom y-order, and then left to right x-order if
there are y-order conflicts.
iframe elements
OneNote pages can contain embedded videos represented by iframe elements.
7 Note
Input attributes
data-original- Required. The URL of the video source. See the list of supported video sources.
src
Example: data-original-src="https://www.youtube.com/watch?v=3Ztr44aKmQ8"
width, height The width or height of the iframe, in pixels. Example: width=300
Output attributes
Example: width=300
HTML
<iframe
width="340" height="280"
data-original-src="https://www.youtube.com/watch?v=3Ztr44aKmQ8"
src="https://www.youtube.com/embed/3Ztr44aKmQ8?
feature=oembed&autoplay=true" />
object elements
OneNote pages can contain file attachments represented by object elements. An object
element can contain the following attributes in the input and output HTML.
7 Note
The OneNote APIs can also render file content as images in a page when the file is
sent as an image and uses the data-render-src attribute. Example: <img data-
render-src="name:part-name" ... />
Input attributes
Input Description
attribute
data Required. The name of the part that represents the file in the multipart request.
style The position and size properties for the object: position (absolute only), left, top,
and width.
Used to create an absolute positioned object, only if the object is a direct child of
the body when the body sets data-absolute-enabled="true" .
type Required.
The standard media file type. Known file types display the icon associated with the
file type on the OneNote page. Unknown file types display a generic file icon.
Output attributes
Output Description
attribute
HTML
<object
data="https://graph.microsoft.com/v1.0/me/onenote/resources/{file-
id}/$value"
data-attachment="fileName.pdf"
type="application/pdf"
[style="..."] />
Input attributes
Output attributes
Output Description
attribute
id A unique, generated ID for the element. Returned by GET requests to a page's content
endpoint when the includeIDs=true query option is used.
style The CSS style properties of the element. In the output HTML, these values may be
returned inline on appropriate child elements or on span elements.
The following examples show input HTML that uses different ways to define styles on
text containers and the output HTML that's returned.
Input HTML with styles defined using inline character styles, in the
start tag, and within a span element.
HTML
Output HTML with the <i> character style and the font settings in
the <p> start tag returned as inline CSS styles on span elements.
HTML
<h1 style="font-size:16pt;color:#1e4e79;margin-top:11pt;margin-
bottom:11pt">Heading <span style="font-style:italic">One</span> text</h1>
<p style="text-align:center"><span style="font-family:Courier;font-
size:8pt;color:green">Some text</span></p>
<p>Some <span style="font-family:Segoe UI Black;font-
size:12pt;color:red">more</span> text</p>
Lists
Lists are represented as ol or ul elements that contain list items represented as li
elements.
Lists and list items can contain the following attributes in the input and output HTML.
Input attributes
style The list-style-type and the CSS style properties for the list or list item.
Output attributes
Output Description
attribute
id A unique, generated ID for the element. Returned by GET requests to a page's content
endpoint when the includeIDs=true query option is used.
style The list-style-type and CSS style properties of the element. In the output HTML, list-
level settings are returned on list items. Default properties are not returned.
List styles
The OneNote APIs in Microsoft Graph support the following list styles:
none none
lower-alpha circle
lower-roman square
upper-alpha
upper-roman
You can apply global styles for a list on the ol or ul element in the input HTML, but
styles are returned on the li elements.
HTML
<ol style="list-style-type:upper-roman;color:blue">
<li style="font-weight:bold">Jacksonville</li>
<li style="text-decoration:line-through">Orlando</li>
<li style="font-family:Courier">Naples</li>
</ol>
This is the output HTML. Notice that styles are returned inline on the individual li or
span elements.
HTML
<ol>
<li style="list-style-type:upper-roman"><span style="color:blue;font-
weight:bold">Jacksonville</span></li>
<li style="list-style-type:upper-roman"><span style="color:blue;text-
decoration:line-through">Orlando</span></li>
<li style="list-style-type:upper-roman"><span style="font-
family:Courier;color:blue">Naples</span></li>
</ol>
HTML
<ul style="font-style:italic">
<li style="list-style-type:square">square style</li>
<li style="list-style-type:circle">circle style</li>
<li style="list-style-type:disc">disc style (default)</li>
</ul>
This is the output HTML. Notice that styles are returned inline on the individual li or
span elements.
HTML
<ul>
<li style="list-style-type:square"><span style="font-
style:italic">square style</span></li>
<li style="list-style-type:circle"><span style="font-
style:italic">circle style</span></li>
<li><span style="font-style:italic">disc style (default)</span></li>
</ul>
Tables
Tables are represented as table elements that can contain tr and td elements. Nested
tables are supported.
Tables can contain the following attributes in the input and output HTML. The OneNote
APIs do not support rowspan or colspan attributes.
Input attributes
Input attribute Description
7 Note
The use of the border property in the style attribute of a table is not supported in
input html.
Output attributes
Output Description
attribute
id A unique, generated ID for the element. Returned by GET requests to a page's content
endpoint when the includeIDs=true query option is used.
The following examples show input HTML that uses different ways to define styles on
tables and the output HTML that's returned.
HTML
<table border="1"; Width="500"; bgcolor = "green">
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
<tr style="background-color:blue">
<td style="text-align:right;background-color:red">Left</td>
<td style="text-align:center">Middle</td>
<td>Right</td>
</tr>
</table>
HTML
<table style="border:0px">
<tr>
<td style="background-color:green;width:166;border:0px">Cell 1</td>
<td style="background-color:green;width:166;border:0px">Cell 2</td>
<td style="background-color:green;width:166;border:0px">Cell 3</td>
</tr>
<tr>
<td style="background-color:red;width:166;border:0px;text-
align:right">Left</td>
<td style="background-color:blue;width:166;border:0px;text-
align:center">Middle</td>
<td style="background-color:blue;width:166;border:0px">Right</td>
</tr>
</table>
Styles
OneNote APIs in Microsoft Graph support the following inline CSS style properties for
elements in the page body, such as body, div, p, li, and span.
Property Example
The APIs accept font size in pt or px, but converts px to pt. Decimal values are
rounded to the nearest n.0pt or n.5pt.
strike- style="text-decoration:line-through"
through
<cite>
HTML
<html lang="en-US">
<head>
<title>Sample Study Notes</title>
<meta name="created" content="2015-01-01T01:01"/>
</head>
<body>
<h1>Aurora Borealis</h1>
<p>Dancing lights in the sky. Also called <i>Northern Lights</i>.
Caused by solar radiation.</p>
<br />
<p><b>Intersting facts</b></p>
<table>
<tr>
<td>Neil Armstrong</td>
<td>Commander</td>
</tr>
<tr>
<td>Buzz Aldrin</td>
<td>LM Pilot</td>
</tr>
<tr>
<td>Michael Collins</td>
<td>Command Module Pilot</td>
</tr>
</table>
<img alt="Apollo 11 commemorative stamp."
src="https://upload.wikimedia.org/wikipedia/commons/a/a4/First_Man_on_Moon_1
969_Issue-10c.jpg" width="400"/>
<p>References:</p>
<p><a
href="https://en.wikipedia.org/wiki/Apollo_11">https://en.wikipedia.org/wiki
/Apollo_11</a></p>
<p><a
href="https://www.nasa.gov/mission_pages/apollo/missions/apollo11.html">http
s://www.nasa.gov/mission_pages/apollo/missions/apollo11.html</a></p>
</body>
</html>
This is the output HTML that Microsoft Graph returns when you get page content.
7 Note
When you create a page or get page metadata, the API returns the content
endpoint URL of the page in the contentUrl property.
HTML
See also
Get OneNote content and structure
Create OneNote pages
Update OneNote page content
Add images, videos, and files
Best practices for working with the
OneNote API in Microsoft Graph
Article • 06/25/2022
This article provides recommendations for working with the OneNote APIs in Microsoft
Graph. These recommendations are based on answers to common questions on
Microsoft Q&A and Twitter.
HTTP
GET ~/notebooks/{id}/sections
This retrieves all the properties of the sections. However, you might not need all
properties. You can use the $select query parameter to return just the properties that
you want, as shown in the following example.
HTTP
GET ~/notebooks/{id}/sections?$select=id,displayName
While this will work (with a few extra sequential roundtrips to the service), a better
approach is to use the $expand query parameter.
HTTP
GET ~/notebooks?$expand=sections,sectionGroups($expand=sections)
This will yield the same results in one network roundtrip, with better performance.
For example, instead of using this call (this API is paged, so you won't be able to fetch
the pages all at once):
HTTP
GET ~/pages
It is better to use the following call several times (especially if you don't need all
sections):
HTTP
GET ~/sections/{id}/pages
HTTP
GET ~/sections/{id}/pages?
$select=id,title,createdDateTime&$orderby=createdDateTime
Branding guidelines for OneNote API
developers
Article • 06/25/2022
Follow the guidance in this article to best integrate the OneNote brand within your
product and satisfy OneNote branding requirements.
Downloadable logos
You can download the logos shown in this article and a PDF copy of these guidelines
from our Branding guidelines for OneNote API developers download page.
Logo variations
Icon symbol
Certain environments, such as on small devices, don't provide enough room for the
entire logo lockup. In those cases, the icon symbol alone may be used in an app or in
digital marketing. When used in an app, use the icon symbol alone only when you need
an icon or favicon to represent OneNote.
Clear space
Treat the logo with respect and give it room to breathe. A minimum clear space
equivalent to the height of the symbol must surround the logo.
Minimum size
The logo should be at least 16 pixels high when it appears on-screen and at least 5 mm
(0.2 inches) high when it appears in print.
Screen: 16 pixels
In color-limited environments and one-color designs, the logo can appear in black.
However, the logo should never appear in gray.
Logo don’ts
Don’t place the logo or icon on a color background
See the following table for details about how to refer to OneNote in various contexts.
Context Usage
Context Usage
App names To avoid confusing consumers within the app stores, we prefer that OneNote
not be included in the name of your app. If it’s determined that OneNote must
be used in the app name, OneNote must be modified by a preposition (for
example, for OneNote or with OneNote).
Under no circumstances can the name of your app begin with OneNote.
Publisher The publisher’s name may not include a reference to OneNote. The publisher’s
names name may not infringe upon any Microsoft trademarks.
General The first mention in a communication should use the full name: Microsoft
marketing OneNote.
(including app
descriptions) Subsequent references in the communication can use the short name: OneNote.
Examples
Applications
Advertising
Website
Packaging
If you have any questions about these guidelines or are creating new communications
using the brand assets shown here, contact us at @onenotedev .
See also
Branding guidelines for OneNote API developers (download page)
Integrate with OneNote
OneNote Developer Blog
OneNote development questions on Microsoft Q&A
OneNote GitHub repos
Error codes for the OneNote API in
Microsoft Graph
Article • 07/07/2022
This article describes error codes that are returned by the OneNote API in Microsoft
Graph whenever a request that is sent through the API fails.
JSON
{
"error":{
"code":"10002",
"message":"The service is currently unavailable. Please try again
later.",
"innerError": {
"requestId": "request-id",
"date": "date-time"
}
}
}
For more information about Microsoft Graph errors, see Microsoft Graph error
responses and resource types.
10001
An unexpected error occurred and the request failed.
10002
The service is not currently available.
10003
The current user's account has exceeded the maximum number of active requests. Your
app will have to repeat the request.
10004
The service can't create a page in the requested section because that section is
protected by a password.
10005
The request contains more than the maximum number of image tags in which the data-
render-src attribute contains a PDF. See Add images and files.
10006
The OneNote API was unable to create a page in the specified section because that
section is corrupt.
10007
The server is too busy to handle the incoming request at this moment. Please try again
later.
10008
One or more of the document libraries on the user or group's OneDrive contains more
than 5000 OneNote items (notebooks, sections, section groups), and cannot be queried
using the API. Please make sure that none of the user or group's document libraries
contains more than 5000 OneNote items. See the OneNote Dev blog for mitigation
steps.
10012
Unable to create or update the entity because the library that contains the notebook
requires items to be checked out before they can be edited. For more information, see
Set up a library to require check-out of files .
Either remove the check-out requirement from the library, or move the notebook.
10013
One or more of the document libraries on the user or group's OneDrive contains more
than 20,000 items and cannot be indexed for querying using the API. Please make sure
that none of the user or group's document libraries contains more than 20,000 items.
See the OneNote Dev blog for mitigation steps.
10014
Azure Key Vault is too busy to handle the incoming request at this moment. Please try
again later.
10015
SharePoint is currently unavailable. Please try again later.
10016
Document library on the user or group’s OneDrive exceeded unique security scopes
threshold limit. The maximum number of unique security scopes set for a library cannot
exceed 50,000.
10017
Bad Request.
19999
The request failed because an undetermined error occurred.
20001
The request is missing the required "Presentation" part. Exactly one is required.
20002
The request contains two or more "Presentation" parts. Exactly one is required.
20003
The content type of the "Presentation" part can be only text/HTML or
application/XHTML+XML.
20004
The "Presentation" part HTML contains an image tag with both the src and the data-
render-src properties set. The API will ignore the src property and use the data-render-
src property.
20005
The request URI is too long. The maximum size of the URI (including all parameters and
data) is 16 KB or 16,384 characters.
20006
The "Presentation" part HTML contains an image tag with neither the src nor the data-
render-src properties set. The API will ignore the image tag.
20007
The "Presentation" part HTML contains a created date/time string that does not match
any of the allowed formats.
20008
The size of the request is too large.
20009
The request contains parts with duplicate names. Part names must be unique.
20010
The Content-Disposition header was not supplied for the specified content type.
20011
The request contains a malformed multipart payload. Problems could include missing
blank lines, a missing last line, incorrectly formatted part separators, and so on. If you're
building the multipart message by hand, carefully check the logic, or consider using a
third-party library.
20012
The request doesn't supply a content type for the specified part.
20013
The request doesn't supply Content-Type and Content-Disposition headers for the
specified part.
20014
The length of a part in the multipart message exceeds the maximum size of 25 MB.
20015
The count of parts in the multipart message exceeds the limit of 500.
20016
The length of the multipart message exceeds the limit of 75 MB.
20017
The email MIME was malformed.
20018
The meeting MIME or ICal was malformed.
20019
No ICal was found.
20020
Encountered malformed Json in request body.
20100
Something is wrong with the syntax of your request.
20101
The property that you requested doesn't exist.
20102
You requested a resource that doesn't exist.
20103
The expand query is not supported for this request. See Supported OData query string
options.
20104
The pagelevel query option is supported only when querying for the pages collection in
a section or for a specific page. For example:
HTTP
GET ../sections/{id}/pages?pagelevel=true
GET ../pages/{id}?pagelevel=true
20106
Your request contains a query operator that is not supported.
20108
Your request contains unsupported OData query parameters.
20109
The payload in the PATCH request is not constructed correctly.
20110
Page create requests with data parts require the content to be multipart, with a
"Presentation" part.
20111
Your request uses an OData feature that isn't supported.
20112
Your request contains an invalid ID for the target notebook, section group, section, or
page entity.
20113
The resource specified in the request has been deleted.
20115
The name contains invalid characters. A notebook name cannot contain any of the
following characters: ? * \ / : < > | ' "
20117
An item with the name you specified already exists in the location that you specified.
20119
The HTML in the "Presentation" part contains a data-attachment attribute that either
doesn't have a valid format or includes one or more of these invalid characters for a file
name: \ / : * ? < > | " . The request substituted the value indicated in the error
message.
20120
Your request specifies a PATCH target that can't be located.
20121
Your request contains an invalid PATCH argument. See Update page content.
20122
Your request specifies an unsupported PATCH action. See Update page content.
20123
The PATCH request is unable to alter the specified page.
20124
Your multipart PATCH request doesn't include a "commands" part with the PATCH action
JSON structure. See Update page content.
20125
Your PATCH request contains no actions. See Update page content.
20126
The message body contains either incorrectly formatted JSON or fields that are not
supported for this operation.
20127
Your request specifies the name of an unknown property.
20128
Your request contains an OData syntax error at the position indicated in the message.
20129
Your request contains a top query string option whose value is too high. For page
queries, the maximum value is 100, and the default value is 20.
20130
Your request contains a URI that points to an HTTP resource that can't be found.
20131
Your request contains an invalid value for Content-Type. Use the value indicated in the
message.
20132
Your request contains invalid content. Common causes for this are a missing Content-
Type request header and/or no content in the body of the request.
20133
Your request specifies a PATCH target that is not supported. See Update page content.
20134
Your request specifies an invalid element as the target of the PATCH action. If the target
uses the data-id identifier, make sure it's prefixed with a # symbol. See Update page
content.
20135
Your request specifies an entity type that is not supported for the PATCH operation. See
Update page content.
20136
Your request contains an invalid or missing data-render-src or data-render-method
attribute. See Extract data from captures.
20137
The target page does not support PATCH requests.
20138
The target element type in your PATCH request doesn't support the append action. See
Update page content.
20139
Your request contains an invalid data-tag attribute value. See Use note tags.
20140
Your request contains an invalid data-tag status value. Check box note tags can have a
completed status.
Example:
HTML
20141
The target in your PATCH request doesn't support the specified action. See Update page
content.
20142
Your request contains an expand expression for a parent of child entities or a child of
parent entities, which is not supported. See Supported OData query string options.
20143
The OData query is invalid.
20144
Your request contains an expand expression for a non-navigation property. Only
navigation properties can be expanded.
20145
The select or expand expression in your request contains an invalid term.
20146
The style="position:absolute" attribute is specified on an element, but the body
element does not specify data-absolute-enabled="true" , which is required to support
positioning. All position settings will be ignored. See Create absolute positioned
elements.
20147
The style="position:absolute" attribute is specified on an element that is not a direct
child of the body element, which is not supported. If the element is a div, img, or object,
make it a direct child of the body; otherwise the position settings will be ignored and its
content will render inside an absolute positioned div. See Create absolute positioned
elements.
20148
The style="position:absolute" attribute is specified on an element type that does not
support it. Only div, img, and object elements that are direct children of the page body
support positioning. See Create absolute positioned elements.
20149
Your request specifies a target element that cannot be found.
20150
The request is not valid for this authentication type. Use the ../me/onenote/ path
instead.
20151
The request is not valid for this authentication type. Use the
../me/onenote/section/{id}/pages endpoint to create a page in a specific section.
20152
There is no name value specified for the entity. The name must be defined, and it cannot
contain whitespaces only.
20153
The entity name contains invalid characters. The name cannot contain the following
characters: ? * \ / : < > | & # " % ~
20154
The entity name cannot start with a space.
20155
The entity name is too long. Notebook names have a 128-character limit. Other entity
names have a 50-character limit.
20156
The specified ID for the destination resource does not exist.
20157
The specified ID for the destination entity is invalid.
20158
Unable to get metadata for the site URL specified in the request. Check the format of
the supplied URL. Supported formats include https://domain.sharepoint.com/site-a
and https://domain.com/sites/site-a .
20160
Unable to find an Office 365 unified group that has the specified ID.
20161
The context does not specify a valid user ID. One common error is that PUID/CID was
passed in as a long instead of a hex.
20166
The application has issued too many requests on behalf of a user in a short period of
time. To help ensure that the OneNote API remains stable and responsive, the API
returns a 429 status code and this error when it detects that an application is using too
many resources.
20168
The video source specified in the request is not supported. See Supported video sites
for the current list.
30101
The user account has exceeded its OneDrive quota. See OneDrive .
30102
Nothing more can be added to the requested section because it has reached its
maximum size.
30103
Resource consumption is too high for the request. Either the target user account has a
large dataset, or the service is receiving a high number of concurrent requests to the
same site (for example, the user's personal site or a team site).
30104
The user account has been suspended.
30105
The user's personal OneDrive for Business site is not provisioned, which is required to
access notebooks. The OneNote service will provision the site now. This process may
take several minutes.
30106
OneDrive for Business is being provisioned for the user.
30108
The user's personal OneDrive for Business could not be retrieved. The following table
lists some possible causes.
Cause Resolution
The user's personal site The user should open OneDrive for Business and follow any
has not been provisioned. instructions to provision the site. If this fails, they should contact
their Microsoft 365 tenant administrator.
The user does not have a The user should contact their Microsoft 365 tenant administrator.
valid OneDrive for
Business license.
30109
Some users in the request do not exist.
30110
Student Information Services has not been registered for this tenant.
30111
There is a generic error with Student Information Services.
30112
Multiple users affected by the request had the same username.
30113
The notebook is not configured to allow invites.
30114
There is a required parameter missing.
40001
The request doesn't contain a valid OAuth token. See Notes permissions.
40002
The user doesn't have permission to write to the requested location.
40003
The user doesn't have permission to access the requested resource.
40004
The OAuth token doesn't have the required scopes to perform the requested action. See
Notes permissions.
40006
The OAuth token doesn't have the required scopes to perform the requested action.
Specifically the edit permission. See Notes permissions.
40007
The user does not have permissions to access this resource.
40008
Access is Forbidden for this resource.
40009
The container is already in use by another resource.
See also
Microsoft Graph error responses and resource types
OneNote API reference
Enabling human-centric notification
experiences using Microsoft Graph
notifications (deprecated)
Article • 06/25/2022
) Important
The Microsoft Graph notifications API is deprecated and stopped returning data in
January 2022. For an alternative notification experience, see Microsoft Azure
Notification Hubs. For more information, see the blog post Retiring Microsoft
Graph notifications API (beta) .
Notifications are one of the most effective ways to reengage with your application users.
A great notification experience can help open a near real-time communication channel
between you and your users, and that in turn can increase app engagement at the right
time, make users more productive, and alert them to important events or required
actions.
https://www.youtube-nocookie.com/embed/cmpPFhrS8ZA
Today, users can access your applications and services via a wide variety of platforms
and form factors. This mix of devices requires that you understand and support
multiplatform notification systems, map users to endpoints, and maintain notification
state across devices.
Most other notification systems eliminate the need to understand and target platform-
specific push notification systems, but are still designed to target each device. The
Microsoft Graph notifications platform provides a human-centric approach that gives
you the ability to target your users across any and all device endpoints.
Why integrate with Microsoft Graph
notifications?
The Microsoft Graph notifications platform provides a user-centric notification offering
that brings five key benefits to your applications.
API reference
Looking for the API reference for this service?
) Important
The Microsoft Graph notifications API is deprecated and stopped returning data in
January 2022. For an alternative notification experience, see Microsoft Azure
Notification Hubs. For more information, see the blog post Retiring Microsoft
Graph notifications API (beta) .
You can integrate your apps with Microsoft Graph notifications with a few simple steps,
as shown in the following diagram.
4. Integrate the new notifications client SDK into your Windows, iOS, Android, or
web clients to receive and manage notifications.
7 Note
) Important
The Microsoft Graph notifications API is deprecated and stopped returning data in
January 2022. For an alternative notification experience, see Microsoft Azure
Notification Hubs. For more information, see the blog post Retiring Microsoft
Graph notifications API (beta) .
In order for your application service to integrate with Microsoft Graph notifications, you
need to register your app with the Microsoft identity platform to support Microsoft
accounts or work or school accounts, and declare the API permissions that are required.
For information about how to register your apps, see Register an application with the
Microsoft identity platform. When you register your app, be sure to keep the application
ID/client ID somewhere handy. You'll need this ID later when you register your
application for cross-device experiences in Partner Center for Windows, Android, or
iOS clients.
7 Note
If you don't already have a Microsoft account and would like to use one, go to
the Microsoft account page. If you're writing an app that needs to use Azure AD
v1.0 as an authentication and identity framework for work or school accounts,
see Azure Active Directory Authentication Libraries. If you’re interested in learning
about or using the new converged Microsoft identity platform (v2.0), see
Comparing the Microsoft identity platform endpoint and Azure AD v1.0
endpoint.
7 Note
If you opt to generate a new client secret, be sure to copy and keep it in a safe
place. You won’t be able to access it again after you leave the portal.
API permissions
You'll need to add additional permissions in order to use Microsoft Graph notifications.
Choose Add a permission, and under Microsoft APIs, select Microsoft Graph, and then
select Delegated permissions.
Add the following permissions:
Next steps
Learn more about permissions and consent or see the Microsoft Graph permissions
reference.
Now that you’ve registered your app, visit Partner Center to set up your application
and target your corresponding app platforms (Windows, iOS, or Android) for
notifications sent via Microsoft Graph. For details, see Onboarding to cross-device
experiences.
7 Note
If you're only targeting web endpoints, you can skip Partner Center registration and
learn how to set up your app service to send notifications.
Onboarding to cross-device experiences
for Microsoft Graph notifications
(deprecated)
Article • 06/25/2022
) Important
The Microsoft Graph notifications API is deprecated and stopped returning data in
January 2022. For an alternative notification experience, see Microsoft Azure
Notification Hubs. For more information, see the blog post Retiring Microsoft
Graph notifications API (beta) .
7 Note
If you're only targeting web endpoints, you can go directly to setting up your app
service to send notifications.
In addition to app registration on Azure Portal, your application needs to register cross-
device information such as cross-platform application ID and cross-platform push
credentials in order to authorize Microsoft Graph to send notifications via native push
notification services that correspond to each operating system: Windows, iOS, and
Android. This is done through the Partner Center dashboard (formerly Windows Dev
Center dashboard) .
7 Note
You'll need a Windows developer account to complete the steps in this article, even
if you don’t plan to build a Windows UWP application. If you don’t already have a
Windows developer account, see Opening a developer account. Alternatively, if
you prefer not to enroll as a Windows developer, you can reach out to us via email
at [[email protected]](sendto: [email protected]). If you create a
Windows developer account and are building a school or work application as part
of an enterprise, you can associate your developer account with the appropriate
Azure AD account that is used for managing your enterprise submissions. For
details, see Associate Azure Active Directory with your Partner Center account.
To get started, sign in to the Partner Center dashboard using your Windows developer
account:
2. Select all supported platforms where your app will have a presence and be enabled
to receive notifications. You can select from supported platforms that include
Windows, Android, and iOS, as shown.
3. Provide app IDs for each of the platforms where your app has a presence, as
shown.
7 Note
You can add different IDs (up to ten) per platform – this is in case you have multiple
versions of the same app, or even different apps, that want to be able to receive the
same notification sent by your app server and targeted to the same user.
4. Provide or select the app ID from Microsoft account and/or Azure AD app
registration. This client ID corresponds to the Microsoft account or Azure AD app
registration that you obtained when you register in the Azure Portal.
5. Microsoft Graph notifications use each of the native notification platforms on all
major platforms to send notifications to the app client endpoints, namely, WNS
(for Windows UWP), FCM (for Android), and APNS (for iOS). Provide your
credentials for these notification platforms to enable Microsoft Graph notifications
to deliver notifications for your app server when you publish user-targeted
notifications, as shown.
7 Note
For Windows UWP apps, enabling WNS push notification is a prerequisite to using
Microsoft Graph notifications. For details, see WNS overview. After you onboard,
you can provide push credentials via Partner Center to the Connected Device
Platform.
That’s it! You've now registered your applications to receive notifications. Next, learn
how to set up your app service and start sending notifications.
Create and send a notification from
your app service (deprecated)
Article • 09/14/2022
) Important
The Microsoft Graph notifications API is deprecated and stopped returning data in
January 2022. For an alternative notification experience, see Microsoft Azure
Notification Hubs. For more information, see the blog post Retiring Microsoft
Graph notifications API (beta) .
You can create and send a notification to a user by using Microsoft Graph APIs. The
notification is stored in the Microsoft Graph Notifications service store and is sent to all
app clients on all devices that the target user is signed in on.
7 Note
For a simplified authentication story, we recommend using the new and improved,
lightweight notification SDK on the client-side with a user notification
subscription ID to receive notifications and manage notification state. Alternatively,
you can post notifications on behalf of the user via delegated permissions and your
app service will need to maintain access tokens and refresh tokens, but this is not
recommended. To learn more about OAuth 2.0 OBO flow, see Service-to-service
calls that use delegated user identity in the On-Behalf-Of flow.
Getting started
To learn how your app service can start sending notifications to your users, see
notification and our App Service sample .
Integrate your Windows UWP app with
the client-side SDK for user notifications
(deprecated)
Article • 06/25/2022
) Important
The Microsoft Graph notifications API is deprecated and stopped returning data in
January 2022. For an alternative notification experience, see Microsoft Azure
Notification Hubs. For more information, see the blog post Retiring Microsoft
Graph notifications API (beta) .
After you register your app in the Azure Portal and onboard your cross-device
experiences in the Partner Dev Center, the next step is to integrate your client app with
the client-side SDK for Windows UWP apps.
With the client-side SDK, your app can perform the necessary registration steps to start
receiving notifications published from your app server targeted at the user who is
currently signed in. The SDK then manages the notifications on the client side, including
receiving new incoming notifications, managing the state of notifications to achieve
scenarios like universal dismiss, and retrieving full notification history.
1. Application logic. This step captures what triggers the notification to be published
to the user. This is app-specific logic, and can be an event or data update about
something else in Microsoft Graph, such as a new calendar event or task
assignment, or else your app service wants to notify the user about.
2. The app server publishes a notification to the targeted user via the Microsoft
Graph notifications API. For more details, see server side integration.
3. On receiving the web request containing the new notification, Microsoft Graph
notifications persists the content of the notification securely in the cloud for this
app and this user.
4. For each app client instance subscribing to receive notifications for this user,
Microsoft Graph notifications sends a signal to notify the app client, via the native
push service provided by the operating system. In this case, the application is a
UWP app on Windows, and it uses WNS push raw notification to send the signal.
5. After the application is signaled by the incoming push notification, it asks the SDK
to fetch for the changes in the user notification store.
6. The SDK establishes a secure and compliant connection with the user notifications
store in Microsoft Graph.
7. The SDK gets the data changes - in this case, the new notification contents.
8. The SDK fires event callbacks to notify the app after the changes are successfully
retrieved.
9. Application logic. This step captures what your app chooses to do inside the event
callback. Usually, this results in local app data changes and local UI updates. In this
case, the app usually constructs a toast notification popup to notify the user about
the notification contents.
The following diagram shows the data flow for changing the state of a notification or
deleting the notification on one device, and receiving/handling the state change or the
deletion on another device.
Notice that the second part of the flow is similar to the flow for handling new incoming
notifications. This is by design - the programming pattern of the SDK is designed so that
the application client can handle all types of user notification data changes (new
incoming notifications, notification state changes, notification deleted) in a similar way.
Download the NuGet package for the Microsoft Graph notifications SDK for Windows
apps on nuget , or use the following steps to download it from your app solution in
Visual Studio:
In Visual Studio, right-click the project to bring up the context menu, and then click
Manage NuGet Packages….
After the installation finishes, the package shows up under References in the Solution
Explorer.
For more details about including and consuming NuGet packages from your UWP app,
see:
C#
AccountManager_AccessTokenRequestedAsync
For a full implementation, see the Windows app sample .
C#
AccountManager_AccessTokenInvalidated
For a full implementation, see the Windows app sample .
C#
private void
AccountManager_AccessTokenInvalidated(ConnectedDevicesAccountManager sender,
ConnectedDevicesAccessTokenInvalidatedEventArgs args)
{
Logger.Instance.LogMessage($"Token Invalidated. AccountId:
{args.Account.Id}, AccountType: {args.Account.Id}, scopes: {string.Join(" ",
args.Scopes)}");
}
For this reason, a valid WNS channel that allows raw push notifications to come through
successfully is required. The following event callback handles WNS push channel
expirations.
NotificationRegistrationManager_NotificationRegistrationStateChanged
If you're using a Microsoft account, you will need to include the following permissions in
your sign-in request: wl.offline_access" , ccs.ReadWrite , wns.connect ,
asimovrome.telemetry , and
https://activity.windows.com/UserActivity.ReadWrite.CreatedByApp .
If you're using an Azure AD account, you'll need to request the following audience:
https://cdpcs.access.microsoft.com .
C#
C#
C#
C#
C#
notification.UserActionState = UserNotificationUserActionState.Activated;
await notification.SaveAsync();
Delete a notification
If a notification deletion is initiated from this app client instance (for example, if the task
corresponding to this notification is marked as complete and is removed from your
app's database), the app needs to call the SDK to delete the notification in order to have
this delete operation synced across all devices used by the same user.
A notification is removed from the user notification store only if it is expired or explicitly
deleted. A user notification is not deleted when you update the UserActionState to be
Dismissed, because the semantic definition of UserActionState is defined by the
application itself.
C#
await channel.DeleteUserNotificationAsync(notification.Id);
See also
API reference for the full set of APIs related to notification features in the SDK.
Client-side sample for Windows UWP apps.
App server sample for publishing notifications.
Integrate your Android app with the
client-side SDK for user notifications
(deprecated)
Article • 03/03/2023
) Important
The Microsoft Graph notifications API is deprecated and stopped returning data in
January 2022. For an alternative notification experience, see Microsoft Azure
Notification Hubs. For more information, see the blog post Retiring Microsoft
Graph notifications API (beta) .
After you register your app in the Azure Portal and onboard your cross-device
experiences in the Partner Dev Center, the next step is to integrate your client app with
the client-side SDK for Android apps.
With the client-side SDK, your app can perform the necessary registration steps to start
receiving notifications published from your app server targeted at the user who is
currently signed in. The SDK then manages the notifications on the client side, including
receiving new incoming notifications, managing the state of notifications to achieve
scenarios like universal dismiss, and retrieving full notification history.
1. Application logic. This step captures what triggers the notification to be published
to the user. This is app-specific logic, and can be an event or data update about
something else in Microsoft Graph, such as a new calendar event or task
assignment, or else your app service wants to notify the user about.
2. The app server publishes a notification to the targeted user via the Microsoft
Graph notifications API. For more details, see server side integration.
3. On receiving the web request containing the new notification, Microsoft Graph
notifications persists the content of the notification securely in the cloud for this
app and this user.
4. For each app client instance subscribing to receive notifications for this user,
Microsoft Graph notifications sends a signal to notify the app client, via the native
push service provided by the operating system. In this case, the application is an
Android app, and it uses FCM data message to send the signal.
5. After the application is signaled by the incoming push notification, it asks the SDK
to fetch for the changes in the user notification store.
6. The SDK establishes a secure and compliant connection with the user notifications
store in Microsoft Graph.
7. The SDK gets the data changes - in this case, the new notification contents.
8. The SDK fires event callbacks to notify the app after the changes are successfully
retrieved.
9. Application logic. This step captures what your app chooses to do inside the event
callback. Usually, this results in local app data changes and local UI updates. In this
case, the app usually constructs a toast notification popup to notify the user about
the notification contents.
The following diagram shows the data flow for changing the state of a notification or
deleting the notification on one device, and receiving/handling the state change or the
deletion on another device.
Notice that the second part of the flow is similar to the flow for handling new incoming
notifications. This is by design - the programming pattern of the SDK is designed so that
the application client can handle all types of user notification data changes (new
incoming notifications, notification state changes, notification deleted) in a similar way.
Java
allprojects {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
maven { url 'https://projectrome.bintray.com/maven/' }
}
}
Then, insert the following dependency into the build.gradle file that is in your project
folder.
Java
dependencies {
...
implementation 'com.microsoft.connecteddevices:connecteddevices-sdk:+'
}
If you want to use ProGuard in your app, add the ProGuard Rules for these new APIs.
Create a file called proguard-rules.txt in the App folder of your project, and paste in the
contents of ProGuard_Rules_for_Android_Rome_SDK.txt . In your project's
AndroidManifest.xml file, add the following permissions inside the manifest element (if
they are not already present). This gives your app permission to connect to the Internet
and to enable Bluetooth discovery on your device. Note that the Bluetooth-related
permissions are only necessary for using Bluetooth discovery; they are not needed for
the other features in the Connected Devices Platform. Additionally,
ACCESS_COARSE_LOCATION is only required on Android SDKs 21 and later. On Android
SDKs 23 and later, you must also prompt the user to grant location access at runtime.
XML
Next, go to the activity classes where you would like the Connected Devices
functionality to be located. Import the following namespaces.
Java
import com.microsoft.connecteddevices;
import com.microsoft.connecteddevices.userdata;
import com.microsoft.connecteddevices.userdata.usernotifications;
Java
platform.getAccountManager().accessTokenRequested().subscribe((accountManage
r, args) -> onAccessTokenRequested(accountManager, args));
platform.getAccountManager().accessTokenInvalidated().subscribe((accountMana
ger, args) -> onAccessTokenInvalidated(accountManager, args));
platform.getNotificationRegistrationManager().notificationRegistrationStateC
hanged().subscribe((notificationRegistrationManager, args) ->
onNotificationRegistrationStateChanged(notificationRegistrationManager,
args));
platform.start();
Handling account access token
All the web calls the SDK makes, including retrieving the content of a new incoming
notification, updating notification states, and more, are reading from or writing to the
user's data, and therefore always require a valid access token. The SDK requires you to
handle the following events - invoked when an access token is requested or invalidated
- to make sure that after the platform is initialized, your access token for the user is
handled correctly.
accessTokenRequested
For a full implementation, see the Android sample app .
Java
accessTokenInvalidated
Java
private void onAccessTokenInvalidated(ConnectedDevicesAccountManager sender,
ConnectedDevicesAccessTokenInvalidatedEventArgs args, List<Account>
accounts) {
Log.i(TAG, "Token invalidated for account: " +
args.getAccount().getId());
}
Therefore, a valid FCM token that allows data notification messages to come through
successfully is required. The following event callback handles FCM push token
expirations.
notificationRegistrationStateChanged
For a full implementation, see the Android sample app .
If you're using a Microsoft account, you will need to include the following permissions in
your sign-in request: wl.offline_access" , ccs.ReadWrite , wns.connect ,
asimovrome.telemetry , and
https://activity.windows.com/UserActivity.ReadWrite.CreatedByApp .
If you're using an Azure AD account, you'll need to request the following audience:
https://cdpcs.access.microsoft.com .
Java
Java
return mUserNotificationsManager.registerForAccountAsync();
});
});
}
Java
Java
if (notification != null) {
try {
ConnectedDevicesPlatform platform =
ConnectedDevicesManager.getConnectedDevicesManager(getApplicationContext()).
getPlatform();
Java
if (notification.getUserActionState() ==
UserNotificationUserActionState.NO_INTERACTION) {
mNewNotifications.add(notification);
if (notification.getReadState() !=
UserNotificationReadState.READ) {
clearNotification(mContext.getApplicationContext(), notification.getId());
addNotification(mContext.getApplicationContext(), notification.getContent(),
notification.getId());
}
} else {
clearNotification(mContext.getApplicationContext(),
notification.getId());
}
});
}
Java
notification.setUserActionState(UserNotificationUserActionState.ACTIVATED);
notification.saveAsync().whenCompleteAsync((userNotificationUpdateResult,
throwable) -> {
if (throwable == null && userNotificationUpdateResult != null &&
userNotificationUpdateResult.getSucceeded()) {
Log.d(TAG, "Successfully activated the notification");
}
});
Delete a notification
If a notification deletion is initiated from this app client instance (for example, if the task
corresponding to this notification is marked as complete and is removed from your
app's database), the app needs to call the SDK to delete the notification in order to have
this delete operation synced across all devices used by the same user.
A notification is removed from the user notification store only if it is expired or explicitly
deleted. A user notification is not deleted when you update the UserActionState to be
Dismissed, because the semantic definition of UserActionState is defined by the
application itself.
Java
channel.deleteUserNotificationAsync(notification.getId()).whenCompleteAsync(
(userNotificationUpdateResult, throwable) -> {
if (throwable == null && userNotificationUpdateResult != null &&
userNotificationUpdateResult.getSucceeded()) {
Log.d(TAG, "Successfully deleted the notification");
}
});
See also
API reference for the full set of APIs related to notification features in the SDK.
Client-side sample for Android apps.
App server sample for publishing notifications.
Integrate your iOS app with the client-
side SDK for user notifications
(deprecated)
Article • 06/25/2022
) Important
The Microsoft Graph notifications API is deprecated and stopped returning data in
January 2022. For an alternative notification experience, see Microsoft Azure
Notification Hubs. For more information, see the blog post Retiring Microsoft
Graph notifications API (beta) .
After you register your app in the Azure Portal and onboard your cross-device
experiences in the Partner Dev Center, the next step is to integrate your client app with
the client-side SDK for iOS apps.
With the client-side SDK, your app can perform the necessary registration steps to start
receiving notifications published from your app server targeted at the user who is
currently signed in. The SDK then manages the notifications on the client side, including
receiving new incoming notifications, managing the state of notifications to achieve
scenarios like universal dismiss, and retrieving full notification history.
1. Application logic. This step captures what triggers the notification to be published
to the user. This is app-specific logic, and can be an event or data update about
something else in Microsoft Graph, such as a new calendar event or task
assignment, or else your app service wants to notify the user about.
2. The app server publishes a notification to the targeted user via the Microsoft
Graph notifications API. For more details, see server side integration.
3. On receiving the web request containing the new notification, Microsoft Graph
notifications persists the content of the notification securely in the cloud for this
app and this user.
4. For each app client instance subscribing to receive notifications for this user,
Microsoft Graph notifications sends a signal to notify the app client, via the native
push service provided by the operating system. In this case, the application is an
iOS app, and it uses [APNs background update notification] to send the signal.
5. After the application is signaled by the incoming push notification, it asks the SDK
to fetch for the changes in the user notification store.
6. The SDK establishes a secure and compliant connection with the user notifications
store in Microsoft Graph.
7. The SDK gets the data changes - in this case, the new notification contents.
8. The SDK fires event callbacks to notify the app after the changes are successfully
retrieved.
9. Application logic. This step captures what your app chooses to do inside the event
callback. Usually, this results in local app data changes and local UI updates. In this
case, the app usually constructs an iOS alert to notify the user about the
notification contents.
The following diagram shows the data flow for changing the state of a notification or
deleting the notification on one device, and receiving/handling the state change or the
deletion on another device.
Notice that the second part of the flow is similar to the flow for handling new incoming
notifications. This is by design - the programming pattern of the SDK is designed so that
the application client can handle all types of user notification data changes (new
incoming notifications, notification state changes, notification deleted) in a similar way.
ObjectiveC
target 'iOSSample' do
# Uncomment the next line if you're using Swift or would like to use
dynamic frameworks
# use_frameworks!
pod 'ProjectRomeSdk'
7 Note
In order to consume CocoaPod, you must use the .xcworkspace file in your project.
ObjectiveC
MCDConnectedDevicesPlatform* platform = [MCDConnectedDevicesPlatform new];
[platform.accountManager.accessTokenRequested
subscribe:^(MCDConnectedDevicesAccountManager* _Nonnull manager,
MCDConnectedDevicesAccessTokenRequestedEventArgs* _Nonnull args) {
// implement the callback;
}];
[self.platform.accountManager.accessTokenInvalidated
subscribe:^(MCDConnectedDevicesAccountManager* _Nonnull manager
__unused,
MCDConnectedDevicesAccessTokenInvalidatedEventArgs* _Nonnull
request) {
// implement the callback;
}];
[self.platform.notificationRegistrationManager.notificationRegistrationState
Changed subscribe:^(MCDConnectedDevicesNotificationRegistrationManager*
_Nonnull manager __unused,
MCDConnectedDevicesNotificationRegistrationStateChangedEventArgs* _Nonnull
args) {
// implement the callback
}];
[platform start];
accessTokenRequested
accessTokenInvalidated
ObjectiveC
[platform.accountManager.accessTokenInvalidated
subscribe:^(MCDConnectedDevicesAccountManager* _Nonnull manager
__unused,
MCDConnectedDevicesAccessTokenInvalidatedEventArgs* _Nonnull
request) {
}];
For this reason, a valid APNs token that allows background update notifications to come
through successfully is required. The following event callback handles APNs push token
expirations.
notificationRegistrationStateChanged
For a full implementation, see the iOS sample app .
If you're using a Microsoft account, you will need to include the following permissions in
your sign-in request: wl.offline_access" , ccs.ReadWrite , wns.connect ,
asimovrome.telemetry , and
https://activity.windows.com/UserActivity.ReadWrite.CreatedByApp .
If you're using an Azure AD account, you'll need to request the following audience:
https://cdpcs.access.microsoft.com .
ObjectiveC
ObjectiveC
NSArray<MCDUserDataFeedSyncScope*>* syncScopes = @[
[MCDUserNotificationChannel syncScope] ];
[feed subscribeToSyncScopesAsync:syncScopes
callback:^(BOOL success __unused, NSError* _Nullable error __unused)
{
// Start syncing down notifications
[feed startSync];
}];
ObjectiveC
ObjectiveC
[reader readBatchAsyncWithMaxSize:100
completion:^(NSArray<MCDUserNotification *> * _Nullable notifications,
NSError * _Nullable
error) {
if (error) {
} else {
for (MCDUserNotification* notification in self.notifications) {
// Handle notification change based on change type;
}
}
}
}];
ObjectiveC
- (void)dismissNotification:(MCDUserNotification*)notification {
if (notification.userActionState ==
MCDUserNotificationUserActionStateNoInteraction) {
[self
dismissNotificationFromTrayWithId:notification.notificationId];
notification.userActionState =
MCDUserNotificationUserActionStateDismissed;
[notification saveAsync:^(__unused MCDUserNotificationUpdateResult *
_Nullable result, __unused NSError * _Nullable error) {
// handle result;
}];
}
}
Delete a notifications
If a notification deletion is initiated from this app client instance (for example, if the task
corresponding to this notification is marked as complete and is removed from your
app's database), the app needs to call the SDK to delete the notification in order to have
this delete operation synced across all devices used by the same user.
A notification is removed from the user notification store only if it is expired or explicitly
deleted. A user notification is not deleted when you update the UserActionState to be
Dismissed, because the semantic definition of UserActionState is defined by the
application itself.
Obj-C
- (void)deleteNotification:(MCDUserNotification*)notification {
[_channel deleteUserNotificationAsync:notification.notificationId
completion:^(__unused MCDUserNotificationUpdateResult* _Nullable
result, NSError* _Nullable error) {
// handle result;
}];
}
See also
API reference for the full set of APIs related to notification features in the SDK.
Client-side sample for Android apps.
App server sample for publishing notifications.
People and workplace intelligence in
Microsoft Graph
Article • 10/06/2022
The hundreds of millions of users of Microsoft 365 cloud services form part of the core
of Microsoft Graph. The users' data is carefully managed, protected, and with proper
authorization, made available by Microsoft Graph services to drive productivity and
creativity in businesses.
The profile API lets you, as app developers, model and represent people in Microsoft 365
services, and the profile card API lets administrators control the information showing on
users' profile cards in the organization.
As ubiquitous the user's data is in Microsoft Graph, data derived from the user's
interactions is particularly interesting. It provides intelligent insights that can answer
questions such as the following:
You can use the people API and insights API in Microsoft Graph to build smarter apps
that can, respectively, access the relevant people and documents for a user.
The people API returns people ordered by relevance to a user, based on that user's
contacts, organization directory, and recent communications on email. This is
particularly useful for people-picking scenarios.
The insights API uses advanced analytics and machine learning to provide the most
relevant files users need throughout their work day. The API powers familiar Microsoft
365 experiences, including Office Delve, SharePoint Home, the Discover view in
OneDrive for Business, and Outlook on the web.
Why integrate with people data?
The people API returns data of a single entity, person, which includes typical data of an
individual in today's business world. What makes this person data especially useful is its
relevance with respect to a Microsoft Graph user. Relevance is noted in the results
returned which are ordered from most relevant to least relevant. You can use the
following Microsoft Graph APIs to search for people inside an organization.
/search
/people (maintenance mode)
All future investments in people search will be made available via /search ; for
example, natural language search like "John the accountant in Nairobi".
Attribute search matching on attributes other than name and email is available.
Better relevance results from /search give better results due to the use of artificial
intelligence, better data models, and sophisticated spell correction.
Lower cost of goods when using /search , but specifically lower latency.
Fuzzy searches return results based on an exact match and also on inferences about the
intent of the search. To illustrate this, the following example returns person objects
relevant to the signed-in user whose name, or email address, contains a word that starts
with 'j'.
HTTP
GET /me/people/?$search=j
You can use the insights API, which includes the trending, shared, and used APIs, to
surface files from across Microsoft 365 based on your users' current context and needs,
making users more productive and improving collaboration in your organization.
Organizations can customize privacy settings for these document-based insights, and
control the availability of these insights in specific Microsoft 365 experiences.
It is easy to render the results from the insights API in your app. Every result comes with
a set of common visualization properties, like a preview image URL or preview text.
Programmatically, you can use the trending entity in the insights API to provide your
app customers a similar experience. Use the trending entity to connect to documents
that are trending around and relevant to the user. Listing trending documents returns
those files stored on OneDrive or SharePoint team sites, sorted by relevance with the
most important ones first.
The insights API provides a similar functionality with the used and shared entities. They
return what a user has been viewing or working on most recently, or what colleagues
have shared with the user most recently in Microsoft 365.
The analytics API enables you to synchronize or integrate user analytics data with a
custom, third-party app to support a wide range of scenarios that can help improve user
productivity and collaboration. For example, you could integrate Viva Insights data with
mobile device activities to help users keep track of all their work and social activities and
plan their day all within one app.
API reference
Looking for the API reference for these services?
Use the Microsoft Graph API to integrate people and workplace intelligence in an
app (v1.0)
Use the Microsoft Graph API to integrate people and workplace intelligence in an
app (beta)
The People API person resource
Profile (preview) resource
Profile card property (preview) resource
Insights API
Analytics API (preview)
Next steps
Use the Graph Explorer to try out the people, insights, and analytics APIs with your
own files. Sign in, expand People or Insights in the column on the left, and try their
sample queries.
Find more about the people API.
See how to customize the profile card.
Find out more about item insights, customizing item insights privacy for users
(preview), and the item insights settings API (preview) that supports the
customization.
Find more about the analytics API.
Find more about the profile API.
Use the Microsoft Search API to search
people
Article • 10/06/2022
Microsoft Graph applications can use the Microsoft Search API to retrieve the people who are
most relevant to a user. Relevance is determined by the user’s communication and
collaboration patterns and business relationships. People can be local contacts or from an
organization’s directory or people from recent communications.
Along with generating this insight, search also provides fuzzy matching search support and
the ability to retrieve the list of users relevant to another user in the signed-in user's
organization.
People APIs
You can use the following APIs to search for people inside an organization.
/search
/people
7 Note
We recommended that users call the /search endpoint instead of the /people endpoint.
Going forward, all future investments will only be available in the /search endpoint; the
/people endpoint is in maintenance mode.
Property Type
additionalOfficeLocation String
companyName String
department String
displayName String
emailAddress String
givenName String
Property Type
hitId String
imAddress String
jobTitle String
officeLocation String
personType String
phones String
rank Integer
summary String
surname String
userPrincipalName String
Person types
The following table shows people types and subtypes supported in the people API.
Hidden object N N
of any type
except Guest
and Teams
group
Request details
Make the results of the people API more specific by giving additional details when you make
a request. The following are a few ways to make the requests more specific.
"Provenances": ["Mailbox"]
Source of results
People results come from two sources, mailbox or directory. By default, the results will come
from both sources with conflicts being removed, which ensures that same values won't be
returned.
Relevant aspects for the use case when a directory source searches in the global addressing
list in Azure Active Directory:
JSON
"Size": 25
JSON
"From": 0
JSON
The following examples show requests that use the Filter object to return people whose
record contains the specified criteria.
JSON
"Filter": {
"And": [
{
"Term": {
"PeopleType": "Person"
}
}
]
},
JSON
"Filter": {
"And": [
{
"Term": {
"PeopleType": "Person"
}
},
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
}
]
},
JSON
"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "PublicDistributionList"
}
},
{
"Term": {
"PeopleSubtype": "UnifiedGroup"
}
}
]
},
JSON
"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Rooms"
}
}
]
},
JSON
"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Guest"
}
}
]
},
JSON
"Filter": {
"And": [
{
"Or": [
{
"Term": {
"PeopleType": "Person"
}
},
{
"Term": {
"PeopleType": "Other"
}
}
]
},
{
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Guest"
}
}
]
}
]
},
Full request
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"person"
],
"query": {
"queryString": "contoso"
},
"from": 0,
"size": 25
}
]
}
Response
The following is an example of the response, which contains one message that matches the
search criterion.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://canary.graph.microsoft.com/testprodbetapersoninsearch/$metadata#microsof
t.graph.searchResponse",
"value": [
{
"hitsContainers": [
{
"total": 1,
"moreResultsAvailable": false,
"hits": [
{
"hitId": "fc138b85-18ac-48e0-80a4-
633ae4b594e0@41f988bf-86f1-53af-91ab-2d7cd034db47",
"rank": 1,
"summary": "",
"resource": {
"@odata.type": "#microsoft.graph.person",
"displayName": "Example User",
"givenName": "User",
"surname": "User",
"department": "Finance",
"officeLocation": "London",
"userPrincipalName": "[email protected]",
"emailAddresses": [
{
"address": "[email protected]",
"rank": 1
}
],
"phones": [
{
"type": "business",
"number": "+44 (20) 12345678"
}
]
}
}
]
}
]
}
]
}
Next steps
Use the Microsoft Search API to query data
Use the people API to get information
about the people most relevant to you
Article • 10/06/2022
Microsoft Graph applications can use the people API to retrieve the people who are
most relevant to a user. Relevance is determined by the user’s communication and
collaboration patterns and business relationships. People can be local contacts or from
an organization’s directory, and people from recent communications.
Along with generating this insight, the people API also provides fuzzy matching search
support and the ability to retrieve the list of users relevant to another user in the signed-
in user's organization.
The people API is particularly useful for people picking scenarios, such as composing an
email or creating a meeting. For example, you can use the people API in email compose
scenarios.
Individuals connected in the org chart: manager, direct report, peers (share the
same manager)
Members of a public group or distribution list with fewer than 30 people. Public
groups have membership lists that are available in the directory.
If the profile owner communicates with someone and there is no public relationship
between them, such as an org chart connection or a group in common, the fact that
they've been communicating is not visible to others.
The ranking of people—that is, the order in which they appear on the profile owner's
page—is determined by the public communication between the profile owner and the
person on the list.
The ranking doesn’t change based on who User A is (the person looking at someone
else's page). The ranking is determined by the interaction level between User B (profile
owner) and User C (person showing up on profile owner's list).
In order for User C to appear, the profile owner must be in a relatively small group or
distribution list with that user that is public (meaning the membership list is available in
the directory).
People external to the organization do not show on the profile owner's list. People they
email or meet with, but who are not part of the same organization, do not show up as
people the owner works with either.
Disabling "working-with"
Administrators can manage the display or return of people relevant to a profile owner at
two levels:
For an organization:
Enable for the entire organization. This is the default setting.
Disable for the entire organization, other than the profile owner.
For an Azure AD group in the organization:
Disable for a specified Azure AD group. This is useful for enabling "working-
with" for an organization except for members in the Azure AD group.
For more information, see customize people insight privacy control.
Authorization
To call the people API in Microsoft Graph, your app will need the appropriate
permissions:
Browse people
The requests in this section get the people most relevant to the signed-in user ( /me ), or
to a specific user in the signed-in user’s organization. These requests require the
People.Read or People.Read.All permission respectively. By default, each response
returns 10 records, but you can change this by using the $top query parameter.
HTTP
GET https://graph.microsoft.com/v1.0/me/people/
The following example shows the response. By default, each response returns 10
records. You can change this by using the $top query parameter. This example uses $top
to limit the response to three records.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "8CE6E1DE-CB84-4BF5-971D-D3ECF452E2B5",
"displayName": "Lorrie Frye",
"givenName": "Lorrie",
"surname": "Frye",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Paralegal",
"companyName": null,
"yomiCompany": "",
"department": "Legal",
"officeLocation": "20/1109",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+1 980 555 0101"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
},
{
"id": "5767393D-42BA-4E5C-BEE4-52BB25639CF4",
"displayName": "Maynard Denman",
"givenName": "Maynard",
"surname": "Denman",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Web Marketing Manager",
"companyName": null,
"yomiCompany": "",
"department": "Sales & Marketing",
"officeLocation": "20/1101",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+1 918 555 0101"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
},
{
"id": "914B5191-11FA-4C0B-A354-0FA8C8EFD585",
"displayName": "Darrel Halsey",
"givenName": "Darrel",
"surname": "Halsey",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Attorney",
"companyName": null,
"yomiCompany": "",
"department": "Legal",
"officeLocation": "14/1102",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+1 205 555 0103"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
}
]
}
Request a subsequent page of people
If the first response does not contain the complete list of relevant people, you can make
a second request using $top and $skip to request additional pages of information. If the
previous request has additional information, the following request gets the next page of
people from the server.
HTTP
GET https://graph.microsoft.com/v1.0/me/people/?$top=3&$skip=10
The following example shows the response. By default, each response returns 10
records. You can change this by using the $top query parameter. This example uses $top
to limit the response to three records.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "1F28616D-BDFE-4080-8F06-03366A851688",
"displayName": "Felix Coppola",
"givenName": "Felix",
"surname": "Coppola",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "CVP Legal",
"companyName": null,
"yomiCompany": "",
"department": "Legal",
"officeLocation": "19/2109",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+1 309 555 0104"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
},
{
"id": "8A3FC021-6DBB-44AC-8884-B7B500CC260A",
"displayName": "Lenora Rowland",
"givenName": "Lenora",
"surname": "Rowland",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Marketing Assistant",
"companyName": null,
"yomiCompany": "",
"department": "Sales & Marketing",
"officeLocation": "18/1106",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+1 954 555 0118"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
},
{
"id": "032C9919-4DF9-4715-8C46-4D0FAE7B3EB2",
"displayName": "Manuel Collette",
"givenName": "Manuel",
"surname": "Collette",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Accountant II",
"companyName": null,
"yomiCompany": "",
"department": "Finance",
"officeLocation": "98/2202",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+20 255501070"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
}
]
}
HTTP
GET https://graph.microsoft.com/v1.0/me/people/?$orderby=displayName
The following example shows the response. By default, each response returns 10
records. You can change this by using the $top parameter. The following example uses
$top to limit the response to three records.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "818E29A1-E6BB-4EDA-AB20-8230B4B1E290",
"displayName": "Adriana Ramos",
"givenName": "Adriana",
"surname": "Ramos",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Product Marketing Manager",
"companyName": null,
"yomiCompany": "",
"department": "Sales & Marketing",
"officeLocation": "18/2111",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+1 425 555 0109"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
},
{
"id": "62633BAA-1CB9-4FA2-9B8F-55AB1840B69D",
"displayName": "Alyce Cooley",
"givenName": "Alyce",
"surname": "Cooley",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Marketing Assistant",
"companyName": null,
"yomiCompany": "",
"department": "Sales & Marketing",
"officeLocation": "131/1104",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+1 858 555 0110"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
},
{
"id": "6BB54D2C-EF20-48DA-ADD9-AE757DD30C4E",
"displayName": "Alyssa Clarke",
"givenName": "Alyssa",
"surname": "Clarke",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Corporate Security Officer",
"companyName": null,
"yomiCompany": "",
"department": "Operations",
"officeLocation": "24/1106",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+1 262 555 0106"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
}
]
}
The following example requests the 1,000 people most relevant to /me . The request also
limits the amount of data sent back from the server by requesting only the displayName
of the person.
HTTP
GET https://graph.microsoft.com/v1.0/me/people/?
$top=1000&$Select=displayName
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "8CE6E1DE-CB84-4BF5-971D-D3ECF452E2B5",
"displayName": "Lorrie Frye"
},
{
"id": "5767393D-42BA-4E5C-BEE4-52BB25639CF4",
"displayName": "Maynard Denman"
},
{
"id": "914B5191-11FA-4C0B-A354-0FA8C8EFD585",
"displayName": "Darrel Halsey"
},
{
"id": "E3C5B235-DE15-4566-B7B1-7A8E32426540",
"displayName": "Roscoe Seidel"
},
{
"id": "6BB54D2C-EF20-48DA-ADD9-AE757DD30C4E",
"displayName": "Alyssa Clarke"
},
{
"id": "818E29A1-E6BB-4EDA-AB20-8230B4B1E290",
"displayName": "Adriana Ramos"
},
{
"id": "62633BAA-1CB9-4FA2-9B8F-55AB1840B69D",
"displayName": "Alyce Cooley"
},
{
"id": "6BB9CC1F-418D-4DDF-AB0C-6A1C4ABCDBF4",
"displayName": "Wayne Leeper"
},
{
"id": "E7D40AC5-0078-4575-B1F3-F738124C4BC9",
"displayName": "Jan Travis"
},
{
"id": "6F99D1CC-4FCC-49E4-9160-E8AB01BF3E83",
"displayName": "Charlotte Delacruz"
},
{
"id": "1F28616D-BDFE-4080-8F06-03366A851688",
"displayName": "Felix Coppola"
},
{
"id": "8A3FC021-6DBB-44AC-8884-B7B500CC260A",
"displayName": "Lenora Rowland"
},
{
"id": "032C9919-4DF9-4715-8C46-4D0FAE7B3EB2",
"displayName": "Manuel Collette"
}
]
}
HTTP
"X-PeopleQuery-QuerySources: Mailbox,Directory”
HTTP
GET https://graph.microsoft.com/v1.0/me/people/?
$select=displayName,scoredEmailAddresses
The following example shows the response. By default, each response returns 10
records. You can change this using the $top parameter. This example uses $top to limit
the response to three records.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "8CE6E1DE-CB84-4BF5-971D-D3ECF452E2B5",
"displayName": "Lorrie Frye",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
]
},
{
"id": "5767393D-42BA-4E5C-BEE4-52BB25639CF4",
"displayName": "Maynard Denman",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
]
},
{
"id": "914B5191-11FA-4C0B-A354-0FA8C8EFD585",
"displayName": "Darrel Halsey",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
]
}
]
}
HTTP
GET https://graph.microsoft.com/v1.0/me/people/?$filter=personType/class eq
'Person' and personType/subclass eq 'OrganizationUser'
The following example shows the response. By default, each response returns 10
records. You can change this using the $top parameter. This example uses $top to limit
the response to three records.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "8CE6E1DE-CB84-4BF5-971D-D3ECF452E2B5",
"displayName": "Lorrie Frye",
"givenName": "Lorrie",
"surname": "Frye",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Paralegal",
"companyName": null,
"yomiCompany": "",
"department": "Legal",
"officeLocation": "20/1109",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+1 980 555 0101"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
},
{
"id": "5767393D-42BA-4E5C-BEE4-52BB25639CF4",
"displayName": "Maynard Denman",
"givenName": "Maynard",
"surname": "Denman",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Web Marketing Manager",
"companyName": null,
"yomiCompany": "",
"department": "Sales & Marketing",
"officeLocation": "20/1101",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+1 918 555 0101"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
},
{
"id": "914B5191-11FA-4C0B-A354-0FA8C8EFD585",
"displayName": "Darrel Halsey",
"givenName": "Darrel",
"surname": "Halsey",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Attorney",
"companyName": null,
"yomiCompany": "",
"department": "Legal",
"officeLocation": "14/1102",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
],
"phones": [
{
"type": "Business",
"number": "+1 205 555 0103"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
}
]
}
HTTP
GET https://graph.microsoft.com/v1.0/me/people/?
$select=displayName,scoredEmailAddresses&$filter=displayName eq 'Lorrie
Frye'
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "8CE6E1DE-CB84-4BF5-971D-D3ECF452E2B5",
"displayName": "Lorrie Frye",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 8
}
]
}
]
}
HTTP
GET https://graph.microsoft.com/v1.0/users('[email protected]')/people/
The following example shows the response. By default, each response returns 10
records. You can change this using the $top parameter. The example below uses $top to
limit the response to three records.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "56155636-703F-47F2-B657-C83F01F49BBC",
"displayName": "Clifton Clemente",
"givenName": "Clifton",
"surname": "Clemente",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Director",
"companyName": null,
"yomiCompany": "",
"department": "Legal",
"officeLocation": "19/2106",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 20
}
],
"phones": [
{
"type": "Business",
"number": "+1 309 555 0101"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
},
{
"id": "6BF27D5A-AB4F-4C43-BED0-7DAD9EB0C1C4",
"displayName": "Sheree Mitchell",
"givenName": "Sheree",
"surname": "Mitchell",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Product Manager",
"companyName": null,
"yomiCompany": "",
"department": "Sales & Marketing",
"officeLocation": "20/2107",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 10
}
],
"phones": [
{
"type": "Business",
"number": "+1 918 555 0107"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
},
{
"id": "B3E5302D-EAF0-4E8B-8C6C-A2AE64B4B163",
"displayName": "Vincent Matney",
"givenName": "Vincent",
"surname": "Matney",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "CVP Engineering",
"companyName": null,
"yomiCompany": "",
"department": "Engineering",
"officeLocation": "23/2102",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": 10
}
],
"phones": [
{
"type": "Business",
"number": "+1 502 555 0102"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
}
]
}
Search people
The requests in this section allow you to search for people relevant to the signed-in user
( /me ) and other users in the signed-in user’s organization. These requests require the
People.Read permission, with the exception of searching other users’ relevant people,
which requires People.Read.All. By default, each response returns 10 records, but you
can change this by using the $top parameter.
HTTP
GET https://graph.microsoft.com/v1.0/me/people/?$search=j
The following example shows the response. By default, each response returns 10
records. You can change this using the $top parameter. This example uses $top to limit
the response to three records.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "E3C5B235-DE15-4566-B7B1-7A8E32426540",
"displayName": "Jan Travis",
"givenName": "Jan",
"surname": "Travis",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "VP Sales",
"companyName": null,
"yomiCompany": "",
"department": "Sales & Marketing",
"officeLocation": "19/3123",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": -12.297347783416837
}
],
"phones": [
{
"type": "Business",
"number": "+1 732 555 0102"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
},
{
"id": "C43BF05E-5B6B-4DCF-B2FC-0837B09E0FA9",
"displayName": "Jacob Cazares (TAILSPIN)",
"givenName": null,
"surname": null,
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": null,
"companyName": null,
"yomiCompany": "",
"department": null,
"officeLocation": null,
"profession": "",
"userPrincipalName": "",
"imAddress": null,
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": -12.298154282019846
}
],
"phones": [],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "PersonalContact"
}
},
{
"id": "6BB9CC1F-418D-4DDF-AB0C-6A1C4ABCDBF4",
"displayName": "Jewell Montgomery",
"givenName": "Jewell",
"surname": "Montgomery",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": null,
"companyName": null,
"yomiCompany": "",
"department": null,
"officeLocation": null,
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": null,
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": -12.531408487977451
}
],
"phones": [],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
}
]
}
HTTP
GET https://graph.microsoft.com/v1.0/me/people?$search="tyler"
//matches both Tyler's name and email
GET https://graph.microsoft.com/v1.0/me/people?$search="tylerle"
//matches Tyler's email
GET https://graph.microsoft.com/v1.0/me/people?$search="[email protected]"
//matches Tyler's email. Note the quotes to enclose '@'.
GET https://graph.microsoft.com/v1.0/me/people?$search="tiler"
//fuzzy match with Tyler's name
GET https://graph.microsoft.com/v1.0/me/people?$search="tyler lee"
//matches Tyler's name. Note the quotes to enclose the space.
Customize people insights privacy in
Microsoft Graph (preview)
Article • 10/06/2022
People insights represent connections of people who are relevant to or working with
one another within the same organization, based on public relationships between the
people. These insights can be displayed in Delve and the profile card, and returned by
the people API.
Disable people insights for a subset of users, by assigning these users to an Azure
Active Directory (Azure AD) group, and setting the disabledForGroup property to
the ID of that group. Find out more about creating a group and adding users as
members.
When customizing privacy for people insights, you can observe behavioral changes in
the following areas:
On the profile card in Microsoft 365, you can find information about users that is stored
and maintained by your organization, for example Job title or Office location.
Additional properties display in the Contact section of the profile card in Microsoft 365.
You can also delete custom attributes from profile cards of the organization.
7 Note
UserPrincipalName
Fax
StreetAddress
PostalCode
StateOrProvince
Alias
The following table shows how the Azure AD attributes correspond with properties of
the Microsoft Graph user entity.
Azure AD attribute User entity property
UserPrincipalName userPrincipalName
Fax faxNumber
StreetAddress streetAddress
PostalCode postalCode
StateOrProvince state
Alias mailNickname
You can add any of these attributes to the profile card by configuring your organization
settings and adding the attribute as the directoryPropertyName property of a
profileCardProperty in Microsoft Graph. When you make additional attributes visible,
you must use the property names for en-us . You don't have to add localized values. The
additional properties will automatically be shown in the language settings that the user
has specified for Microsoft 365.
) Important
When adding an attribute to profile card, it takes up to 24 hours for the addition to
be displayed.
Example
The following example displays the Alias attribute on the profile card.
HTTP
POST
https://graph.microsoft.com/beta/organization/{tenantid}/settings/profileCar
dProperties
Content-Type: application/json
{
"directoryPropertyName": "Alias"
}
HTTP/1.1 201 OK
Content-type: application/json
{
"directoryPropertyName": "Alias",
"annotations": []
}
Custom properties are not searchable and can't be used to search for people across
Microsoft apps and services.
The following table shows how the Azure AD custom extension attribute names
correspond to the supported values for the directoryPropertyName property of the
profileCardProperty resource. These Azure AD custom extension attribute names are not
case-sensitive:
extensionAttribute1 customAttribute1
extensionAttribute2 customAttribute2
extensionAttribute3 customAttribute3
extensionAttribute4 customAttribute4
extensionAttribute5 customAttribute5
extensionAttribute6 customAttribute6
extensionAttribute7 customAttribute7
extensionAttribute8 customAttribute8
extensionAttribute9 customAttribute9
extensionAttribute10 customAttribute10
Azure AD custom extension attribute Value to specify as directoryPropertyName
extensionAttribute11 customAttribute11
extensionAttribute12 customAttribute12
extensionAttribute13 customAttribute13
extensionAttribute14 customAttribute14
extensionAttribute15 customAttribute15
Example
The following example adds the first Azure AD custom extension attribute to the profile
card, using the display name Cost center. For users that have set their language settings
to German, the display name will be Kostenstelle.
Request
HTTP
POST
https://graph.microsoft.com/beta/organization/{tenantid}/settings/profileCar
dProperties
Content-Type: application/json
{
"directoryPropertyName": "customAttribute1",
"annotations": [
{
"displayName": "Cost center",
"localizations": [
{
"languageTag": "de",
"displayName": "Kostenstelle"
}
]
}
]
}
If a language is not supported, the property name will be shown with the default value.
Response
HTTP
HTTP/1.1 201 OK
Content-type: application/json
{
"directoryPropertyName": "customAttribute1",
"annotations": [
{
"displayName": "Cost center",
"localizations": [
{
"languageTag": "de",
"displayName": "Kostenstelle"
}
]
}
]
}
Example
The following example deletes the custom attribute customAttribute5 from the
organization settings. A successful deletion returns HTTP 204 .
Request
HTTP
DELETE
https://graph.microsoft.com/beta/organization/{organizationId}/settings/prof
ileCardProperties/customAttribute5
Response
HTTP
See also
Find your Microsoft 365 tenant ID
onPremisesExtensionAttributes resource type
User resource type
Graph Explorer
Get profileCardProperty
Item insights overview
Article • 11/29/2022
Item insights are user-centric recommendations for you and those you work with, based
on your collaborative work in Microsoft 365.
https://www.microsoft.com/en-us/videoplayer/embed/RWPGbr?postJsllMsg=true
What are interactions with Microsoft 365 resources like, and how do item insights result
from them? Microsoft 365 lets you collaborate with colleagues in many ways – chatting
with colleagues in Teams chats or channel conversations, over documents such as lists in
SharePoint, PowerBI reports in OneDrive for Business, SharePoint sites, Teams, or
Outlook email. Microsoft derives insights from analyzing activities (such as modifying,
commenting, or sharing), and applies these insights to empower user-centric
experiences with recommendations for users of Microsoft 365, thereby increasing
overall company productivity. Item insights are a type of insights that Microsoft
calculates using advanced machine learning techniques, and applies as content
recommendations for you and your colleagues within the organization.
7 Note
This article does not address other insight-based experiences in Microsoft 365, such
as Viva Insights, the Insights add-in for Outlook, WorkWith feature, MyAnalytics,
and Insights dashboard.
Microsoft does not use your activities from working in a private space to calculate
recommendations for others. That means no one can get insights from your private
documents.
Finally, your colleagues can see recommendations built only on content that they
already have access to. If Alice collaborates with Robert on writing a document, Alice
and Robert can both get recommendations based on this collaborative work. Kate, who
does not have access to the document, does not see recommendations associated with
this file or the collaboration between Alice and Robert. This rule applies to all users in an
organization. In our example, that includes Kate’s manager and administrators, who
would not see recommendations based on content that they do not have access to.
Disabling item insights
By allowing Microsoft to compute item insights from signals in your shared workspaces,
you turn activities and content into usable recommendations, and make this knowledge
easily discoverable and usable to you and your colleagues in your organization. By
doing so, you are helping to boost the productivity of your entire organization.
Even though Microsoft never discloses your private documents and only uses insights of
content that users already have access to, there can be cases where the risk of
discovering the content by undesirable users outweighs the possible benefits. In these
cases, you should consider turning off item insights. Remember that disabling item
insights is not a security measure, and you should always start by reviewing your work
patterns and ensure that your security access is configured as intended. If you want to
make your content and activities less discoverable, you can disable item insights by
using the toggle available in MyAccount, under Settings & Privacy .
Updating settings can take up to 24 hours to apply within the user’s organization across
Microsoft 365 experiences.
Your colleagues can still see files that you have shared with them from OneDrive
for Business and SharePoint in experiences such as Delve and the profile cards in
Microsoft 365 . To prevent these places from displaying shared files, remove the
sharing permissions on the files.
Experiences that show content trending around you is inaccessible to others, in
places such as Delve and the Discover section in Outlook mobile. The lack of
trending insights also reduces your personalized relevance in Microsoft Search
since it cannot use your trending content as signals for relevance.
API reference
Looking for the API reference for this service?
Next steps
Use the Graph Explorer to try out the insights API with your own files. Sign in,
expand Insights in the column on the left, and try the sample queries.
Learn more about customizing item insights privacy for users, and the insights
settings API (preview) that supports the customization.
Customize item insights privacy in
Microsoft Graph (preview)
Article • 03/03/2023
Item insights are relationships that Microsoft calculates using advanced machine
learning techniques. When users collaborate over documents, SharePoint sites and lists,
Teams chats and channels, Microsoft aggregates these activities as signals. From the
signals Microsoft derives insights to make user-centric content recommendations for
users in an organization.
Item insights can help users quickly find files that matter to them, such as in the
Recommended experience in Office.com and Delve. Users can discover in the Discover
area in Outlook Mobile potentially useful content to which they have access but may not
have seen before. From personalized insights such as Recent files in a persona card in
Bing and Recent in Microsoft 365 apps, users can easily discover their recent files.
These item insights reflect only content to which users have access. No user gets
recommendations to content that they can't access.
7 Note
This article does not address other insight-based experiences in Microsoft 365, such
as Viva Insights, the Insights add-in for Outlook, WorkWith feature, MyAnalytics,
and Insights dashboard.
There are a few ways to customize users' item insights privacy settings:
7 Note
The REST and PowerShell APIs for item insights settings are currently available only
in the beta version.
The rest of this article describes how an administrator can customize item insights
privacy in an organization.
Background
At the time of first release in 2014, Office Graph was a backend service for Delve. They
shared a set of privacy controls over both the Office Graph insights and the Delve user
experience. Office Graph has since evolved and become more independent and
powerful, as part of every Microsoft 365 experience and of Microsoft Graph. To offer a
coherent Microsoft Graph schema, Microsoft introduced an itemInsights entity which
inherits all the properties of the pre-existing officeGraphInsights resource, and has kept
officeGraphInsights around for backward compatibility. The introduction of
itemInsights also de-couples the privacy story for the two independent pieces.
While existing apps could continue to use officeGraphInsights, these apps should
upgrade to itemInsights to gain the flexibility to fine-tune item insights in Office Graph
and Delve.
The next section describes using the admin center, and is followed by the section about
PowerShell cmdlets. If you're using the REST API, skip the next two sections and
continue with Configure item insights settings using the REST API. Then refer to the read
or update REST operations for more information.
Additional prerequisites
PowerShell module - Install module version 0.9.1 or higher .
.NET Framework - Install .NET Framework 4.7.2 or a higher version.
Command examples
7 Note
Because item insights commands are only available in beta, switch to the beta
profile before calling it.
PowerShell
Select-MgProfile beta
To get item insights configuration for an organization, use the Microsoft Graph
PowerShell module and the following command, where you replace $TenantId with your
Azure Active Directory tenant ID. You can retrieve this ID from the overview page of your
Azure Active Directory.
PowerShell
By default, item insights are enabled for the entire organization. You can use the
Microsoft Graph PowerShell module to change that and disable item insights for
everyone in the organization.
7 Note
PowerShell
Use the following command, where you replace $TenantId with your Azure Active
Directory Tenant ID and specify -IsEnabledInOrganization as false .
PowerShell
Alternatively, you can change the default and disable item insights for a specific Azure
AD group. Use the following command, where you replace $TenantId with your Azure
Active Directory Tenant ID, and $GroupID with the Azure Active Directory group ID.
PowerShell
Update-MgOrganizationSettingItemInsight -OrganizationId $TenantId -
DisabledForGroup $GroupId
Disable item insights for all users in the organization, by setting the
isEnabledInOrganization property of the insightsSettings resource to false .
Disable item insights for a subset of users, by assigning these users in an Azure AD
group, and setting the disabledForGroup property to the ID of that group. Find
out more about creating a group and adding users as members.
Transition period
To accommodate configuring item insights settings, through the end of 2020, Microsoft
365 respects both Delve settings and item insights settings, and enforces the stricter of
the two if they differ. This means that a user is considered as opted out of item insights
if the user has opted out by either Delve controls or item insights settings.
After this transition period, Delve settings control only Delve experience, and item
insights settings affect only Microsoft Graph item insights. Make sure to configure item
insights according to your organization's requirements.
7 Note
During the transition period, due to technical reasons, the SharePoint start page
may provide stale suggestions if an organization disables item insights for all users.
This issue will be addressed in upcoming server-side changes.
See also
Learn more about Delve and using Delve feature settings to control documents showing
up in the Discover feed:
Using the Microsoft Graph API, you can enable, disable, or get settings that manage
pronouns in an organization, such as controlling the display within the organization of
any pronouns users might have set up for themselves.
Pronouns, in this context, are words used to replace a person's name in a sentence.
Pronouns and their gender-neutral versions exist in many languages. For example, in
English, "she", "her, "he", "him", and the gender-neutral "they", and "them" are common
pronouns. Correctly using someone’s pronouns shows inclusion and respect. Sharing
pronouns helps people avoid guessing or making assumptions based solely on names
or initial observations of the person. In a hybrid, multicultural work or school
environment, the simple act of using the right pronouns can help build trust and
improve communication among one another.
Global administrators can enable or disable pronouns for everyone in the organization,
using the Microsoft 365 Admin Center or Microsoft Graph API as described below. By
default, pronouns are disabled.
When pronouns are enabled, a user can optionally add and manage pronouns in
the profile card in Outlook on the web and Teams.
Pronouns appear by the user's name on the profile card in Outlook and Teams.
Pronouns are displayed only internally within the organization.
Anyone that has an account in the organization, including guest accounts, can see
pronouns on profile cards.
The end user experience with pronouns might evolve over time. For current information
about the end user experience with pronouns, see Pronouns in Microsoft 365 .
Global administrators can decide whether to display pronouns that users set up in their
profile cards. To enable this scenario, you set the isEnabledInOrganization property to
true . When this property is set to true , pronouns are displayed for everyone within the
organization. When this property is set to false , pronouns are not displayed for anyone
within or outside the organization. The default setting is false .
) Important
When you turn pronouns on or off, it can take up to six hours for users to see
changes. For example, if you turn pronouns on, users cannot see the option to add
pronouns on their profile card for up to six hours. If you turn pronouns off, any
previously set pronouns might stay visible in Microsoft 365 (for example, on profile
cards) for up to six hours.
When you turn off pronouns, all pronouns data created by users is deleted. The
data deletion process might take up to 30 days to complete. If you turn pronouns
back on within that period, any hidden pronouns that have not yet been deleted
from Microsoft servers become visible in Microsoft 365 experiences, such as profile
cards.
Prerequisites
PowerShell module - Install module version 1.24.0 or higher .
.NET Framework - Install .NET Framework 4.7.2 or a higher version.
7 Note
Because pronouns settings commands are only available in beta, switch to the beta
profile before running the command.
PowerShell
Select-MgProfile beta
7 Note
PowerShell
Connect-MgGraph -Scopes
"Organization.ReadWrite.All","Organization.Read.All"
Use the following command, where you replace $TenantId with your Azure Active
Directory Tenant ID and specify -IsEnabledInOrganization as true .
PowerShell
PowerShell
The following example gets the current display settings, which have pronouns disabled.
HTTP
GET
https://graph.microsoft.com/beta/organization/{organizationId}/settings/pron
ouns
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"isEnabledInOrganization": false
}
HTTP
PATCH
https://graph.microsoft.com/beta/organization/{organizationId}/settings/pron
ouns
Content-Type: application/json
{
"isEnabledInOrganization": true
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"isEnabledInOrganization": true
}
HTTP
PATCH
https://graph.microsoft.com/beta/organization/{organizationId}/settings/pron
ouns
Content-Type: application/json
{
"isEnabledInOrganization": false
}
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"isEnabledInOrganization": false
}
See also
Turn pronouns on or off for your organization in the Microsoft 365 admin center
Pronouns in Microsoft 365
Profile cards in Microsoft 365
Outlook personal contacts API overview
Article • 10/06/2022
Outlook contacts lets you store personal contacts' data, and is part of the Outlook
messaging hub in Microsoft 365. Through Outlook, you can manage emails, schedule
meetings, find information about users in an organization, initiate online conversations,
share files, and collaborate in groups.
Similarly to the customer experience, you can create contact instances and assign
them to contactFolder objects.
The contacts API lets you assign categories contacts, as well as events, messages,
tasks, and group posts in a consistent way to enhance organization and discovery.
In addition, you can define a user's master list of categories, which can open up
additional creative scenarios.
You can set a flag on a contact for follow-up. (Flagging is currently in preview in
Microsoft Graph.)
The API does not support accessing in-place archive mailboxes, not on Exchange Online
nor on Exchange Server.
API reference
Looking for the API reference for this service?
Next steps
Select and try contacts sample queries in Graph Explorer. Choose Show more
samples in the column on the left. Use the menu to turn on Personal contacts.
Learn about:
Getting immutable identifiers for Outlook resources
Getting shared contacts
Get Outlook contacts in a shared folder
Article • 06/25/2022
Outlook lets customers share folders with one another and provide read, create, modify,
or delete access to individual contact folders. Outlook also allows a customer to
delegate another user to act on the customer's behalf, and access specific folders or the
customer's entire mailbox; this is also known as delegation in Outlook.
As an example, Garth has shared with John a custom contact folder and given John read
access. If John has signed into your app and provided delegated permissions
(Contacts.Read.Shared or Contacts.ReadWrite.Shared), your app is able to access Garth's
custom contact folder and the contacts in that folder. For details, see the following
sections.
7 Note
HTTP
On successful completion, you'll get HTTP 200 OK and the contact instance identified by
{id} from Garth's shared contact folder.
Get all contacts in the shared folder
Get all the contacts in Garth's shared contact folder:
HTTP
On successful completion, you'll get HTTP 200 OK and a collection of contact instances
in Garth's shared contact folder.
HTTP
On successful completion, you'll get HTTP 200 OK and a contactFolder instance that
represents Garth's shared contact folder.
The same GET capabilities apply if Garth had delegated John his entire mailbox.
If Garth has not shared the contact folder with John, nor has he delegated his mailbox to
John, specifying Garth’s user ID or user principal name in those GET operations will
return an error.
Next steps
Find out more about:
Outlook items (messages, events, contacts, tasks) have an interesting behavior that
you've probably either never noticed or has caused you significant frustration: their IDs
change. It doesn't happen often, only if the item is moved, but it can cause real
problems for apps that store IDs offline for later use. Immutable identifiers (IDs) enable
your application to obtain an ID that does not change for the lifetime of the item.
7 Note
Immutable identifiers, like all identifiers in Microsoft Graph, are case-sensitive. Keep
this in mind if you are comparing IDs.
How it works
Immutable ID is an optional feature for Microsoft Graph. To opt in, your application
needs to send an additional HTTP header in your API requests:
HTTP
Prefer: IdType="ImmutableId"
This header only applies to the request it is included with. If you want to always use
immutable IDs, you must include this header with every API request.
Container types (mailFolder, calendar, etc.) do not support immutable ID, but their
regular IDs were already constant.
1. Create a draft message using the Prefer: IdType="ImmutableId" header and save
the id property of the message in the response.
2. Send the message using the ID from the previous step.
3. Get the message using the ID from the first step. This is the copy in Sent Items.
7 Note
Getting the message in Sent Items may not succeed immediately after sending the
message. The copy of the message is not created until the message successfully
sends, which may take time.
with both ID formats, so your application does not need to re-synchronize to take
advantage of immutable ID. You can use the header to get immutable IDs going
forward, and you can update your app's storage separately.
7 Note
Example
The following example translates a normal Microsoft Graph ID to an immutable
Microsoft Graph ID.
Request
HTTP
POST https://graph.microsoft.com/v1.0/me/translateExchangeIds
{
"inputIds" :
[
"AQMkAGM2…"
],
"targetIdType" : "restImmutableEntryId",
"sourceIdType" : "restId"
}
Response
HTTP
HTTP 200 OK
{
"value": [
{
"targetId": "AAkALgAA...",
"sourceId": "AQMkAGM2..."
}
]
}
Change notifications for Outlook
resources in Microsoft Graph
Article • 03/02/2023
The Microsoft Graph API lets you subscribe to changes to a resource—including creation,
update, or deletion of the resource—and receive notifications via webhooks. A subscription
specifies the desired types of changes to monitor for a specific resource, and includes a
URL for an endpoint to receive notifications of those changes.
Setting up a subscription reduces the overhead of otherwise having to query and compare
resources to deduce any changes. You can optionally specify in the subscription request to
encrypt and include as part of a notification the resource data that has changed, saving a
separate subsequent API call to get the resource payload.
There is a maximum limit of 1000 active subscriptions for Outlook resources per mailbox
for all applications. You can subscribe to changes in contacts, events, or messages in the
mailbox.
The following Outlook resources support subscriptions with or without resource data in the
change notification payload.
contact
event
message
Create a subscription
To create a subscription, specify the Outlook resource and the type of changes (creation,
update, or deletion) for which you want to receive notifications. See an example.
Request permissions
Creating and managing (getting, updating, and deleting) a subscription requires a read
scope to the resource. For example, to get change notifications on messages, your app
needs the Mail.Read permission. Outlook change notifications support delegated and
application permission scopes. Note the following limitations:
Depending on the resource, use the least privileged permission specified in the following
table to call this API.
Notifications with resource data for Outlook resources are currently available only in
the Microsoft Graph beta endpoint.
To have resource data included in a change notification, you must specify the following
properties, in addition to those you normally include when creating a subscription:
resource: This property specifies the resource URL. Make sure to use the $select
query parameter to explicitly specify the Outlook resource properties to include in the
notification payload.
7 Note
encryptionCertificate: This property contains only the public key that Microsoft Graph
uses to encrypt resource data. Keep the corresponding private key to decrypt the
content.
encryptionCertificateId: This property is your own identifier for the certificate. Use
this ID to match in each change notification which certificate to use for decryption.
See an example for subscribing to change notifications with resource data for the message
resource.
One common application of $filter is to get notified upon a change in a specific resource
property. For example, you can use $filter to subscribe to unread messages in a folder
(the isRead property is false ), and include all the change types:
If you lose the permission granted earlier for a subscription and the subscription expires
meanwhile, request permission again to create a new subscription.
{
"value": [
{
"subscriptionId": "dfd11b2f-8222-4189-9545-4205c95d6235",
"subscriptionExpirationDateTime": "2021-12-31T16:16:44.9907405+05:30",
"changeType": "created",
"resource": "Users('722effaf-0433-4272-9ac4-
d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"encryptedContent": {
"data": "<<--EncryptedContent-->>",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"dataSignature": "Qw/9ubWeUYJPWWXvNiGgct2FkNG2MXTRm/BLUpJM66k=",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"resourceData": {
"@odata.type": "#microsoft.graph.message",
"@odata.id": "Users('722effaf-0433-4272-9ac4-
d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUR8n\"",
"id": "AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA="
}
}
]
"validationTokens": ["<<--ValidationTokens-->>"]
}
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
JSON
{
"[email protected]":"#DateTimeOffset",
"receivedDateTime":"2021-12-30T10:53:35Z",
"subject":"TEST MESSAGE FOR RICH NOTIFICATIONS",
"bodyPreview":"Hello,\r\n\r\nWhat\u2019s up?\r\n\r\nThanks\r\nMegan",
"[email protected]":"#microsoft.graph.importance",
"importance":"normal",
"from": {
"@odata.type":"#microsoft.graph.recipient",
"emailAddress": {
"@odata.type":"#microsoft.graph.emailAddress",
"name":"Megan Brown",
"address":"[email protected]"
}
}
}
The next example shows the payload of a notification that corresponds to an Outlook
message resource. It includes the resource and resourceData properties, which represent
the resource that triggered the notification. Use the resource and @odata.id properties to
make calls to Microsoft Graph to get the payload of the resource.
7 Note
GET calls always return the current state of the resource. If the resource is changed
between the time the notification is sent and the time the resource is retrieved, the
operation returns the state of the resource on retrieval.
JSON
"value": [
{
"subscriptionId": "c6126aa3-0ed8-412f-a988-71e6cee627c4",
"subscriptionExpirationDateTime": "2022-01-02T03:12:18.2257768+05:30",
"changeType": "created",
"resource": "Users/622eaaff-0683-4862-9de4-
f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIxAAA=",
"resourceData": {
"@odata.type": "#Microsoft.Graph.Message",
"@odata.id": "Users/622eaaff-0683-4862-9de4-
f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIAAA=",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUUXn\"",
"id": "AAMkAGUwNjQ4ZjIxAAA="
},
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}
]
Examples
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"expirationDateTime": "2021-07-07T21:42:18.2257768+00:00",
"clientState": "secretClientState"
}
Response
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "5522bd62-7c96-4530-85b0-00b916f6151a",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientState",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T21:42:18.2257768Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": null,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": null,
"encryptionCertificateId": null,
"notificationUrlAppId": null
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?
$select=Subject,bodyPreview,importance,receivedDateTime,from",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "178eec5f-cf3c-4e7e-8a9c-8640deb5b5c5",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?
$select=Subject,bodyPreview,importance,receivedDateTime,from",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "me/mailfolders('Drafts')/messages?
$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance
eq 'High'",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "239dbc5f-cf3c-4e7e-8c9c-3340abc5b5c5",
"resource": "me/mailfolders('Drafts')/messages?
$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance eq
'High'",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-20T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}
See also
Microsoft Graph change notifications
Set up change notifications that include resource data
Outlook mail API overview
Outlook contacts API overview
Outlook calendar API overview
Microsoft Graph reports API overview
Article • 10/26/2022
The reports API in Microsoft Graph enables you to understand application and resource
activity in your Azure Active Directory (Azure AD) tenant.
https://www.youtube-nocookie.com/embed/P6HneRXYdx8
OneDrive Activity
Usage
Outlook Activity
App usage
Mailbox usage
SharePoint Activity
Site usage
Yammer Activity
Device usage
Groups activity
API reference
Looking for the API reference for this service?
Next steps
Explore the APIs in Graph Explorer.
Authorization for APIs to read Microsoft
365 usage reports
Article • 06/25/2022
Reports data that is accessible via the Microsoft Graph reports API is sensitive. In
particular, Microsoft 365 usage reports are protected by both permissions and Azure
Active Directory (Azure AD) roles. The information in this article applies to the reports
API that reads Microsoft 365 usage reports.
The APIs to read Microsoft 365 usage reports support two types of authorization:
The Azure AD tenant administrator must explicitly grant consent for the requested
permissions to the Graph Explorer application.
The user must be a member of a limited administrator role in Azure AD, listed
above for user-delegated authorization.
7 Note
7 Note
Microsoft Search is an enterprise search engine that delivers productivity gains and
relevant search results for your organization. It harnesses the collective knowledge and
productivity of an organization, and surfaces relevant content to keep end users up to
date. Microsoft Search is available in various experiences including Office, SharePoint,
Delve, Windows, and Bing. You can use the Microsoft Search API in Microsoft Graph to
extend Microsoft Search to your apps.
API reference
Looking for the API reference for this service?
Next steps
Learn more about Microsoft Search.
Learn more about a few key use cases:
Manage connections to index external content
Index external content
Search Outlook messages
Search calendar events
Search content in SharePoint and OneDrive
Search external content
Search with application permissions
Search person (preview)
Manage administrative search answers (preview)
Manage search results layout (preview)
Refine search results
Request spelling correction (preview)
Sort search results
Use query templates (preview)
Trim duplicate search results (preview)
Explore the search APIs in Graph Explorer.
Download the sample search connector from GitHub.
Engage with the community on Microsoft Q&A or on GitHub.
Use the Microsoft Search API to search
acronyms
Article • 03/07/2023
You can use the Microsoft Search API in Microsoft Graph to search acronyms in your
organization. Administrators can create acronyms in the Microsoft 365 admin center
or via the Create acronym API.
U Caution
The search API schema has changed in the beta version. Some properties in a
search request and response have been renamed or removed. For details, see
Schema change deprecation warning. The examples in this topic show the up-to-
date schema.
After acronyms are created, to search for them, in the searchRequest, in the entityTypes
property, specify acronym as the value.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"acronym"
],
"query": {
"queryString":"what is KQL"
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#search",
"value": [
{
"@odata.type": "#microsoft.graph.searchResponse",
"hitsContainers": [
{
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "a9f59c69-f4a1-42ac-820e-0f35114300f8",
"rank": 1,
"resource": {
"@odata.type": "#microsoft.graph.search.acronym",
"id": "a9f59c69-f4a1-42ac-820e-0f35114300f8",
"displayName": "KQL",
"description": "Kusto Query Language is a powerful tool to explore
your data and discover patterns, identify anomalies and outliers, create
statistical modeling, and more.",
"webUrl": "https://docs.microsoft.com/en-us/azure/data-
explorer/kusto/query",
"standsFor": "Kusto Query Language"
}
}
}
],
"total": 1,
"moreResultsAvailable": false
}
]
}
]
}
Known issues
Sorting, aggregation, and pagination are not supported for acronym searches.
Combination searches with non-answer entity types (for example, driveItem, list)
are not supported.
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to search
bookmarks
Article • 03/07/2023
You can use the Microsoft Search API in Microsoft Graph to search bookmarks.
Administrators can create bookmarks in the Microsoft 365 admin center or via the
Create bookmark API.
U Caution
The search API schema has changed in the beta version. Some properties in a
search request and response have been renamed or removed. For details, see
Schema change deprecation warning. The examples in this topic show the up-to-
date schema.
After bookmarks are created, to search for them, in the searchRequest, in the
entityTypes property, specify bookmark as the value.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"bookmark"
],
"query": {
"queryString":"Yammer"
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#search",
"value": [
{
"@odata.type": "#microsoft.graph.searchResponse",
"hitsContainers": [
{
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "a9f59c69-f4a1-42ac-820e-0f35114300f8",
"rank": 1,
"resource": {
"@odata.type": "#microsoft.graph.search.bookmark",
"id": "a9f59c69-f4a1-42ac-820e-0f35114300f8",
"displayName": "Yammer",
"description": "Yammer is a collaboration tool that helps you
connect and engage across the company. Start conversations, share knowledge,
and build communities.",
"webUrl": "https://www.yammer.com/office365",
}
}
}
],
"total": 1,
"moreResultsAvailable": false
}
]
}
]
}
Known issues
Sorting, aggregation and pagination are not supported for bookmark searches.
Combination search with non-Answer entityTypes (i.e. driveItem, list) is not
supported. Only combination search with the other Answer entityTypes
bookmarks, qna and acronym is supported.
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to search
custom types imported using Microsoft
Graph connectors
Article • 10/20/2022
Use the Microsoft Search API in Microsoft Graph to search across external content
ingested and indexed by Microsoft Graph connectors. The content is imported either via
built-in connectors provided by Microsoft, or via custom connectors implemented by
using the Microsoft Graph connectors ingestion API.
U Caution
The search API schema has changed in the beta version. Some properties in a
search request and response have been renamed or removed. For details, see
Schema change deprecation warning. The examples in this topic show the up-to-
date schema.
After the content has been imported and indexed, you can use the search API to query
the content.
To search for custom types, specify the following properties in the request body of the
query method:
The fields property to include the fields in the external item to retrieve. Note that if
you do not include any fields in the request, the response will contain all the fields
marked as retrievable in the data schema specified for the specified connections in
the contentSources property.
Request
HTTP
POST https://graph.microsoft.com/v1.0/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"externalItem"
],
"contentSources": [
"/external/connections/azuresqlconnector",
"/external/connections/azuresqlconnector2"
],
"query": {
"queryString": "yang"
},
"from": 0,
"size": 25,
"fields": [
"BusinessEntityID",
"firstName",
"lastName"
]
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.searc
hResponse)",
"value": [
{
"searchTerms": ["yang"],
"hitsContainers": [
{
"total": 2,
"moreResultsAvailable": false,
"hits": [
{
"hitId": "AAMkADc0NDNlNTE0",
"rank": 1,
"summary": "<ddd/>",
"contentSource": "/external/connections/azuresqlconnector",
"resource": {
"@odata.type": "#microsoft.graph.externalItem",
"properties": {
"businessEntityID": 20704,
"firstName": "Amy",
"lastName": "Yang"
}
}
},
{
"hitId": "AQMkADg3M2I3YWMyLTEwZ",
"rank": 2,
"summary": "<ddd/>",
"contentSource": "/external/connections/azuresqlconnector2",
"resource": {
"@odata.type": "#microsoft.graph.externalItem",
"properties": {
"businessEntityID": 20704,
"shortDescription": "Contoso maintenance guidelines",
"firstName": "Amy",
"lastName": "Yang"
}
}
},
]
}
]
}
]
}
Request
HTTP
POST https://graph.microsoft.com/v1.0/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"microsoft.graph.externalItem"
],
"contentSources": [
"/external/connections/FileAsUdt"
],
"query": {
"query_string": {
"query": "test"
}
},
"stored_fields": [
"label_Title",
"label_URL",
"label_LastModifiedBy",
"label_LastModifiedDateTime"
],
"from": 0,
"size": 25
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.searc
hResponse)",
"value": [
{
"searchTerms": [
"test"
],
"hitsContainers": [
{
"hits": [
{
"_id":
"AQMkAGRjZWJjZTFkLTkzYWItNDhlOC1iODA2LTgwMTNjNjEzYzI2YwBGAAADOx0/YV2JckefuDm
JtUO7mwcAHNjGq33S50uXSFeU/U9mogAAAgEWAAAAHNjGq33S50uXSFeU/U9mogAAAgleAAAA",
"_contentSource": "FileAsUdt",
"_score": 1,
"_summary": "<c0>Test</c0> component to move data files and
messages between the gateway and internal <ddd/>",
"_source": {
"@odata.type": "#microsoft.graph.externalItem",
"properties": {
"label_Title": "SONIC Operations support and test Guide
for the month of March",
"label_URL":
"D:\\\\ConnectorsEcho\\\\New\\\\MSW06SecondSet\\\\teams\\\\Enterprise_Platfo
rms\\\\CCO\\\\Projects\\\\BTSi Modernization\\\\SONIC
Retirement\\\\SONIC_Operations_Support_Guide.docx",
"label_LastModifiedBy": [
"Bob",
"Scott"
],
"label_LastModifiedDateTime": "2020-01-30T12:44:19Z"
}
}
},
{
"_id":
"AQMkAGRjZWJjZTFkLTkzYWItNDhlOC1iODA2LTgwMTNjNjEzYzI2YwBGAAADOx0/YV2JckefuDm
JtUO7mwcAHNjGq33S50uXSFeU/U9mogAAAgEWAAAAHNjGq33S50uXSFeU/U9mogAAAgldAAAA",
"_contentSource": "FileAsUdt",
"_score": 2,
"_summary": "File Transfer Workbench A <c0>test</c0> File
transfer Management Solution File Transfer the number <ddd/>",
"_source": {
"@odata.type": "#microsoft.graph.externalItem",
"properties": {
"label_Title": "Test File Transfer Workbench for the
month of January",
"label_URL":
"D:\\\\ConnectorsEcho\\\\New\\\\MSW06SecondSet\\\\teams\\\\IssueLog\\\\FCAGA
Organisation\\\\NSN CO CCA Infra YBCFTPAR entry\\\\File Transfer
Workbench.ppt",
"label_LastModifiedBy": [
"Alice",
"Scott"
],
"label_LastModifiedDateTime": "2020-01-31T11:44:19Z"
}
}
},
{
"_id":
"AQMkAGRjZWJjZTFkLTkzYWItNDhlOC1iODA2LTgwMTNjNjEzYzI2YwBGAAADOx0/YV2JckefuDm
JtUO7mwcAHNjGq33S50uXSFeU/U9mogAAAgEWAAAAHNjGq33S50uXSFeU/U9mogAAAglgAAAA",
"_contentSource": "FileAsUdt",
"_score": 3,
"_summary": "document and the associated <c0>test</c0>
software are the sole property of Express Logic.<ddd/>",
"_source": {
"@odata.type": "#microsoft.graph.externalItem",
"properties": {
"label_Title": "System User Guide Express Logic
858.613.6640",
"label_URL":
"D:\\\\ConnectorsEcho\\\\New\\\\MSW06FirstSet\\\\teams\\\\AzureIoTMarketing\
\\\Shared Documents\\\\Whitepapers\\\\RTOS Whitepapers\\\\User
Guides\\\\Azure_RTOS_FileX_User_Guide.pdf",
"label_LastModifiedBy": [
"Alice",
"Bob"
],
"label_LastModifiedDateTime": "2020-05-25T10:20:19Z"
}
}
}
],
"total": 3,
"moreResultsAvailable": false
}
]
}
]
}
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to search
OneDrive and SharePoint content
Article • 04/28/2023
Use the Microsoft Search API in Microsoft Graph to search content stored in OneDrive
or SharePoint: files, folders, lists, list items, or sites.
U Caution
The search API schema has changed in the beta version. Some properties in a
search request and response have been renamed or removed. For details, see
Schema change deprecation warning. The examples in this topic show the up-to-
date schema.
The Search API lets you scope the types of content to retrieve in OneDrive or SharePoint
by specifying the entityTypes property on the searchRequest. This article describes
some examples.
Request
HTTP
POST /search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"driveItem"
],
"query": {
"queryString": "contoso"
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#search",
"value": [
{
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"total": 1,
"moreResultsAvailable": false,
"hits": [
{
"hitId": "FlULeN/ui/1GjLx1rUfio5UAAEl",
"rank": 1,
"summary": "<c0>Contoso</c0> Detailed Design <ddd/>",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"createdDateTime": "2019-06-10T06:37:43Z",
"lastModifiedDateTime": "2019-06-10T06:37:43Z",
"name": "web_part_test_long Notebook",
"webUrl": "https://contoso.sharepoint.com/sites/contoso-
team/contoso-designs.docx",
"createdBy": {
"user": {
"displayName": "Michaelvincent Santos;Provisioning User"
}
},
"lastModifiedBy": {
"user": {
"displayName": "Richard Mayer"
}
},
"parentReference": {
"siteId": "m365x231305.sharepoint.com,5724d91f-650c-4810-
83cc-61a8818917d6,c3ba25dc-2c9f-48cb-83be-74cdf68ea5a0",
"driveId": "da61a2b0-4120-4a3f-812b-0fc0d79bf16b",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-83D7-
985FAA4B206D"
}
},
"fileSystemInfo": {
"createdDateTime": "2019-06-10T06:37:43Z",
"lastModifiedDateTime": "2019-06-10T06:37:43Z"
}
}
}
]
}
]
}
]
}
Request
HTTP
POST /search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"listItem"
],
"query": {
"queryString": "contoso"
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#search",
"value": [
{
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"total": 1,
"moreResultsAvailable": false,
"hits": [
{
"hitId": "FlULeN/ui/1GjLx1rUfio5UAAEl",
"rank": 1,
"summary": "",
"resource": {
"@odata.type": "#microsoft.graph.listItem",
"createdDateTime": "2019-06-10T06:37:43Z",
"lastModifiedDateTime": "2019-06-10T06:37:43Z",
"name": "web_part_test_long Notebook",
"webUrl": "https://contoso.sharepoint.com/sites/contoso-
team/Lists/Issue tracker list/DispForm.aspx?ID=1",
"sharepointIds": {
"listId": "33498de0-d695-4d23-ac26-e1bf95a3206e",
"listItemId": "13"
},
"createdBy": {
"user": {
"displayName": "Michaelvincent Santos;Provisioning User"
}
},
"lastModifiedBy": {
"user": {
"displayName": "Richard Mayer"
}
},
"parentReference": {
"sharepointIds":{
"listId":"da61a2b0-4120-4a3f-812b-0fc0d79bf16b"
},
"siteId": "m365x231305.sharepoint.com,5724d91f-650c-4810-
83cc-61a8818917d6,c3ba25dc-2c9f-48cb-83be-74cdf68ea5a0"
}
}
}
]
}
]
}
]
}
Request
HTTP
POST /search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"site"
],
"query": {
"queryString": "contoso"
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#search",
"value": [
{
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"total": 1,
"moreResultsAvailable": false,
"hits": [
{
"hitId": "contoso.sharepoint.com,6598ee0b-0f5f-4416-a0ae-
66d864efb43a,60024ce8-e74d-4d63-a939-ad00cd738670",
"rank": 1,
"summary": "",
"resource": {
"@odata.type": "#microsoft.graph.site",
"id": "contoso.sharepoint.com,6598ee0b-0f5f-4416-a0ae-
66d864efb43a,60024ce8-e74d-4d63-a939-ad00cd738670",
"createdDateTime": "2019-06-10T06:37:43Z",
"description": "Contoso Communication Site",
"lastModifiedDateTime": "2020-08-30T06:41:56Z",
"webUrl": "https://contoso.sharepoint.com/sites/contoso-
team/"
}
}
]
}
]
}
]
}
Request
HTTP
POST /search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"driveItem", "listItem", "list"
],
"query": {
"queryString": "contoso"
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#search",
"value": [
{
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"total": 1,
"moreResultsAvailable": false,
"hits": [
{
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hitId": "FlULeN/ui/1GjLx1rUfio5UAAEl",
"rank": 1,
"summary": "<c0>Contoso</c0> Detailed Design <ddd/>",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"createdDateTime": "2019-06-10T06:37:43Z",
"lastModifiedDateTime": "2019-06-10T06:37:43Z",
"name": "web_part_test_long Notebook",
"webUrl": "https://contoso.sharepoint.com/sites/contoso-
team/contoso-designs.docx",
"createdBy": {
"user": {
"displayName": "Michaelvincent Santos;Provisioning User"
}
},
"lastModifiedBy": {
"user": {
"displayName": "Richard Mayer"
}
},
"parentReference": {
"siteId": "m365x231305.sharepoint.com,5724d91f-650c-4810-
83cc-61a8818917d6,c3ba25dc-2c9f-48cb-83be-74cdf68ea5a0",
"driveId": "da61a2b0-4120-4a3f-812b-0fc0d79bf16b",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-83D7-
985FAA4B206D"
}
},
"fileSystemInfo": {
"createdDateTime": "2019-06-10T06:37:43Z",
"lastModifiedDateTime": "2019-06-10T06:37:43Z"
}
}
},
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "51eef59e-5d49-4d28-96f0-864cf90765e0",
"rank": 2,
"summary": "",
"resource": {
"@odata.type": "#microsoft.graph.list",
"displayName": "Contoso - Documents",
"id": "51eef59e-5d49-4d28-96f0-864cf90765e0",
"description": "",
"lastModifiedDateTime": "2020-07-08T18:17:59+00:00",
"name": "Shared Documents",
"parentReference": {
"siteId": "microsoft.sharepoint-df.com,220fd155-0ea2-477c-
a816-5c08fdc45f5d,fad16ab6-0736-4fbc-a053-087296b47c99"
},
"webUrl": "https://microsoft.sharepoint-
df.com/teams/spoppe/collab/TaskBoard/Contoso/Shared
Documents/Forms/AllItems.aspx"
}
}
]
}
]
}
]
}
Note that property selection for custom properties in SharePoint is only available for
listItem or driveItem because these are the only two SharePoint entities in Microsoft
Graph that support custom properties.
listItem request
HTTP
POST /search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"listItem"
],
"query": {
"queryString": "contoso"
},
"fields": [
"title",
"contentclass"
]
}
]
}
listItem response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#search",
"value": [
{
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"total": 1,
"moreResultsAvailable": false,
"hits": [
{
"hitId": "contoso.sharepoint.com,6598ee0b-0f5f-4416-a0ae-
66d864efb43a,60024ce8-e74d-4d63-a939-ad00cd738670",
"rank": 1,
"summary": "",
"resource": {
"@odata.type": "#microsoft.graph.listItem",
"createdDateTime": "2019-06-10T06:37:43Z",
"webUrl": "https://contoso.sharepoint.com/sites/contoso-
team/contoso-designs.docx",
"sharepointIds": {
"listId": "33498de0-d695-4d23-ac26-e1bf95a3206e",
"listItemId": "13"
},
"parentReference": {
"siteId": "m365x231305.sharepoint.com,5724d91f-650c-4810-
83cc-61a8818917d6,c3ba25dc-2c9f-48cb-83be-74cdf68ea5a0"
},
"fields": {
"contentclass": "STS_ListItem_GenericList",
"title": "Contoso issue "
}
}
}
]
}
]
}
]
}
driveItem request
HTTP
POST /search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"driveItem"
],
"query": {
"queryString": "contoso"
},
"fields": [
"listId",
"author",
"title"
]
}
]
}
driveItem response
HTTP
POST /search/query
Content-Type: application/json
{
"value": [
{
"searchTerms": [],
"hitsContainers": [
{
"hits": [
{
"hitId": "01YOWRGSD34TVVP25X7NAZAW3P2JRL7FWE",
"rank": 1,
"summary": "",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"listItem": {
"@odata.type":
"#microsoft.graph.listItem",
"fields": {
"listId": "3b6a49d3-6bea-4549-bed8-
8b1c92a12345",
"author": "Robin",
"title": "Test Notebook"
},
"id": "57ebe47b-b7eb-41fb-905b-
123452bf96c4"
}
}
}
],
"total": 371,
"moreResultsAvailable": true
}
]
}
],
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searc
hResponse)"
}
Known limitations
When searching for drive, you need to include in the queryString a term contained in
the name of the document library. Querying * is not supported and does not return all
available drives.
Next steps
Use the Microsoft Search API to query data
Search SharePoint content with
application permissions
Article • 03/06/2023
This article describes how you can use application permissions with the Microsoft Search
API in Microsoft Graph to search SharePoint content. Unlike delegated permissions,
application permissions allow an application owner the option to search all content in
the owner's SharePoint sites in a selected region.
By default, application permissions enable search on shared content and disable search
on private content. To enable private content search, see Example 2: Include all private
content.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"listItem"
],
"query": {
"queryString": "contoso"
},
"region": "NAM"
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.type": "#microsoft.graph.searchResponse",
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"total": 2,
"moreResultsAvailable": false,
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "01VRZMWHPGDM5KTXS53RF3SSGHW7SGGPKL",
"rank": 1,
"summary": "As we work to become a more <ddd/> We
<c0>test</c0> samples from the region between 10 and 100 times per day
<ddd/> and surrounding areas that CPU uses to <c0>test</c0> the quality of
your drinking water every day <ddd/> contoso",
"resource": {
"@odata.type": "#microsoft.graph.listItem",
"size": 971838,
"fileSystemInfo": {
"createdDateTime": "2020-07-22T21:14:59Z",
"lastModifiedDateTime": "2018-09-12T16:20:16Z"
},
"id": "01VRZMWHPGDM5KTXS53RF3SSGHW7SGGPKL",
"createdBy": {
"user": {
"displayName": "Adventure Works Cycles"
}
},
"createdDateTime": "2020-07-22T21:14:59+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Adventure Works Cycles"
}
},
"lastModifiedDateTime": "2018-09-12T16:20:16+00:00",
"name": "Adventure Works Cycles Name",
"parentReference": {
"siteId": "Contoso066a,5724d91f-650c-4810-83cc-
61a8818917d6,c3ba25dc-2c9f-48cb-83be-74cdf68ea5a0",
"driveId": "b!NAe_rKr80k-
n7e5zlCVIqSnIwTNsGBVBlusjEvRHgjMmmcA3Ubc7R4Kyao9hbgL4",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl": "http://www.adventure-works.com/"
}
},
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "01BTQFB3LHZTAYBV2VXVEK22ETF5WOQGT2",
"rank": 2,
"summary": "QT300 Accessories Specs Costs Chart Continue
<ddd/> 16 Package 5 14 Grand Total 99 Results Data <c0>Test</c0> Group
Gender <c0>Test</c0> Option 1 2 3 18-25 Male Package 4 Color <ddd/> ",
"resource": {
"@odata.type": "#microsoft.graph.listItem",
"size": 34428,
"fileSystemInfo": {
"createdDateTime": "2020-07-22T21:23:50Z",
"lastModifiedDateTime": "2012-10-29T17:52:10Z"
},
"id": "01BTQFB3LHZTAYBV2VXVEK22ETF5WOQGT2",
"createdBy": {
"user": {
"displayName": "Adventure Works Cycles"
}
},
"createdDateTime": "2020-07-22T21:23:50+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Adatum Corporation"
}
},
"lastModifiedDateTime": "2012-10-29T17:52:10+00:00",
"name": "Adatum Corporation Name",
"parentReference": {
"siteId": "Contoso066a,893378cb-d2cd-4076-a2c9-
e50587a26832,04120cf2-7863-4701-8541-eb26266a25e6",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl": "http://www.adatum.com/contoso"
}
}
]
}
]
}
Example 2: Include all private content
By default, private content search is disabled for customers with application permissions.
7 Note
Searching all private content can be an expensive option. When you run an initial
search request, if the tenant does not have an active APC stamp, you will need a
provision a new APC stamp for your tenant. This can take several hours or days to
complete. After the provisioning, the search will work as normal.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"listItem"
],
"query": {
"queryString": "contoso"
},
"region": "NAM",
"sharePointOneDriveOptions": {
"includeContent": "privateContent,sharedContent"
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.type": "#microsoft.graph.searchResponse",
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"total": 2,
"moreResultsAvailable": false,
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "01VRZMWHPGDM5KTXS53RF3SSGHW7SGGPKL",
"rank": 1,
"summary": "As we work to become a more <ddd/> We
<c0>test</c0> samples from the region between 10 and 100 times per day
<ddd/> and surrounding areas that CPU uses to <c0>test</c0> the quality of
your drinking water every day <ddd/> contoso",
"resource": {
"@odata.type": "#microsoft.graph.listItem",
"size": 971838,
"fileSystemInfo": {
"createdDateTime": "2020-07-22T21:14:59Z",
"lastModifiedDateTime": "2018-09-12T16:20:16Z"
},
"id": "01VRZMWHPGDM5KTXS53RF3SSGHW7SGGPKL",
"createdBy": {
"user": {
"displayName": "Adventure Works Cycles"
}
},
"createdDateTime": "2020-07-22T21:14:59+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Adventure Works Cycles"
}
},
"lastModifiedDateTime": "2018-09-12T16:20:16+00:00",
"name": "Adventure Works Cycles Name",
"parentReference": {
"siteId": "Contoso066a,5724d91f-650c-4810-83cc-
61a8818917d6,c3ba25dc-2c9f-48cb-83be-74cdf68ea5a0",
"driveId": "b!NAe_rKr80k-
n7e5zlCVIqSnIwTNsGBVBlusjEvRHgjMmmcA3Ubc7R4Kyao9hbgL4",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl": "http://www.adventure-works.com/"
}
},
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "01BTQFB3LHZTAYBV2VXVEK22ETF5WOQGT2",
"rank": 2,
"summary": "QT300 Accessories Specs Costs Chart Continue
<ddd/> 16 Package 5 14 Grand Total 99 Results Data <c0>Test</c0> Group
Gender <c0>Test</c0> Option 1 2 3 18-25 Male Package 4 Color <ddd/> ",
"resource": {
"@odata.type": "#microsoft.graph.listItem",
"size": 34428,
"fileSystemInfo": {
"createdDateTime": "2020-07-22T21:23:50Z",
"lastModifiedDateTime": "2012-10-29T17:52:10Z"
},
"id": "01BTQFB3LHZTAYBV2VXVEK22ETF5WOQGT2",
"createdBy": {
"user": {
"displayName": "Adventure Works Cycles"
}
},
"createdDateTime": "2020-07-22T21:23:50+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Adatum Corporation"
}
},
"lastModifiedDateTime": "2012-10-29T17:52:10+00:00",
"name": "Adatum Corporation Name",
"parentReference": {
"siteId": "Contoso066a,893378cb-d2cd-4076-a2c9-
e50587a26832,04120cf2-7863-4701-8541-eb26266a25e6",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl": "http://www.adatum.com/contoso"
}
}
]
}
]
}
Known limitation
Deep paging (paging through the entire result set) is not supported beyond start
row x (e.g. "from" value > 1000). Suggest not to use big 'from' and 'size' value
while executing search request with Application Permission.
Collapsing is not supported.
Use the Microsoft Search API to search with
interleaved results
Article • 12/13/2022
The searchRequest resource supports passing multiple entity types in a single request, and return
interleaved results with requested entity type which is ranked by relevance.
Entity Type message chatMessage drive driveItem event externalItem list listItem person site
message True - - - - - - - - -
chatMessage - True - - - - - - - -
event - - - - True - - - - -
person - - - - - - - - True -
Examples
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"listItem",
"site",
"externalItem"
],
"query": {
"queryString": "contoso"
},
"contentSources":[
"/external/connections/*"
],
"from": 0,
"size": 25
}
]
}
Response
The following is an example of interleaving response.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#search",
"value": [
{
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"total": 4,
"moreResultsAvailable": false,
"hits": [
{
"hitId": "adce5789-c324-485a-a8bf-66bb809527ff",
"rank": 1,
"summary": "Test listItem 1",
"resource": {
"@odata.type": "#microsoft.graph.listItem",
"createdDateTime": "2019-10-07T10:00:08Z",
"lastModifiedDateTime": "2019-10-07T10:00:11Z",
"title": "Here is a summary of your messages from last week - New
Feature: Live captions in English-US a"
},
{
"hitId": "microsoft.sharepoint.com,9fb3f597-167e-4c3d-b5e6-
1ddc18d22d48,c53cd46e-9033-4b42-af94-0ad76ab75fd0",
"rank": 2,
"summary": "Test site",
"resource": {
"@odata.type": "#microsoft.graph.site",
"createdDateTime": "2019-10-07T10:00:08Z",
"lastModifiedDateTime": "2019-10-07T10:00:11Z",
"title": "Test site summary"
}
},
{
"hitId": "adce5789-c324-485a-a8bf-66bb809527ff=",
"rank": 3,
"summary": "Test externalItem",
"resource": {
"@odata.type": "#microsoft.graph.externalItem",
"title": "Test externalItem summary",
}
},
{
"hitId": "ad60906b-1317-495c-b566-7b8ce1be5555",
"rank": 4,
"summary": "Test listItem 2",
"resource": {
"@odata.type": "#microsoft.graph.listItem",
"createdDateTime": "2019-10-07T10:00:08Z",
"lastModifiedDateTime": "2019-10-07T10:00:11Z",
"title": "Test listItem summary 2"
}
]
}
]
}
]
}
Known limitations
Customized sort is not supported in interleaving scenario, all of them are ordered by relevance.
QueryTemplate is only supported for file items in interleaving query, it cannot filter out any
externalItem results in the response. The behavior could be changed in the future and allow
queryTemplate filter out the externalItem results, not suggest to use queryTemplate in
interleaving request.
Collapse is not supported.
Speller modification is not supported, speller suggestion can be used as normal.
Result template is not supported.
Aggregation limitation, if same aggregated field both exist in Sharepoint file types (site, drive,
driveItem, list, listItem) and connectors. Aggregation result will show two same aggregation
buckets with same name, suggest to rename one of its name to bypass the limitation.
Specifying a single connection in content source is not supported, so please only use
"/external/connections/*" in contentSource. Note that there is a plan to change the behavior to
allow single connection interleaving search in the future.
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to search
Outlook calendar events
Article • 06/28/2022
Use the Microsoft Search API in Microsoft Graph to search for events in the signed-in
user’s primary calendar. The user identity for the search is based on the auth token.
U Caution
The search API schema has changed in the beta version. Some properties in a
search request and response have been renamed or removed. For details, see
Schema change deprecation warning. The examples in this topic show the up-to-
date schema.
Example
Request
This example searches in the user's calendar for the keyword "contoso", and returns up
to 25 results.
HTTP
POST https://graph.microsoft.com/v1.0/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"event"
],
"query": {
"queryString":"contoso"
},
"from": 0,
"size": 25
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#search",
"value": [
{
"@odata.type": "#microsoft.graph.searchResponse",
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId":
"AAMkADEwODY2NzllLTQ3MmEtNGRlMC05ZTUyLTE4ZDRhYmU1ZGM3NABGAAAAAAA3+iYQBnJnQab
RVDelNhnzBwAejhWkAOAxQ6M4c1c9NwfrAAAAAAENAAAejhWkAOAxQ6M4c1c9NwfrAABbUZLJAAA
=",
"rank": 1,
"summary": "Here is a summary of your events from last week",
"resource": {
"@odata.type": "#microsoft.graph.event",
"end": {
"dateTime": "2020-06-16T04:15:00Z",
"timeZone": "UTC"
},
"hasAttachments": false,
"iCalUId":
"040000008200E00074C5B7101A82E008000000007093FDD79B3AD6010000000000000000100
0000036DAA2262EB4E04DA27DA77985FB8251",
"isAllDay": false,
"sensitivity": "Normal",
"start": {
"dateTime": "2020-06-16T03:30:00Z",
"timeZone": "UTC"
},
"subject": "Weekly digest: Microsoft 365 changes",
"type": "Single"
}
}
],
"total": 1,
"moreResultsAvailable": false
}
]
}
]
}
Known limitations
You can access only the signed-in user’s own mailbox. Searching delegated
mailboxes is not supported.
For events, the total property of the searchHitsContainer type contains the number
of results on the page, not the total number of matching results.
Sorting results is not supported for events. A sort clause in the request will return a
Bad Request error code in the response.
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to search
Outlook messages
Article • 06/28/2022
Use the Microsoft Search API in Microsoft Graph to search for information in email
messages, return messages ranked by relevance, and render a dedicated search
experience. The search applies to the body and attachments of messages in the signed-
in user's own mailbox.
U Caution
The search API schema has changed in the beta version. Some properties in a
search request and response have been renamed or removed. For details, see
Schema change deprecation warning. The examples in this topic show the up-to-
date schema.
A search query can include filters that end users enter in the Search text box in
Outlook.
Message search applies to work or school accounts. Users can search their own mailbox,
but can't search delegated mailboxes. For details, see known limitations.
Message search also looks for attachments. The supported file types for message
attachment search are the same as those for SharePoint Online search.
Request
HTTP
POST https://graph.microsoft.com/v1.0/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"message"
],
"query": {
"queryString": "contoso"
},
"from": 0,
"size": 25
}
]
}
Response
The following is an example of the response, which contains one message that matches
the search criterion.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#search",
"value": [
{
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"total": 1,
"moreResultsAvailable": false,
"hits": [
{
"hitId": "ptWLQ4o6HYpQg8xmAAATzOzRAAA=",
"rank": 1,
"summary": "Here is a summary of your messages from last
week",
"resource": {
"@odata.type": "#microsoft.graph.message",
"createdDateTime": "2019-10-07T10:00:08Z",
"lastModifiedDateTime": "2019-10-07T10:00:11Z",
"receivedDateTime": "2019-10-07T10:00:09Z",
"sentDateTime": "2019-10-07T09:59:52Z",
"hasAttachments": false,
"subject": "Weekly digest: Microsoft 365 changes",
"bodyPreview": "Here is a summary of your messages from last
week - New Feature: Live captions in English-US a",
"importance": "normal",
"replyTo": [
{
"emailAddress": {
"name": "Goncalo Torres"
}
}
],
"sender": {
"emailAddress": {
"name": "Office365 Message Center",
"address": "[email protected]"
}
},
"from": {
"emailAddress": {
"name": "Office365 Message Center",
"address": "[email protected]"
}
}
}
}
]
}
]
}
]
}
Request
HTTP
POST https://graph.microsoft.com/v1.0/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"message"
],
"query": {
"queryString": "contoso"
},
"from": 0,
"size": 15,
"enableTopResults": true
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#search",
"value": [
{
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"total": 1,
"moreResultsAvailable": false,
"hits": [
{
"hitId": "ptWLQ4o6HYpQg8xmAAATzOzRAAA=",
"rank": 1,
"summary": "Here is a summary of your messages from last
week",
"resource": {
"@odata.type": "#microsoft.graph.message",
"createdDateTime": "2019-10-07T10:00:08Z",
"lastModifiedDateTime": "2019-10-07T10:00:11Z",
"receivedDateTime": "2019-10-07T10:00:09Z",
"sentDateTime": "2019-10-07T09:59:52Z",
"hasAttachments": false,
"subject": "Weekly digest: Microsoft 365 changes",
"bodyPreview": "Here is a summary of your messages from last
week - New Feature: Live captions in English-US a",
"importance": "normal",
"replyTo": [
{
"emailAddress": {
"name": "Goncalo Torres"
}
}
],
"sender": {
"emailAddress": {
"name": "Office365 Message Center",
"address": "[email protected]"
}
},
"from": {
"emailAddress": {
"name": "Office365 Message Center",
"address": "[email protected]"
}
}
}
}
]
}
]
}
]
}
Known limitations
You can access only the signed-in user’s own mailbox. Searching delegated
mailboxes is not supported.
For messages, the total property of the searchHitsContainer type contains the
number of results on the page, not the total number of matching results.
Sorting results is not supported for events. A sort clause in the request will return a
Bad Request error code in the response.
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to search
people
Article • 10/06/2022
Microsoft Graph applications can use the Microsoft Search API to retrieve the people who are
most relevant to a user. Relevance is determined by the user’s communication and
collaboration patterns and business relationships. People can be local contacts or from an
organization’s directory or people from recent communications.
Along with generating this insight, search also provides fuzzy matching search support and
the ability to retrieve the list of users relevant to another user in the signed-in user's
organization.
People APIs
You can use the following APIs to search for people inside an organization.
/search
/people
7 Note
We recommended that users call the /search endpoint instead of the /people endpoint.
Going forward, all future investments will only be available in the /search endpoint; the
/people endpoint is in maintenance mode.
Property Type
additionalOfficeLocation String
companyName String
department String
displayName String
emailAddress String
givenName String
Property Type
hitId String
imAddress String
jobTitle String
officeLocation String
personType String
phones String
rank Integer
summary String
surname String
userPrincipalName String
Person types
The following table shows people types and subtypes supported in the people API.
Hidden object N N
of any type
except Guest
and Teams
group
Request details
Make the results of the people API more specific by giving additional details when you make
a request. The following are a few ways to make the requests more specific.
"Provenances": ["Mailbox"]
Source of results
People results come from two sources, mailbox or directory. By default, the results will come
from both sources with conflicts being removed, which ensures that same values won't be
returned.
Relevant aspects for the use case when a directory source searches in the global addressing
list in Azure Active Directory:
JSON
"Size": 25
JSON
"From": 0
JSON
The following examples show requests that use the Filter object to return people whose
record contains the specified criteria.
JSON
"Filter": {
"And": [
{
"Term": {
"PeopleType": "Person"
}
}
]
},
JSON
"Filter": {
"And": [
{
"Term": {
"PeopleType": "Person"
}
},
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
}
]
},
JSON
"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "PublicDistributionList"
}
},
{
"Term": {
"PeopleSubtype": "UnifiedGroup"
}
}
]
},
JSON
"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Rooms"
}
}
]
},
JSON
"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Guest"
}
}
]
},
JSON
"Filter": {
"And": [
{
"Or": [
{
"Term": {
"PeopleType": "Person"
}
},
{
"Term": {
"PeopleType": "Other"
}
}
]
},
{
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Guest"
}
}
]
}
]
},
Full request
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"person"
],
"query": {
"queryString": "contoso"
},
"from": 0,
"size": 25
}
]
}
Response
The following is an example of the response, which contains one message that matches the
search criterion.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://canary.graph.microsoft.com/testprodbetapersoninsearch/$metadata#microsof
t.graph.searchResponse",
"value": [
{
"hitsContainers": [
{
"total": 1,
"moreResultsAvailable": false,
"hits": [
{
"hitId": "fc138b85-18ac-48e0-80a4-
633ae4b594e0@41f988bf-86f1-53af-91ab-2d7cd034db47",
"rank": 1,
"summary": "",
"resource": {
"@odata.type": "#microsoft.graph.person",
"displayName": "Example User",
"givenName": "User",
"surname": "User",
"department": "Finance",
"officeLocation": "London",
"userPrincipalName": "[email protected]",
"emailAddresses": [
{
"address": "[email protected]",
"rank": 1
}
],
"phones": [
{
"type": "business",
"number": "+44 (20) 12345678"
}
]
}
}
]
}
]
}
]
}
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to search
questions and answers
Article • 03/07/2023
You can use the Microsoft Search API in Microsoft Graph to search questions and
answers (Q&As). The qna resource represents Q&As in Microsoft Search. Administrators
can create Q&As in the Microsoft 365 admin center or via the Create qna API.
U Caution
The search API schema has changed in the beta version. Some properties in a
search request and response have been renamed or removed. For details, see
Schema change deprecation warning. The examples in this topic show the up-to-
date schema.
After you create your Q&As, you can use the Microsoft Graph Search API to search for
them. To do this, specify qna as the value in the entityTypes property in your search
request body and then provide a relevant query string, as shown in the following
example.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"qna"
],
"query": {
"queryString":"what is Microsoft Azure"
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#search",
"value": [
{
"@odata.type": "#microsoft.graph.searchResponse",
"hitsContainers": [
{
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
{
"hitId": "2364ebd9-cd11-4f47-b785-fe378c6233f3",
"rank": 1,
"resource": {
"@odata.type": "#microsoft.graph.search.qna",
"id": "2364ebd9-cd11-4f47-b785-fe378c6233f3",
"displayName": "what is Microsoft Azure",
"description": "Microsoft Azure is a cloud computing platform and
an online portal that allows you to access and manage cloud services and
resources provided by Microsoft.",
"webUrl": "https://azure.microsoft.com/en-us/resources/cloud-
computing-dictionary/what-is-azure/"
}
}
],
"total": 1,
"moreResultsAvailable": false
}
]
}
]
}
Known issues
Sorting, aggregation, and pagination are not supported for [qna]
((/graph/api/resources/search-qna) searches.
Combination search with non-Answer entityTypes (i.e. driveItem, list) is not
supported. Only combination search with the other Answer entityTypes
bookmarks, qna and acronym is supported.
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to search
Teams messages
Article • 03/02/2023
Use the Microsoft Search API in Microsoft Graph to search for information in Teams
messages, return messages ranked by relevance, and render a dedicated search
experience. The search applies to the body and attachments of messages in the signed-
in user's Teams messages.
U Caution
The search API schema has changed in the beta version. Some properties in a
search request and response have been renamed or removed. For details, see
Schema change deprecation warning. The examples in this topic show the up-to-
date schema.
Teams message search also looks for attachments. The supported file types for message
attachment search are the same as those for SharePoint Online search.
Examples
Request
The following example queries Teams chat messages in the signed-in user's Teams chat
storage that contain the string "test" in any part of the chat message (the sender name,
message body, or any attachments). The query returns the first 25 results. The search
results are ordered by descending dateTime.
HTTP
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"chatMessage"
],
"query": {
"queryString": "test"
},
"from": 0,
"size": 25
}
]
}
Response
The following is an example of the response, which contains one message that matches
the search criterion.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"searchTerms": [
"test"
],
"hitsContainers": [
{
"hits": [
{
"hitId":
"AAMkAGIwMDA5MmY0LWY5ZTgtNGY5YS04NzczLWNhNjc0ZGIyZDBjYgBGAAAAAADm35sgHbzESap
J8+BjBlhEBwDAYtphe7dsRbDrOT/HAHoKAAAAAAEpAADAYtphe7dsRbDrOT/HAHoKAAFwxQGaAAA
=",
"rank": 1,
"summary": "...Test with the TDF account",
"resource": {
"@odata.type":
"microsoft.graph.chatMessage",
"id": "1657782060227",
"createdDateTime": "2022-07-14T07:01:01Z",
"lastModifiedDateTime": "2022-07-
14T07:01:03Z",
"subject": "",
"importance": "normal",
"webLink":
"https://outlook.office365.com/owa/?
ItemID=AAMkAGIwMDA5MmY0LWY5ZTgtNGY5YS04NzczLWNhNjc0ZGIyZDBjYgBGAAAAAADm35sgH
bzESapJ8%2BBjBlhEBwDAYtphe7dsRbDrOT%2FHAHoKAAAAAAEpAADAYtphe7dsRbDrOT%2FHAHo
KAAFwxQGaAAA%3D&exvsurl=1&viewmodel=ReadMessageItem",
"from": {
"emailAddress": {
"name": "Goncalo Torres",
"address": "[email protected]"
}
},
"channelIdentity": {},
"etag": "1657782060227",
"chatId":
"19:[email protected]"
}
}
],
"total": 1,
"moreResultsAvailable": false
}
]
}
]
}
Request
The following example uses the search query shown in Example 1, and sorts the results
by relevance.
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"chatMessage"
],
"query": {
"queryString": "test"
},
"from": 0,
"size": 15,
"enableTopResults": true
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"searchTerms": [
"test"
],
"hitsContainers": [
{
"hits": [
{
"hitId":
"AAMkAGIwMDA5MmY0LWY5ZTgtNGY5YS04NzczLWNhNjc0ZGIyZDBjYgBGAAAAAADm35sgHbzESap
J8+BjBlhEBwDAYtphe7dsRbDrOT/HAHoKAAAAAAEpAADAYtphe7dsRbDrOT/HAHoKAAFwxQGaAAA
=",
"rank": 1,
"summary": "...Test with the TDF account",
"resource": {
"@odata.type":
"microsoft.graph.chatMessage",
"id": "1657782060227",
"createdDateTime": "2022-07-14T07:01:01Z",
"lastModifiedDateTime": "2022-07-
14T07:01:03Z",
"subject": "",
"importance": "normal",
"webLink":
"https://outlook.office365.com/owa/?
ItemID=AAMkAGIwMDA5MmY0LWY5ZTgtNGY5YS04NzczLWNhNjc0ZGIyZDBjYgBGAAAAAADm35sgH
bzESapJ8%2BBjBlhEBwDAYtphe7dsRbDrOT%2FHAHoKAAAAAAEpAADAYtphe7dsRbDrOT%2FHAHo
KAAFwxQGaAAA%3D&exvsurl=1&viewmodel=ReadMessageItem",
"from": {
"emailAddress": {
"name": "Goncalo Torres",
"address": "[email protected]"
}
},
"channelIdentity": {},
"etag": "1657782060227",
"chatId":
"19:[email protected]"
}
}
],
"total": 1,
"moreResultsAvailable": false
}
]
}
]
}
Request
The following example shows how to search a message that contains Contoso that Bob
sent to Alice after 2022-07-14.
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"chatMessage"
],
"query": {
"queryString": "contoso from:bob to:alice sent>2022-07-14"
},
"from": 0,
"size": 15,
"enableTopResults": true
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"searchTerms": [
"test"
],
"hitsContainers": [
{
"hits": [
{
"hitId":
"AAMkAGIwMDA5MmY0LWY5ZTgtNGY5YS04NzczLWNhNjc0ZGIyZDBjYgBGAAAAAADm35sgHbzESap
J8+BjBlhEBwDAYtphe7dsRbDrOT/HAHoKAAAAAAEpAADAYtphe7dsRbDrOT/HAHoKAAFwxQGaAAA
=",
"rank": 1,
"summary": "...Contoso Test with the TDF
account",
"resource": {
"@odata.type":
"microsoft.graph.chatMessage",
"id": "1657782060227",
"createdDateTime": "2022-07-15T07:01:01Z",
"lastModifiedDateTime": "2022-07-
15T07:01:03Z",
"subject": "",
"importance": "normal",
"webLink":
"https://outlook.office365.com/owa/?
ItemID=AAMkAGIwMDA5MmY0LWY5ZTgtNGY5YS04NzczLWNhNjc0ZGIyZDBjYgBGAAAAAADm35sgH
bzESapJ8%2BBjBlhEBwDAYtphe7dsRbDrOT%2FHAHoKAAAAAAEpAADAYtphe7dsRbDrOT%2FHAHo
KAAFwxQGaAAA%3D&exvsurl=1&viewmodel=ReadMessageItem",
"from": {
"emailAddress": {
"name": "bob",
"address": "[email protected]"
}
},
"channelIdentity": {},
"etag": "1657782060228",
"chatId":
"19:[email protected]"
}
}
],
"total": 1,
"moreResultsAvailable": false
}
]
}
]
}
Known limitations
You can access only the signed-in user's Teams message or the message the user is
included in.
The search Teams API does not return all properties defined in chatMessage. You
can use the Teams API to retrieve more details about any single message.
For Teams messages, the total property of the searchHitsContainer type contains
the number of results on the page, not the total number of matching results.
Sorting results is not supported for messages.
You can't use this API with other entity types at this time.
Next steps
Use the Microsoft Search API to query data
Set up administrative search answers for
users in an organization (preview)
Article • 03/02/2023
Microsoft Search lets administrators associate search terms with meanings or web pages
that are specific to their organizations and include these associations as search answers.
For example, users in an organization may run into an unfamiliar acronym that
represents an internal project name, or a team name that is associated with a team web
page. Administrators can set up acronyms, bookmarks, or QnA in the Microsoft 365
admin center , under Search & intelligence. This enables users to use search to
navigate and get familiarized with their work.
Administrators can also use the Microsoft Search API in Microsoft Graph to
programmatically manage administrative search answers in the organization. These
answers are displayed in Microsoft Search results when triggered by an acronym or
keyword defined in the available search answer resource types: acronym, bookmark, and
QnA resources.
When triggered by a defined acronym or keyword, these search answers appear at the
top of the search results page in your organization.
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/search/acronyms
Content-Type: application/json
{
"displayName": "GDPR",
"standsFor": "General Data Protection Regulation",
"description": "A European Union (EU) regulation on data protection
and privacy in the EU and the European Economic Area (EEA) that enhances
individuals' control and rights over their personal data, simplifies the
regulatory environment for international business, and addresses the
transfer of personal data outside the EU and EEA areas.",
"webUrl": "http://contoso.com/GDPR",
"state": "published"
}
Response
Here is an example of the response.
HTTP
HTTP/1.1 200 Ok
Content-Type: application/json
{
"id": "733b26d5-af76-4eea-ac69-1a0ce8716897"
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/search/bookmarks
Content-Type: application/json
{
"displayName": "Contoso Install Site",
"webUrl": "http://www.contoso.com/",
"description": "Try or buy Contoso for Home or Business and view
product information",
"keywords": {
"keywords": ["Contoso", "install"],
"reservedKeywords": ["Contoso"],
"matchSimilarKeywords": true
},
"state": "published"
}
Response
Here is an example of the response.
HTTP
{
"id": "733b26d5-af76-4eea-ac69-1a0ce8716897"
}
Next steps
Be familiar with the Search API scenarios and capabilities: Microsoft Search API
overview.
Explore the search APIs in Graph Explorer.
Use the Microsoft Search API to manage administrative answers.
Use the Microsoft Search API to manage
layout templates for search results
Article • 06/28/2022
You can use the Microsoft Search API in Microsoft Graph to manage layout templates
for search results. A search display layout or result type is a rule that causes distinct
kinds of search results to be displayed in different ways in search result pages. It consists
of the following:
The Microsoft Graph Search API provides a renderable response based on Adaptive
Cards . By using the Adaptive Card template , clients can render different search
result in different canvases.
Customers can customize their search result type in the Microsoft 365 admin center .
Request example
The following example shows how to get the display layouts or result templates for
rendering the search results by setting the enableResultTemplate property to true in
the request contract.
The response shows three search hits, two of them related, with the resultTemplateId
1603900360618_5XCBK2OXG, and the other one with the resultTemplateId
1603900360618_5XCBK2OXP. These IDs match with one of the keys of the two display
layouts contained in the resultTemplates dictionary that's included within the response
contract. Using the result template IDs, you can determine which display layout to use to
render each search result.
Request
HTTP
POST https://graph.microsoft.com/v1.0/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"externalItem"
],
"contentSources": [
"Connectors"
],
"query": {
"queryString": "*"
},
"resultTemplateOptions": {
"enableResultTemplate": true
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.searc
hResponse)",
"value": [
{
"searchTerms": [],
"hitsContainers": [
{
"total": 1201701,
"moreResultsAvailable": true,
"hits": [
{
"hitId": "85437765-b430-434f-a945-38eceead5b93",
"rank": 1,
"summary": "",
"resultTemplateId": "1603900360618_5XCBK2OXG",
"resource": {
"@odata.type":
"#microsoft.graph.externalItem",
"id": "B5B6E9C7-152C-4478-BCCB-
CEF053F17397",
"Title": "[SM00186] Number of tests -
Liquid",
"URL":
"https://liquid.microsoft.com/Web/Object/Read/scanningtoolwarnings/Requireme
nts/CodeQL.SM00186"
}
},
{
"hitId": "85437765-5430-434f-a945-38eceead5b94",
"rank": 2,
"summary": "",
"resultTemplateId": "1603900360618_5XCBK2OXP",
"resource": {
"@odata.type":
"#microsoft.graph.externalItem",
"id": "B5B6E9C7-152C-4478-BCCB-
CEF053F17398",
"Title": "[SM00186] Number of tests - Liquid
2",
"URL":
"https://liquid.microsoft.com/Web/Object/Read/scanningtoolwarnings/Requireme
nts/CodeQL.SM00186"
}
},
{
"hitId": "85437765-b430-434f-a945-38eceead5b95",
"rank": 3,
"summary": "",
"resultTemplateId": "1603900360618_5XCBK2OXG",
"resource": {
"@odata.type":
"#microsoft.graph.externalItem",
"id": "B5B6E9C7-152C-4478-BCCB-
CEF053F17399",
"Title": "[SM00186] Number of tests - Liquid
3",
"URL":
"https://liquid.microsoft.com/Web/Object/Read/scanningtoolwarnings/Requireme
nts/CodeQL.SM00186"
}
}
]
}
],
"resultTemplates": {
"1603900360618_5XCBK2OXG": {
"displayName": "Liquid-3",
"body": {
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "Image",
"url":
"https://searchuxcdn.azureedge.net/designerapp/images/LiquidLogo.png",
"horizontalAlignment":
"Center",
"size": "Small"
}
],
"horizontalAlignment": "Center"
},
{
"type": "Column",
"width": 10,
"items": [
{
"type": "TextBlock",
"text": "[{Title}]({URL})",
"weight": "Bolder",
"color": "Accent",
"size": "Medium",
"maxLines": 3
},
{
"type": "TextBlock",
"text": "{ResultSnippet}",
"maxLines": 3,
"wrap": true
}
],
"spacing": "Medium"
}
]
}
],
"$schema":
"http://adaptivecards.io/schemas/adaptive-card.json"
}
},
"1603900360618_5XCBK2OXP": {
"displayName": "Liquid-2",
"body": {
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "Image",
"url":
"https://searchuxcdn.azureedge.net/designerapp/images/LiquidLogo.png",
"horizontalAlignment":
"Center",
"size": "Small"
}
],
"horizontalAlignment": "Center"
},
{
"type": "Column",
"width": 10,
"items": [
{
"type": "TextBlock",
"text": "[{Title}]({URL})",
"weight": "Bolder",
"color": "Accent",
"size": "Medium",
"maxLines": 3
},
{
"type": "TextBlock",
"text": "{ResultSnippet}",
"maxLines": 3,
"wrap": true
}
],
"spacing": "Medium"
}
]
}
],
"$schema":
"http://adaptivecards.io/schemas/adaptive-card.json"
}
}
}
}
]
}
) Important
This example uses a version of Adaptive Card templating earlier than the May 2020
release. For more details, see:
Adaptive Card templating
Adaptive Card templating SDK
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Adaptive Cards Example</title>
<script src="https://unpkg.com/[email protected]/dist/markdown-it.js">
</script>
<script src="https://unpkg.com/adaptivecards/dist/adaptivecards.min.js">
</script>
<script src="https://unpkg.com/[email protected]
alpha1/dist/adaptivecards-templating.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.js"
integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk="
crossorigin="anonymous"></script>
<style type="text/css">
#exampleDiv {
border: solid 1px black;
}
</style>
<script type="text/javascript">
function renderCard() {
var mockdata = this.getMockData();
var renderTemplates = [];
console.log(hit.resource);
console.log(context);
var card = template.expand(context);
// OPTIONAL: Render the card (requires that the adaptivecards
library be loaded)
function getMockData() {
return {
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.searc
hResponse)",
"value": [
{
"searchTerms": [],
"hitsContainers": [
{
"total": 1201701,
"moreResultsAvailable": true,
"hits": [
{
"hitId": "85437765-b430-434f-a945-
38eceead5b93",
"rank": 1,
"summary": "",
"resultTemplateId":
"1603900360618_5XCBK2OXG",
"resource": {
"@odata.type":
"#microsoft.graph.externalItem",
"id": "B5B6E9C7-152C-4478-BCCB-
CEF053F17397",
"Title": "[SM00186] Number of
tests - Liquid",
"URL":
"https://liquid.microsoft.com/Web/Object/Read/scanningtoolwarnings/Requireme
nts/CodeQL.SM00186"
}
},
{
"hitId": "85437765-5430-434f-a945-
38eceead5b94",
"rank": 2,
"summary": "",
"resultTemplateId":
"1603900360618_5XCBK2OXP",
"resource": {
"@odata.type":
"#microsoft.graph.externalItem",
"id": "B5B6E9C7-152C-4478-BCCB-
CEF053F17398",
"Title": "[SM00186] Number of
tests - Liquid 2",
"URL":
"https://liquid.microsoft.com/Web/Object/Read/scanningtoolwarnings/Requireme
nts/CodeQL.SM00186"
}
},
{
"hitId": "85437765-b430-434f-a945-
38eceead5b95",
"rank": 3,
"summary": "",
"resultTemplateId":
"1603900360618_5XCBK2OXG",
"resource": {
"@odata.type":
"#microsoft.graph.externalItem",
"id": "B5B6E9C7-152C-4478-BCCB-
CEF053F17399",
"Title": "[SM00186] Number of
tests - Liquid 3",
"URL":
"https://liquid.microsoft.com/Web/Object/Read/scanningtoolwarnings/Requireme
nts/CodeQL.SM00186"
}
}
]
}
],
"resultTemplates": {
"1603900360618_5XCBK2OXG": {
"displayName": "Liquid-3",
"body": {
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "Image",
"url":
"https://searchuxcdn.azureedge.net/designerapp/images/LiquidLogo.png",
"horizontalAlignment": "Center",
"size": "Small"
}
],
"horizontalAlignment":
"Center"
},
{
"type": "Column",
"width": 10,
"items": [
{
"type":
"TextBlock",
"text": "
[{Title}]({URL})",
"weight":
"Bolder",
"color":
"Accent",
"size":
"Medium",
"maxLines": 3
},
{
"type":
"TextBlock",
"text": "
{ResultSnippet}",
"maxLines": 3,
"wrap": true
}
],
"spacing": "Medium"
}
]
}
],
"$schema":
"http://adaptivecards.io/schemas/adaptive-card.json"
}
},
"1603900360618_5XCBK2OXP": {
"displayName": "Liquid-2",
"body": {
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "Image",
"url":
"https://searchuxcdn.azureedge.net/designerapp/images/LiquidLogo.png",
"horizontalAlignment": "Center",
"size": "Small"
}
],
"horizontalAlignment":
"Center"
},
{
"type": "Column",
"width": 10,
"items": [
{
"type":
"TextBlock",
"text": "
[{Title}]({URL})",
"weight":
"Bolder",
"color":
"Accent",
"size":
"Medium",
"maxLines": 3
},
{
"type":
"TextBlock",
"text": "
{ResultSnippet}",
"maxLines": 3,
"wrap": true
}
],
"spacing": "Medium"
}
]
}
],
"$schema":
"http://adaptivecards.io/schemas/adaptive-card.json"
}
}
}
}
]
}
</script>
</head>
<body onload="renderCard()">
<h1>Adaptive Cards Data Binding Example</h1>
<div id="exampleDiv"></div>
</body>
</html>
See also
Create a layout to customize search results
Use the Microsoft Search API to query data
Use the Microsoft Search API to refine
queries with aggregations
Article • 10/20/2022
You can use the Microsoft Search API in Microsoft Graph to refine search results and
show their distribution in the index.
To refine the results, in the search request, specify the aggregationOption. Each
aggregationOption specifies the property on which the aggregation should be
computed and the number of searchBucket items to be returned in the response.
The response includes two searchBucket objects for the two aggregations:
The key property specifies the actual value (by fileType , contentclass , or
lastModifiedTime ) for those matching listItem objects that are aggregated in the
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"listItem"
],
"query": {
"queryString": "test"
},
"from": 0,
"size": 25,
"aggregations": [
{
"field": "fileType",
"size": 20,
"bucketDefinition": {
"sortBy": "count",
"isDescending": "true",
"minimumCount": 0
}
},
{
"field": "contentclass",
"size": 15,
"bucketDefinition": {
"sortBy": "keyAsString",
"isDescending": "true",
"minimumCount": 0
}
},
{
"field": "lastModifiedTime",
"size": 2,
"bucketDefinition": {
"sortBy": "KeyAsString",
"isDescending": "true",
"minimumCount": 0,
"ranges": [
{
"to": "2021-09-01T09:08:19.6224752Z"
},
{
"from": "2021-09-01T09:08:19.6224752Z",
"to": "2021-11-09T09:08:19.6224752Z"
},
{
"from": "2021-11-09T09:08:19.6224752Z"
}
]
}
}
]
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.type": "#microsoft.graph.searchResponse",
"hitsContainers": [
{
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
"..."
],
"total": 9,
"moreResultsAvailable": false,
"aggregations": [
{
"@odata.type":
"#microsoft.substrateSearch.searchAggregation",
"field": "fileType",
"buckets": [
{
"@odata.type":
"#microsoft.substrateSearch.searchBucket",
"key": "docx",
"count": 5,
"aggregationFilterToken": "\"ǂǂ646f6378\""
},
{
"@odata.type":
"#microsoft.substrateSearch.searchBucket",
"key": "xlsx",
"count": 3,
"aggregationFilterToken": "\"ǂǂ786c7378\""
},
{
"@odata.type":
"#microsoft.substrateSearch.searchBucket",
"key": "pptx",
"count": 1,
"aggregationFilterToken": "\"ǂǂ70707478\""
}
]
},
{
"@odata.type":
"#microsoft.substrateSearch.searchAggregation",
"field": "contentclass",
"buckets": [
{
"@odata.type":
"#microsoft.substrateSearch.searchBucket",
"key": "STS_ListItem_DocumentLibrary",
"count": 9,
"aggregationFilterToken":
"\"ǂǂ5354535f4c6973744974656d5f446f63756d656e744c696272617279\""
}
]
},
{
"@odata.type":
"#microsoft.substrateSearch.searchAggregation",
"field": "lastModifiedTime",
"buckets": [
{
"key": "Before 2021-09-01T09:08:19.6224752Z",
"count": 5,
"aggregationFilterToken": "range(min, 2021-09-
01T09:08:19.6224752Z)"
},
{
"key": "From 2021-09-01T09:08:19.6224752Z up to
2021-11-09T09:08:19.6224752Z",
"count": 3,
"aggregationFilterToken": "range(2021-09-
01T09:08:19.6224752Z, 2021-11-09T09:08:19.6224752Z)"
},
{
"key": "2021-11-09T09:08:19.6224752Z or later",
"count": 1,
"aggregationFilterToken": "range(2021-11-
09T09:08:19.6224752Z, max, to=\"le\")"
}
]
}
]
}
]
}
The string value assigned to the aggregationFilters property follows the format "
{field}:\"{aggregationFilterToken}\"". If multiple values for the same filter are required,
the string value assigned to the aggregationFilters property should follow this format : "
{field}:or(\"{aggregationFilterToken1}\",\"{aggregationFilterToken2}\")".
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"driveItem"
],
"query": {
"queryString": "test"
},
"from": 0,
"size": 20,
"aggregations": [
{
"field": "fileType",
"size": 10,
"bucketDefinition": {
"sortBy": "count",
"isDescending": "true",
"minimumCount": 0
}
}
],
"aggregationFilters": [
"fileType:\"ǂǂ68746d6c\"",
"lastModifiedTime:range(2021-09-01T09:08:19.6224752Z, 2021-11-
09T09:08:19.6224752Z)"
]
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.type": "#microsoft.graph.searchResponse",
"hitsContainers": [
{
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
"..."
],
"total": 69960,
"moreResultsAvailable": true,
"aggregations": [
{
"@odata.type":
"#microsoft.substrateSearch.searchAggregation",
"field": "fileType",
"buckets": [
{
"@odata.type":
"#microsoft.substrateSearch.searchBucket",
"key": "html",
"count": 69960,
"aggregationFilterToken": "\"ǂǂ68746d6c\""
}
]
},
{
"@odata.type":
"#microsoft.substrateSearch.searchAggregation",
"field": "lastModifiedTime",
"buckets": [
{
"key": "Before 2021-09-01T09:08:19.6224752Z",
"count": 0,
"aggregationFilterToken": "range(min, 2021-09-
01T09:08:19.6224752Z)"
},
{
"key": "From 2021-09-01T09:08:19.6224752Z up to
2021-11-09T09:08:19.6224752Z",
"count": 69960,
"aggregationFilterToken": "range(2021-09-
01T09:08:19.6224752Z, 2021-11-09T09:08:19.6224752Z)"
},
{
"key": "2021-11-09T09:08:19.6224752Z or later",
"count": 0,
"aggregationFilterToken": "range(2021-11-
09T09:08:19.6224752Z, max, to=\"le\")"
}
]
}
]
}
]
}
The response includes 3 searchBucket objects, one for each size range aggregation:
The 2 buckets of the lower size ranges don't include any search matches.
All 9 search matches have sizes 1000 or higher.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"driveItem"
],
"query": {
"queryString": "test"
},
"from": 0,
"size": 10,
"aggregations": [
{
"field": "Size",
"size": 5,
"bucketDefinition": {
"sortBy": "keyAsNumber",
"isDescending": "true",
"minimumCount": 0,
"ranges": [
{
"to": "100"
},
{
"from": "100",
"to": "1000"
},
{
"from": "1000"
}
]
}
}
]
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.type": "#microsoft.graph.searchResponse",
"hitsContainers": [
{
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
"..."
],
"total": 9,
"moreResultsAvailable": false,
"aggregations": [
{
"@odata.type":
"#microsoft.substrateSearch.searchAggregation",
"field": "Size",
"buckets": [
{
"@odata.type":
"#microsoft.substrateSearch.searchBucket",
"key": "Less than 100",
"count": 0,
"aggregationFilterToken": "range(min, 100)"
},
{
"@odata.type":
"#microsoft.substrateSearch.searchBucket",
"key": "100 up to 1000",
"count": 0,
"aggregationFilterToken": "range(100, 1000)"
},
{
"@odata.type":
"#microsoft.substrateSearch.searchBucket",
"key": "1000 and up",
"count": 9,
"aggregationFilterToken": "range(1000, max,
to=\"le\")"
}
]
}
]
}
]
}
Known limitations
Aggregations are supported only for SharePoint, OneDrive, or external items. They are
not supported for message or event types.
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to request
spelling corrections
Article • 03/07/2023
You can use the Microsoft Search API in Microsoft Graph to request spelling corrections
to handle mismatches between typos in user queries and correct words in matched
contents. To request spelling corrections, specify the following properties in the
queryAlterationOptions property of the searchRequest:
The priority of spelling modification is higher than spelling suggestion if they are both
enabled.
If speller suggestion is disabled while speller modification is enabled, results can still
contain the speller suggestion for the original query with the typo. This is by design,
because the feature provides the spelling suggestion by default if spelling modification
is enabled.
All the user query strings should be the same to enable spelling corrections for searches
of multiple entities.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"listItem"
],
"query": {
"queryString": "accountt"
},
"from": 0,
"size": 25,
"queryAlterationOptions": {
"enableSuggestion": true,
"enableModification": false
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searc
hResponse)",
"value": [
{
"searchTerms": [
"accountt"
],
"hitsContainers": [
{
"total": 0,
"moreResultsAvailable": false
}
],
"queryAlterationResponse": {
"@odata.type":
"#microsoft.substrateSearch.alterationResponse",
"originalQueryString": "accountt",
"queryAlteration": {
"@odata.type":
"#microsoft.substrateSearch.searchAlteration",
"alteredQueryString": "account",
"alteredHighlightedQueryString": "account",
"alteredQueryTokens": [
{
"offset": 0,
"length": 8,
"suggestion": "account"
}
]
},
"queryAlterationType": "Suggestion"
}
}
]
}
In this example, there are no results for the original query with typo accountt . The
response contains results related to corrected string account and alterationResponse
objects for the spelling modification.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"listItem"
],
"query": {
"queryString": "accountt"
},
"from": 0,
"size": 25,
"queryAlterationOptions": {
"enableSuggestion": true,
"enableModification": true
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#Collection(microsoft.graph.searc
hResponse)",
"value": [
{
"searchTerms": [
"account"
],
"hitsContainers": [
{
"total": 1,
"moreResultsAvailable": false,
"hits": [
{
"hitId": "FlULeN/ui/1GjLx1rUfio5UAAEl",
"rank": 1,
"summary": "",
"resource": {
"@odata.type": "#microsoft.graph.listItem",
"createdDateTime": "2019-06-10T06:37:43Z",
"lastModifiedDateTime": "2019-06-
10T06:37:43Z",
"name": "web_part_test_long Notebook",
"webUrl":
"https://contoso.sharepoint.com/sites/contoso-team/Lists/Issue tracker
list/DispForm.aspx?ID=1",
"sharepointIds": {
"listId": "33498de0-d695-4d23-ac26-
e1bf95a3206e",
"listItemId": "13"
},
"createdBy": {
"user": {
"displayName": "System Account"
}
},
"lastModifiedBy": {
"user": {
"displayName": "System Account"
}
},
"parentReference": {
"sharepointIds": {
"listId": "da61a2b0-4120-4a3f-812b-
0fc0d79bf16b"
},
"siteId":
"m365x231305.sharepoint.com,5724d91f-650c-4810-83cc-61a8818917d6,c3ba25dc-
2c9f-48cb-83be-74cdf68ea5a0"
}
}
}
]
}
],
"queryAlterationResponse": {
"@odata.type":
"#microsoft.substrateSearch.alterationResponse",
"originalQueryString": "accountt",
"queryAlteration": {
"@odata.type":
"#microsoft.substrateSearch.searchAlteration",
"alteredQueryString": "account",
"alteredHighlightedQueryString": "account",
"alteredQueryTokens": [
{
"offset": 0,
"length": 8,
"suggestion": "account"
}
]
},
"queryAlterationType": "Modification"
}
}
]
}
Known limitations
Spelling correction is only supported for the following resources: message, event, site,
drive, driveItem, list, listItem, and externalItem.
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to collapse
search results
Article • 01/31/2023
You can use the Microsoft Search API in Microsoft Graph to collapse items in a search
result set. This allows you to display results in a concise, readable way. You can specify
the criteria for collapsing by using the collapseProperties property in a searchRequest
object, which contains one or more collapseProperty parameters to set fields to be
collapsed and limit the size of the results. The collapseProperties property is supported
for the following entity types:
site
drive
driveItem
list
listItem
externalItem
The following table lists the collapse scenarios that you can enable.
Examples
The following table shows a sample list in SharePoint. The examples in this section use
this list to show how the collapseProperties property works.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"listItem"
],
"query": {
"queryString": "note"
},
"fields": [
"filename"
],
"collapseProperties": [
{
"fields": [
"filename"
],
"limit": 3
}
]
}
]
}
Group the items based on Filename and show the top three ("limit": 3) for each group.
As you can see in the following table, the ranking is maintained. The top three and last
three rows remain, but rows four and five are excluded because the collapseProperties
limit is 3.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"listItem"
],
"query": {
"queryString": "note"
},
"fields": [
"filename",
"author"
],
"collapseProperties": [
{
"fields": [
"filename",
"author"
],
"limit": 2
}
]
}
]
}
In the following table, the ranking is maintained, but the results are collapsed by two
properties simultaneously to find unique combinations of Filename and Author. This
results in keeping the first four rows and excluding row five, because the combination of
Note (Filename) and James (Author) is only allowed up to 2 times. The last three rows
remain for the same reason.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"listItem"
],
"query": {
"queryString": "note"
},
"fields": [
"filename",
"author"
],
"collapseProperties": [
{
"fields": [
"filename"
],
"limit": 3
},
{
"fields": [
"author"
],
"limit": 1
}
]
}
]
}
In the following table, the ranking is maintained, but the results are collapsed first on
Filename and then on Author. For the first -evel collapse on Filename, with a limit of 3,
the first three rows remain, rows four and five are removed, and the last three rows
remain as is. For the second-level collapse with a limit of 1, the first three rows don't
change because each has a unique Author value. Row eight is excluded because James
is listed again as Author and that property must have unique values.
Response
When you use collapseProperties, the response contains an isCollapsed Boolean
property for each result. This property indicates the collapse state of the result.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"searchTerms": [
"note"
],
"hitsContainers": [
{
"hits": [
{
"hitId": "94149344-55e4-4678-b22a-b37a9ed1ffff",
"rank": 1,
"isCollapsed": true,
"summary": "",
"resource": {
"@odata.type": "#microsoft.graph.listItem",
"sharepointIds": {
"listId": "9b786f01-4668-4862-8bbf-
443159c0ffff",
"listItemId": "3"
},
"id": "94149344-55e4-4678-b22a-
b37a9ed1ffff",
"createdDateTime": "2012-10-10T12:07:57Z",
"lastModifiedDateTime": "2022-11-
30T08:38:47Z",
"parentReference": {
"id":
"01PPFMTLYPOGQADPQCOJAJTXZLKETTQP6F",
"siteId": "microsoftapc-
my.sharepoint.com,5b8af7a0-0c23-4719-ab6c-457c2104ea8a,2e4df0d0-c83a-473b-
bed1-2d2046966d31"
},
"webUrl": "https://microsoftapc-
my.sharepoint.com/Documents/Notes"
}
}
],
"total": 4281349,
"moreResultsAvailable": true
}
]
}
],
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.searc
hResponse)"
}
Known limitations
The collapseProperties property is not supported for the following resources:
message,chatMessage, event, person, externalItem, bookmark, acronym or qna.
Next steps
Use the Microsoft Search API to query data
Collapse search results in SharePoint
Use the Microsoft Search API to trim
duplicate search results
Article • 06/28/2022
You can use the Microsoft Search API in Microsoft Graph to trim duplicate search results.
Specify the trimDuplicates property in a searchRequest object to trim away the
duplicate search results. The trimDuplicates property is only supported on files hosted
in SharePoint. The default value is false .
Example
The following example shows a request that searches for files hosted in SharePoint and
uses the trimDuplicates property to trim away the duplicate search results.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"driveItem"
],
"query": {
"queryString": "Adatum Corporation"
},
"trimDuplicates": true
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.type": "#microsoft.graph.searchResponse",
"searchTerms": [
"Adatum",
"Corporation"
],
"hitsContainers": [
{
"total": 2,
"moreResultsAvailable": false,
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "01VRZMWHPGDM5KTXS53RF3SSGHW7SGGPKL",
"rank": 1,
"summary": "Unique Item 1 which created by Adatum
Corporation ",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"size": 971838,
"fileSystemInfo": {
"createdDateTime": "2020-07-22T21:14:59Z",
"lastModifiedDateTime": "2018-09-12T16:20:16Z"
},
"id": "01VRZMWHPGDM5KTXS53RF3SSGHW7SGGPKL",
"createdBy": {
"user": {
"displayName": "Adatum Corporation"
}
},
"createdDateTime": "2020-07-22T21:14:59+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Adatum Corporation"
}
},
"lastModifiedDateTime": "2018-09-12T16:20:16+00:00",
"name": "Adatum Corporation Name",
"parentReference": {
"siteId": "Contoso066a,5724d91f-650c-4810-83cc-
61a8818917d6,c3ba25dc-2c9f-48cb-83be-74cdf68ea5a0",
"driveId": "b!NAe_rKr80k-
n7e5zlCVIqSnIwTNsGBVBlusjEvRHgjMmmcA3Ubc7R4Kyao9hbgL4",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl": "http://www.adatum.com/"
}
},
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "01BTQFB3LHZTAYBV2VXVEK22ETF5WOQGT2",
"rank": 2,
"summary": "Unique item 2 which modified by Adatum
Corporation",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"size": 34428,
"fileSystemInfo": {
"createdDateTime": "2020-07-22T21:23:50Z",
"lastModifiedDateTime": "2012-10-29T17:52:10Z"
},
"id": "01BTQFB3LHZTAYBV2VXVEK22ETF5WOQGT2",
"createdBy": {
"user": {
"displayName": "Adventure Works Cycles"
}
},
"createdDateTime": "2020-07-22T21:23:50+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Adatum Corporation"
}
},
"lastModifiedDateTime": "2012-10-29T17:52:10+00:00",
"name": "Adventure Works Cycles Name",
"parentReference": {
"siteId": "Contoso066a,893378cb-d2cd-4076-a2c9-
e50587a26832,04120cf2-7863-4701-8541-eb26266a25e6",
"driveId":
"b!H9kkVwxlEEiDzGGogYkX1twlusOfLMtIg750zfaOpaBq9eOBX6MXQapv1hTT-bIt",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl": "http://www.adventure-works.com/"
}
}
]
}
]
}
Known limitations
The trimDuplicates property is not supported for the following resources: message,
event, and externalItem.
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to search
content using query templates
Article • 06/28/2022
You can use query templates in the Microsoft Search API in Microsoft Graph to search
for content based on query variables and KQL. This allows you to restrict the query
scope and build your own search experience.
Example
The following example shows a request that uses a query template to search for content
based on a query variable and KQL.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"driveItem"
],
"query": {
"queryString": "contoso",
"queryTemplate":"({searchTerms}) AuthorOWSUSER:Adventure"
}
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.type": "#microsoft.graph.searchResponse",
"searchTerms": [
"contoso"
],
"hitsContainers": [
{
"total": 2,
"moreResultsAvailable": false,
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "01VRZMWHPGDM5KTXS53RF3SSGHW7SGGPKL",
"rank": 1,
"summary": "As we work to become a more <ddd/> We
<c0>test</c0> samples from the region between 10 and 100 times per day
<ddd/> and surrounding areas that CPU uses to <c0>test</c0> the quality of
your drinking water every day <ddd/> contoso",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"size": 971838,
"fileSystemInfo": {
"createdDateTime": "2020-07-22T21:14:59Z",
"lastModifiedDateTime": "2018-09-12T16:20:16Z"
},
"id": "01VRZMWHPGDM5KTXS53RF3SSGHW7SGGPKL",
"createdBy": {
"user": {
"displayName": "Adventure Works Cycles"
}
},
"createdDateTime": "2020-07-22T21:14:59+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Adventure Works Cycles"
}
},
"lastModifiedDateTime": "2018-09-12T16:20:16+00:00",
"name": "Adventure Works Cycles Name",
"parentReference": {
"siteId": "Contoso066a,5724d91f-650c-4810-83cc-
61a8818917d6,c3ba25dc-2c9f-48cb-83be-74cdf68ea5a0",
"driveId": "b!NAe_rKr80k-
n7e5zlCVIqSnIwTNsGBVBlusjEvRHgjMmmcA3Ubc7R4Kyao9hbgL4",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl": "http://www.adventure-works.com/"
}
},
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "01BTQFB3LHZTAYBV2VXVEK22ETF5WOQGT2",
"rank": 2,
"summary": "QT300 Accessories Specs Costs Chart Continue
<ddd/> 16 Package 5 14 Grand Total 99 Results Data <c0>Test</c0> Group
Gender <c0>Test</c0> Option 1 2 3 18-25 Male Package 4 Color <ddd/> ",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"size": 34428,
"fileSystemInfo": {
"createdDateTime": "2020-07-22T21:23:50Z",
"lastModifiedDateTime": "2012-10-29T17:52:10Z"
},
"id": "01BTQFB3LHZTAYBV2VXVEK22ETF5WOQGT2",
"createdBy": {
"user": {
"displayName": "Adventure Works Cycles"
}
},
"createdDateTime": "2020-07-22T21:23:50+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Adatum Corporation"
}
},
"lastModifiedDateTime": "2012-10-29T17:52:10+00:00",
"name": "Adatum Corporation Name",
"parentReference": {
"siteId": "Contoso066a,893378cb-d2cd-4076-a2c9-
e50587a26832,04120cf2-7863-4701-8541-eb26266a25e6",
"driveId":
"b!H9kkVwxlEEiDzGGogYkX1twlusOfLMtIg750zfaOpaBq9eOBX6MXQapv1hTT-bIt",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl": "http://www.adatum.com/contoso"
}
}
]
}
]
}
Next steps
Use the Microsoft Search API to query data
Use the Microsoft Search API to sort
search results
Article • 10/20/2022
You can use the Microsoft Search API in Microsoft Graph to sort search results. To sort
the results, specify the sortProperties property in a searchRequest object and identify a
resource property in entityTypes to sort matches by, in ascending or descending order.
Sorting is supported for SharePoint and OneDrive items. The property of SharePoint and
OneDrive items to be sorted on should be sortable in the search schema.
Sorting is also supported for external items. The property of external items to be sorted
on should be refinable in the search schema.
The default sort order is ascending. Set the isDescending property to change it.
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"driveItem"
],
"query": {
"queryString": "contoso"
},
"sortProperties": [
{
"name": "CreatedDateTime",
"isDescending": false
}
]
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.type": "#microsoft.graph.searchResponse",
"searchTerms": [
"test"
],
"hitsContainers": [
{
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "01VRZMWHPGDM5KTXS53RF3SSGHW7SGGPKL",
"rank": 1,
"summary": "As we work to become a more <ddd/> We
<c0>test</c0> samples from the region between 10 and 100 times per day
<ddd/> and surrounding areas that CPU uses to <c0>test</c0> the quality of
your drinking water every day <ddd/> ",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"size": 971838,
"fileSystemInfo": {
"createdDateTime": "2020-07-22T21:14:59Z",
"lastModifiedDateTime": "2018-09-12T16:20:16Z"
},
"id": "01VRZMWHPGDM5KTXS53RF3SSGHW7SGGPKL",
"createdBy": {
"user": {
"displayName": "Contoso066a"
}
},
"createdDateTime": "2020-07-22T21:14:59+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Contoso066a"
}
},
"lastModifiedDateTime": "2018-09-12T16:20:16+00:00",
"name": "Our Water Our Future.docx",
"parentReference": {
"siteId": "Contoso066a,5724d91f-650c-4810-83cc-
61a8818917d6,c3ba25dc-2c9f-48cb-83be-74cdf68ea5a0",
"driveId": "b!NAe_rKr80k-
n7e5zlCVIqSnIwTNsGBVBlusjEvRHgjMmmcA3Ubc7R4Kyao9hbgL4",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl":
"https://Contoso066a/sites/GlobalSales/Shared Documents/Q1 2019/Our Water
Our Future.docx"
}
},
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "01BTQFB3LHZTAYBV2VXVEK22ETF5WOQGT2",
"rank": 2,
"summary": "QT300 Accessories Specs Costs Chart Continue
<ddd/> 16 Package 5 14 Grand Total 99 Results Data <c0>Test</c0> Group
Gender <c0>Test</c0> Option 1 2 3 18-25 Male Package 4 Color <ddd/> ",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"size": 34428,
"fileSystemInfo": {
"createdDateTime": "2020-07-22T21:23:50Z",
"lastModifiedDateTime": "2012-10-29T17:52:10Z"
},
"id": "01BTQFB3LHZTAYBV2VXVEK22ETF5WOQGT2",
"createdBy": {
"user": {
"displayName": "Contoso066a"
}
},
"createdDateTime": "2020-07-22T21:23:50+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Contoso066a"
}
},
"lastModifiedDateTime": "2012-10-29T17:52:10+00:00",
"name": "QT300 Accessories Specs.xlsx",
"parentReference": {
"siteId": "Contoso066a,893378cb-d2cd-4076-a2c9-
e50587a26832,04120cf2-7863-4701-8541-eb26266a25e6",
"driveId":
"b!H9kkVwxlEEiDzGGogYkX1twlusOfLMtIg750zfaOpaBq9eOBX6MXQapv1hTT-bIt",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl":
"https://Contoso066a/sites/contosoteam/Shared Documents/QT300 Accessories
Specs.xlsx"
}
}
]
}
]
}
Request
HTTP
POST https://graph.microsoft.com/beta/search/query
Content-Type: application/json
{
"requests": [
{
"entityTypes": [
"microsoft.graph.driveItem"
],
"query": {
"queryString": "contoso"
},
"sortProperties": [
{
"name": "name",
"isDescending": false
},
{
"name": "CreatedDateTime",
"isDescending": false
}
],
"from": 0,
"size": 20
}
]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.type": "#microsoft.graph.searchResponse",
"searchTerms": [
"test"
],
"hitsContainers": [
{
"@odata.type": "#microsoft.graph.searchHitsContainer",
"hits": [
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "01D6DZBXUX6RQ2OM7AIVEJFRQTD3W75L7V",
"rank": 1,
"summary": "If you are projecting to a second monitor,
use Presenter View on your PC to read the talk track and see where to click
next (note that this is a PowerPoint, so the “clicks” are <ddd/> ",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"size": 34122491,
"fileSystemInfo": {
"createdDateTime": "2020-07-22T21:48:38Z",
"lastModifiedDateTime": "2019-01-11T22:41:06Z"
},
"id": "01D6DZBXUX6RQ2OM7AIVEJFRQTD3W75L7V",
"createdBy": {
"user": {
"displayName": "Contoso066a"
}
},
"createdDateTime": "2020-07-22T21:48:38+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Contoso066a"
}
},
"lastModifiedDateTime": "2019-01-11T22:41:06+00:00",
"name": "Build an Approval Process with Microsoft
Flow Click Through.pptx",
"parentReference": {
"siteId": "Contoso066a,506e4b2b-4af3-41e6-904c-
668e67911889,04120cf2-7863-4701-8541-eb26266a25e6",
"driveId":
"b!K0tuUPNK5kGQTGaOZ5EYifIMEgRjeAFHhUHrJiZqJeZq9eOBX6MXQapv1hTT-bIt",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl":
"https://Contoso066a/sites/DigitalInitiativePublicRelations/Shared
Documents/General/PowerApps/Build an Approval Process with Microsoft Flow
Click Through.pptx"
}
},
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "013C7INN2ZPRBMXUAPJNDKMJ2YHTGQLXJT",
"rank": 2,
"summary": "You can use the Office Add-ins platform to
build solutions that extend Office applications and interact with content in
Office documents <ddd/> Your solution can run in Office across <ddd/> ",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"size": 7816159,
"fileSystemInfo": {
"createdDateTime": "2020-07-27T11:20:22Z",
"lastModifiedDateTime": "2017-09-15T14:20:00Z"
},
"id": "013C7INN2ZPRBMXUAPJNDKMJ2YHTGQLXJT",
"createdBy": {
"user": {
"displayName": "Contoso066a"
}
},
"createdDateTime": "2020-07-27T11:20:22+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Contoso066a"
}
},
"lastModifiedDateTime": "2017-09-15T14:20:00+00:00",
"name": "CR -227 Camera briefing.docx",
"parentReference": {
"siteId": "Contoso066a,7955f1b7-70eb-4a26-8fa7-
313ad3a45126,04120cf2-7863-4701-8541-eb26266a25e6",
"driveId":
"b!t_FVeetwJkqPpzE606RRJvIMEgRjeAFHhUHrJiZqJeYmmcA3Ubc7R4Kyao9hbgL4",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl":
"https://Contoso066a/sites/Mark8ProjectTeam/Shared Documents/Research and
Development/CR -227 Camera briefing.docx"
}
},
{
"@odata.type": "#microsoft.graph.searchHit",
"hitId": "013C7INN67OOARDMIO3BE23AHO3AMCC62W",
"rank": 3,
"summary": "<c0>Test</c0> Credit Card Account Numbers
<ddd/> While testing, use only the credit card numbers listed <ddd/> a
different character count than the other <c0>test</c0> numbers, it is the
correct and functional <ddd/> ",
"resource": {
"@odata.type": "#microsoft.graph.driveItem",
"size": 22418,
"fileSystemInfo": {
"createdDateTime": "2020-07-27T11:22:11Z",
"lastModifiedDateTime": "2016-06-09T16:23:00Z"
},
"id": "013C7INN67OOARDMIO3BE23AHO3AMCC62W",
"createdBy": {
"user": {
"displayName": "Contoso066a"
}
},
"createdDateTime": "2020-07-27T11:22:11+00:00",
"lastModifiedBy": {
"user": {
"displayName": "Contoso066a"
}
},
"lastModifiedDateTime": "2016-06-09T16:23:00+00:00",
"name": "Manufacturing and delivery plan.docx",
"parentReference": {
"siteId": "Contoso066a,7955f1b7-70eb-4a26-8fa7-
313ad3a45126,04120cf2-7863-4701-8541-eb26266a25e6",
"driveId": "b!NAe_rKr80k-
n7e5zlCVIqfIMEgRjeAFHhUHrJiZqJeYmmcA3Ubc7R4Kyao9hbgL4",
"sharepointIds": {
"listId": "c61d1892-ca82-4f53-b16f-
6bb8a379e2b2",
"listItemId": "1027",
"listItemUniqueId": "E320AFEB-AD73-46A2-
83D7-985FAA4B206D"
}
},
"webUrl":
"https://Contoso066a/sites/Mark8ProjectTeam/Shared Documents/Research and
Development/Manufacturing and delivery plan.docx"
}
}
]
}
]
}
Known limitations
Sort is not supported for message and event.
Sort by relevance cannot be specified in sortProperties.
Next steps
Use the Microsoft Search API to query data
Supported language codes
Article • 04/28/2023
For Microsoft Search APIs in Microsoft Graph, the Accept-Language HTTP request header
provides a list of acceptable human languages for the response. The value is used for
localization on the server side. The following table lists the supported Accept-Language
header values.
af Afrikaans
am Amharic
as Assamese
be Belarusian
bg Bulgarian
bs Bosnian (Latin)
ca Catalan Spanish
ca-ES-valencia Valencian
cs Czech
cy Welsh
da Danish
de German (Germany)
el Greek
es Spanish (Spain)
et Estonian
eu Basque
fa Persian
fi Finnish
fil-Latn Filipino
fr French (France)
ga Irish
gl Galician
gu Gujarati
he Hebrew
hi Hindi
hr Croatian
hu Hungarian
hy Armenian
id Indonesian
ig-Latn Igbo
is Icelandic
it Italian (Italy)
Accept-Language header string Language
ja Japanese
ka Georgian
kk Kazakh
km Khmer
kn Kannada
ko Korean
kok Konkani
ky-Cyrl Kyrgyz
lb Luxembourgish
lt Lithuanian
lv Latvian
mi-Latn Maori
mk Macedonian
ml Malayalam
mr Marathi
ms Malay (Malaysia)
mt Maltese
nb Norwegian (Bokmål)
ne Nepali (Nepal)
nl Dutch (Netherlands)
nn Norwegian (Nynorsk)
or Odia
pa Punjabi (Gurmukhi)
pl Polish
prs-Arab Dari
qut-Latn K’iche’
ro Romanian (Romania)
ru Russian
rw Kinyarwanda
si Sinhala
sk Slovak
sl Slovenian
sq Albanian
sv Swedish (Sweden)
sw Kiswahili
ta Tamil
te Telugu
th Thai
Accept-Language header string Language
ti Tigrinya
tn Setswana
tr Turkish
ug-Arab Uyghur
uk Ukrainian
ur Urdu
vi Vietnamese
wo Wolof
xh isiXhosa
yo-Latn Yoruba
zu isiZulu
Examples
We will support the format language-region e.g. en-US. Multiple languages also can be
listed by using commas and given an associated quality value which represents an
estimate of the user's preference for the languages specified by that range e.g. en-US,
fr-FR;q=0.9. The quality value defaults to "q=1".
HTTP
POST /search/query
Content-Type: application/json
Accept-Language: en-US, fr-FR;q=0.9
Known limitations
If no Accept-Language header is present in the request, the server assumes that all
languages are equally acceptable. If an Accept-Language header is present, then
all languages which are assigned a quality factor greater than 0 are acceptable.
See also
Use the Microsoft Search API to query data
Microsoft Graph security API overview
Article • 09/08/2022
You can use the Microsoft Graph security API to connect Microsoft security products,
services, and partners to streamline security operations and improve threat protection,
detection, and response capabilities.
The Microsoft Graph security API is an intermediary service (or broker) that provides a
single programmatic interface to connect multiple Microsoft Graph security providers
(also called security providers or providers). Requests to the Microsoft Graph security
API are federated to all applicable security providers. The results are aggregated and
returned to the requesting application in a common schema, as shown in the following
diagram. For details, see Microsoft Graph security API data flow.
For information about authorization, see Authorization and the Microsoft Graph security
API. For information about permissions, including delegated and application
permissions, see Permissions.
https://www.youtube-nocookie.com/embed/oYXPGwH9Ho0
In many organizations, eDiscovery workflows are frequent, critical, and high volume. In
the cases where there are common repeated tasks or a high volume of activities, the
APIs will help provide a scalable way to repeat processes consistently and effectively.
Many organizations handle a high volume of cases and eDiscovery requests and would
prefer to automate some tasks. The Microsoft Graph APIs for advanced eDiscovery
provide API access to most functions available within the Microsoft Purview eDiscovery
(premium) solution.
Depending on the current systems and processes in place, organizations might have
various priorities for automation and integration, from upstream processes such as case
creation, to downstream such as collection, review set queries, or export. Supporting
workflows with APIs throughout the advanced eDiscovery workflow provides flexibility
and options.
Create custom reporting to track case load and progress from individual cases.
Area Benefits
Area Benefits
API reference
Looking for the API reference for this service?
Next steps
Explore Microsoft Graph security API samples
Interested in becoming a security provider? Reach out to graphsecfeedback.
Microsoft Graph Security API data flow
Article • 06/28/2022
The Microsoft Graph Security API federates requests to all providers in the Microsoft
Graph security ecosystem. This is based on the security provider consent provided by
the application, as shown in the following diagram. The consent workflow only applies
to non-Microsoft providers.
1. The application user signs in to the provider application to view the consent form
from the provider. This consent form experience or UI is owned by the provider
and applies to non-Microsoft providers only to get explicit consent from their
customers to send requests to Microsoft Graph Security API.
2. The client consent is stored on the provider side.
3. The provider consent service calls the Microsoft Graph Security API to inform
consent approval for the respective customer.
4. The application sends a request to the Microsoft Graph Security API.
5. The Microsoft Graph Security API checks for the consent information for this
customer mapped to various providers.
6. The Microsoft Graph Security API calls all those providers the customer has given
explicit consent to via the provider consent experience.
7. The response is returned from all the consented providers for that client.
8. The result set response is returned to the application.
9. If the customer has not consented to any provider, no results from those providers
are included in the response.
Authorization and the Microsoft Graph
Security API
Article • 06/28/2022
Security data accessible via the Microsoft Graph Security API is sensitive and protected
by both permissions and Azure Active Directory (Azure AD) roles.
7 Note
This option can also support cases where Role-Based Access Control (RBAC) is
managed by the application.
If you're calling the Microsoft Graph Security API from Graph Explorer:
The Azure AD tenant admin must explicitly grant consent for the requested
permissions to the Graph Explorer application.
The user must be a member of the Security Reader Limited Admin role in Azure AD
(either Security Reader or Security Administrator).
7 Note
If you're calling the Microsoft Graph Security API from a custom or your own
application:
The Azure AD tenant admin must explicitly grant consent to your application. This
is required both for application-level authorization and user delegated
authorization.
If you're using user delegated authorization, the user must be a member of the
Security Reader or Security Administrator Limited Admin role in Azure AD.
Who Action
Application developer Sign in as the user and use the application to access the Microsoft
Graph Security API.
Application registration only defines which permissions the application needs in order to
run. It does NOT grant these permissions to the application.
The Azure AD tenant administrator MUST explicitly grant the permissions to the
application. This must be done per tenant and must be performed every time the
application permissions are changed in the application registration portal.
For example, assume that you have an application, two Azure AD tenants, T1 and T2,
and two permissions, P1 and P2. The following is the authorization process:
When users in tenant T1 get an Azure AD token for this application, the token does
not contain any permissions.
When users in tenant T2 get an Azure AD token for the application, the token does
not contain any permissions because the admin of tenant T2 did not yet grant
permissions to the application. Permission must be granted per tenant and per
application.
The application has its registration changed to now require permissions P1 and P2.
When users in tenant T1 get an Azure AD token for the application, it only contains
permission P1. Permissions granted to an application are recorded as snapshots of
what was granted; they do not change automatically after the application
registration (permission) changes.
7 Note
The Azure AD tokens for the application in tenant T1 and the application in
tenant T2 contain different permissions, because each tenant admin has
granted different permissions to the application.
To make the application work again in tenant T1, the admin of tenant T1 must
explicitly grant permissions P1 and P2 to the application.
7 Note
3. On the registration page for the new application, enter a value for Name and
select the account types you wish to support. In the Redirect URI field, enter the
redirect URL.
4. Select Register to create the app and view its overview page. *
6. Select Add a permission and then choose Microsoft Graph in the flyout. Select
Delegated permissions. Use the search box to find and select the required
permissions. For a list of permissions, see Security permissions.
7 Note
The Microsoft Graph Security API requires the *.Read.All scope for GET
queries, and the *.ReadWrite.All scope for PATCH/POST/DELETE queries.
Application (client) ID
Redirect URL
List of required permissions
*Windows Defender Advanced Threat Protection (WDATP) requires additional user roles
than what is required by the Microsoft Graph Security API; therefore, only the users in
both WDATP and Microsoft Graph Security API roles can have access to the WDATP
data. Application-only authentication is not limited by this; therefore, we recommend
that you use an app-only authentication token.
For more information, see Register your app with the Microsoft identity platform.
Application ID: The application ID from the Azure application registration portal.
Redirect URL: The string you set in the Azure application registration portal for
authentication response.
https://login.microsoftonline.com/common/adminconsent?client_id=<Application
Id>&state=12345&redirect_uri=<Redirect URL>
In a web browser, go to this URL, and sign in as a tenant administrator. The dialog
box shows the list of permission the application requires, as specified in the
application registration portal. Choose OK to grant the application these
permissions.
7 Note
This step grants permissions to the application, not to users. This means that
all users belonging to the Azure AD tenant that use this application will be
granted these permissions—even non-admin users.
7 Note
The following table lists resources that you can use to create an authentication code.
Web apps - JavaScript SPA Microsoft Authentication Library for JavaScript Preview
Type of application Authentication library
For applications that don't use any of the existing libraries, see Get access on behalf of a
user.
1. Get a code from Azure AD. The query to call contains parameter for Application ID,
Redirect URl, and required permissions.
2. Use the code to get an access token.
If you use OpenId Connect library, see Authenticate using Azure AD and OpenID
Connect and call app.UseOpenIdConnectAuthentication() .
7 Note
If you're requesting user delegated authentication tokens, the parameter for the
library is Requested Scopes. Use User.Read for this parameter instead of what the
registered application requires. The Requested Scopes parameter does NOT affect
the permissions contained in the returned authentication tokens. These are
determined by the permissions that the tenant admin granted the application.
For example, if you're using the .NET MSAL library, call the following:
7 Note
This example should use the least privileged permission, such as User.Read.
However, the returned access token can contain permissions that were granted by
the tenant admin for the current user tenant, such as User.Read.All or
User.ReadWrite.All.
The response from Microsoft Graph contains a header called client-request-id, which is a
GUID. If access is denied, please specify this GUID when seeking support at Microsoft
Tech Community , so we can help investigate the cause of this authentication failure.
Security solution integrations using the
Microsoft Graph Security API
Article • 10/07/2022
You can connect with the Microsoft Graph Security API using any of the following
options. These options enable you to work with data in a unified format across
supported Microsoft and partner security providers through a single integration:
Use the supported integration options: Refer to the list of supported integration
options such as writing code to directly connect your application to derive rich
insights. Leverage samples to get started.
Use native integrations and connectors built by Microsoft partners: Refer to the
Microsoft Graph Security API partner solutions to use these integrations.
Use connectors built by Microsoft: Refer to the list of connectors that you can use
to connect with the API through a variety of solutions for Security Incident and
Management (SIEM), Security Response and Orchestration (SOAR), Incident
Tracking and Service Management (ITSM), reporting, and so on.
SIEM Splunk Microsoft Graph Security API Add-On for Blog post
Enterprise and Splunk Splunk on
Splunk Cloud Cloud blog
post
SOAR Azure Logic Microsoft Graph Security connector for Blog post
Apps / Microsoft Azure Logic Apps, Microsoft Flow and Power
Flow Apps
API reference
Looking for the API reference for this service?
Next steps
Select and try Information Protection labeling sample queries in Graph Explorer.
Choose Show more samples in the column on the left. Use the menu to turn on
Microsoft Purview Information Protection.
Partnering opportunities with the
Microsoft Graph Security API
Article • 06/28/2022
This article describes partnering opportunities enabled by the Microsoft Graph Security
API. It is designed to help product managers and business development roles
understand investment paths and provide insight into partnering value propositions.
Background
Most organizations deal with high volumes of security data and have dozens of security
solutions in their enterprise, making the task of integrating various products and
services daunting and complex. These challenges hinder the ability for organizations to
move quickly when detecting and remediating threats in a world of fast-moving,
disruptive attacks.
Technology partners can integrate with the Microsoft platform using the Microsoft
Graph Security API to address these customer challenges.
The security API is part of the Microsoft Graph, which is a unified REST API for
integrating data and intelligence from Microsoft and partner products and services.
Using Microsoft Graph, customers and partners can rapidly build solutions that
authenticate once and use a single API call to access or act on security insights from
multiple security solutions. Additional value is uncovered when you explore the other
Microsoft Graph entities (Microsoft 365, Azure Active Directory, Intune, and more) to tie
business context with your security insights.
1. As a consumer of information from Microsoft Graph, you can enrich your solutions
with information contained in Microsoft Graph as well as use the Microsoft Graph
API to perform tasks on behalf of a customer.
2. You can also contribute your alerts and actions to Microsoft Graph alongside
Microsoft providers.
Enable others to integrate with your Alerts from your Security Actions for
products through the Microsoft Graph security products your security product
Security API.
Let’s delve a little deeper and explore some common scenarios where Microsoft Graph
Security API integration magnifies security integration investments and the benefits to
customers that we can achieve together.
Supported entities:
Alerts are “conclusions with a security impact” rather than raw log data or other
uncorrelated information. Learn more.
Threat Indicators, also referred to as indicators of compromise or IoCs, represent
data about known threats, such as malicious files, URLs, domains, and IP addresses.
Customers may generate indicators through internal threat intelligence gathering
or acquire indicators from threat intelligence communities, licensed feeds, and
other sources. Learn more.
Security Actions enable technology partners to expose functional capabilities via
the Graph. For example, if your security solution supports the ability to block IP
addresses you can expose “Block IP” as a capability in the Graph. Other Graph
Security API products can call your action via the Graph. Learn more.
Secure Score… Learn more.
Get Alerts – Get alert information with filtering as needed. For example: Show me
all the high priority alerts, or “all the high priority alerts” for a specific user, host,
etc.
Update Alert Status – Enabling management of an alert lifecycle. For example:
setting an alerts status to “resolved” from “in progress” or adding comments to an
alert.
Get Secure Score – Microsoft Secure Score is a “credit rating” type value for
security configurations of Microsoft Products.
Subscribe - Allowing notification of changes to alerts or queries.
Feed custom threat indicators - Automatically send your threat indicators to
Microsoft security solutions to enable Alert, Block, or Allow actions. Use the
Microsoft Graph Security API directly or leverage integrations with leading threat
intelligence platforms.
Invoke a Microsoft Graph Security Action – Take immediate action to defend
against threats using the Microsoft Graph Security securityActions entity.
Provider scenarios are widely varied. A curated onboarding process begins with
identifying relevant scenarios. Once scenarios are agreed upon, documentation, sample
code and development environments are available to support development of your
Microsoft Graph Security Provider.
Get started
Sample code
Microsoft Graph Security samples
Contribute to Microsoft Graph Security samples
Getting to market
Microsoft Partner Network – The primary program for partnering with Microsoft
is the Microsoft Partner Network. Microsoft Graph Security integrations fall into the
MPN Independent Software Vendor (ISV) track.
Microsoft Intelligent Security Association is the program specifically for
Microsoft Security Partners to help enrich your security products and improve
customer discoverability of your integrations to Microsoft Security products.
Microsoft AppSource – As a Microsoft Graph Security API partner, you can list your
Microsoft Graph integration in the Microsoft AppSource Marketplace .
SharePoint sites and content API
overview
Article • 06/28/2022
SharePoint is your mobile, intelligent intranet. With SharePoint, users can share and
manage content, knowledge, and applications to empower teamwork, find information,
and collaborate across an organization. You can use the SharePoint REST API in
Microsoft Graph to integrate your solutions with SharePoint sites and content.
Team sites that store the content that users collaborate on with their coworkers.
Communication sites and portals where users publish rich content pages to share
across the organization.
The SharePoint Framework provides a way to build web parts using client-side
technologies and open source tooling that can be hosted on SharePoint pages.
SharePoint Add-ins are self-contained extensions that can be added to a
SharePoint site without the need for custom code to run on the server.
When your app runs within a SharePoint page, you can easily use Microsoft Graph to
access data across Microsoft 365.
To learn about these models in more detail, visit the SharePoint Dev Center or the
SharePoint Developer Docs.
API reference
Looking for the API reference for this service?
Next steps
Get started with SharePoint in Microsoft Graph by learning more about working with
sites.
Planner tasks and plans API overview
Article • 01/11/2023
The Planner API in Microsoft Graph provides a simple and visual way for teams to
organize their work. Customers can use Planner to create plans, organize and assign
tasks, share progress, and collaborate on content. Planner provides several interactive
experiences including a task board, a charts page, and a schedule view, as well as
integrations throughout Microsoft 365.
Planner itself is also powered by the Microsoft Graph and the Microsoft 365 group
service. Files that you upload and attach to Planner tasks are stored in SharePoint.
Planner comments are based on Outlook group conversations.
API reference
Looking for the API reference for this service?
Planner API in Microsoft Graph v1.0
Planner API in Microsoft Graph beta
Next steps
Work with plans
Work with tasks
Business scenarios API overview
(preview)
Article • 01/11/2023
The business scenarios API allows apps to model and integrate real work business
processes with a Microsoft 365 service over Microsoft Graph. Business scenarios allow
applications to create data in the form of existing Microsoft Graph entities in the tenant;
however, they can specify behaviors for this data to make sure that the requirements of
the represented business process can be met. While the data created for the scenario
behaves in accordance with the scenario rules, other applications can consume this data
the same way they consume other data for the same entity types. Business scenario
applications can work at the tenant level, without having access to the tenant data,
outside of the data created for a specific scenario.
API reference
Looking for the API reference for this service?
Next Steps
Get started using business scenarios to integrate data into Microsoft Planner.
Configuring task recurrence in Planner
(preview)
Article • 04/01/2023
This article describes how to use recurrence with Planner tasks to automate the creation
of repetitive tasks. The recurrence property on a Planner task allows users to automate
the creation of future tasks that represent real-life tasks that need to be completed
repetitively.
User scenarios
The following scenarios are supported:
Continue a series. Marking a task complete results in the generation of a new task
to continue the series, according to the recurrence schedule. If the active task in a
series is deleted, the user should be prompted to determine whether they want to
continue or terminate the series. If the client doesn't know about recurrence and
doesn't offer a prompt, the series should continue. It shouldn't be terminated
accidentally.
The report and its associated task are due every 2 weeks on Friday; the series started on
May 14, 2021. The first report is due on that date, Friday, May 14. Fast forward to
January 7, 2022, 34 weeks later. The person who did the reports took some time off in
December, and nobody completed the reports. The current recurring task (and
corresponding report) is due on December 10. The report and its associated task are
now 4 weeks overdue.
Note: At this point, the contrast between recurring meetings and events becomes
apparent. Meetings don't need to be marked complete in order for an automated
system to schedule the next meeting on the calendar. Completing an overdue task
can generate another task that is due in the past, but there is no concept of
completing a meeting in the past. The next instance of a meeting is always in the
future, based on today's date. The today's date isn't used to calculate due dates of
recurring tasks, in order to avoid losing track of late work.
For this task, if the recurrence schedule isn't edited, and the December 10 task is marked
complete, the next task for the series is instantiated with a due date of December 24.
However, suppose a decision is made that going forward, this report should be done
every 3 weeks, rather than every 2 weeks. The decision might even be that the 3-week
cadence should be retroactive for the overdue reports. This change invites different
possible options for how the continuation of the series can be defined:
The following is the current state of the recurring task, and decision:
Given the context, two options are possible, and both are valid customer stories for how
the series can be changed to accommodate the new 3-week cadence.
Option 1: Change the December 10 task to be due 3 weeks after the previous November
26 task. The current task has its due date changed to December 17, and the following
task is due on January 7.
Option 2: Keep the current December 10 due date, and change the cadence for the
following task that is due on December 31.
Planner supports both of these options; today's date doesn't factor into how these
different cases are handled. This example is explored further in Example 1: Changing the
pattern with and without changes to patternStartDateTime.
Definitions
The following terms are used to discuss and describe Planner tasks with recurrence:
A task with active recurrence (call it task A) can trigger the recurrence mechanism of the
service that creates a new task (task B) to continue the recurring series. When that
happens, task A has its recurrence.nextInSeriesTaskId set to the ID of task B. Because
task A no longer meets condition 2, it no longer has active recurrence. Task A can never
have active recurrence ever again, as nextInSeriesTaskId is a read-only property and the
service never deletes its value.
Tasks sharing the same recurrence.seriesId belong to the same recurrence series.
Each task in the series has a distinct recurrence.occurenceId.
The first task in the series has an occurrenceId of 1 .
When the first task has its recurrence mechanism triggered (by being marked
complete or deleted, while it has active recurrence), then the second task is created
with an occurenceId of 2 . This process continues until the recurrence series is
terminated.
Avoiding the ambiguous term recurring task
In common speech, the term recurring task sometimes refers to the unique task with
active recurrence within a series; and sometimes refers to the recurrence series itself, or
all the tasks within the recurrence series. This ambiguity is common in spoken English: in
the same way, the weekly report might refer to one instance of the report, or to the
recurring responsibility of doing the report each week. Due to this ambiguity, the usage
of the term recurring task is avoided; instead, one of the following terms is preferred:
task with active recurrence or recurrence series.
plannerRecurrenceSchedule
The plannerRecurrenceSchedule encapsulates a recurrence pattern definition (pattern), a
start date for that pattern (patternStartDateTime), and a system-generated property
that indicates the next occurrence date (nextOccurrenceDateTime).
The pattern is a recurrencePattern; for details, see Planner-specific notes about the
recurrencePattern.
The patternStartDateTime indicates the starting date and time of the series as a
DateTimeOffset. A non-null value must be assigned to patternStartDateTime whenever
the pattern property is used; this is currently the only way to define recurrence. Clients
should generally reassign this value when they make a change to the
recurrence.schedule.pattern to indicate the starting date of the new pattern; however, if
clients don't include a value, the service continues the series using a default value based
on the schedule. For more details, see the following notes and clarifications.
relativeMonthly and relativeYearly patterns might not specify more than one
It occurs weekly every Wednesday: the pattern has type = weekly , interval = 1 ,
daysOfWeek = [ wednesday ], and firstDayOfWeek = sunday
The dueDateTime is Wednesday 2/2
The nextOccurrenceDateTime is Wednesday 2/9
Three changes to the pattern are possible, and the resulting nextOccurrenceDateTime
are shown in the following table.
Note the difference of Thursday 2/10 vs. Thursday 2/3. When firstDayOfWeek =
Thursday , Thursday 2/3 is not in the same week as Wednesday 2/2 because a new week
starts on Thursday; whereas if the firstDayOfWeek isn't Thursday , then Thursday 2/3 is
in the same week as Wednesday 2/2, and Thursday 2/10 is in the next week.
The recurrence pattern specifies every 2 weeks on Friday, for example, type =
weekly , interval = 2 , daysOfWeek = [ friday ], and firstDayOfWeek = sunday .
A decision is made to change the cadence from 2 weeks to 3 weeks. Thus, the pattern is
modified to have interval = 3 along with the same values for weekly on Fridays.
Three distinct possibilities are examined, each yielding different due dates for the next
task in the series:
In the first example, the patternStartDateTime is set to be the same value as the
dueDateTime, for example, December 10. The nextOccurrenceDateTime is set to 3
weeks after the patternStartDateTime, being December 31. Conceptually, this
represents the cadence change taking effect only for the following task rather than for
this task.
The third example is similar to the first, except that it doesn't specify the
patternStartDateTime. A patternStartDateTime that is long back, like in August, can't
be used. In this case, the nextOccurrenceDateTime is calculated based on the original
due date of December 10, resulting in a nextOccurrenceDateTime of December 31,
similar to the first example. Note that the original due date isn't exposed, though it is
used in this calculation. This means that the dueDateTime can be changed to another
value, or even changed to be null , but the dueDateTime value is ignored for this
calculation, using instead the original due date. This is another reason why we
recommend that you change the dueDateTime and patternStartDateTime together.
It occurs weekly every Wednesday: the pattern has type = weekly , interval = 1 ,
daysOfWeek = [ wednesday ], and firstDayOfWeek = sunday .
The dueDateTime is Wed 2/16.
The nextOccurrenceDateTime is Wed 2/9.
The original due date is Wednesday 2/2. This value isn't publicly exposed, although
it can be inferred from the nextOccurrenceDateTime.
Change Resulting
nextOccurrenceDateTime
In all three examples, the dueDateTime isn't changed from its modified value of
Wednesday 2/16, and the next task in the series is created with a dueDateTime equal to
the nextOccurrenceDateTime in the previous table.
Note:
The other two conditions mentioned in the definition of active recurrence influence
whether a recurrence.schedule can be added:
Other recurrence sub-properties are read-only. If they aren't already assigned, the
service automatically generates them when the recurrence.schedule is added.
Trigger recurrence
The following shows two ways that a the recurrence mechanism can be triggered on a
task with active recurrence:
Update the task and set percentComplete to 100 (also referred to as completing
the task or marking the task complete).
Delete the task.
In the previous definition for a _task with active recurrence, if any of the three conditions
isn't met, the recurrence mechanism isn't triggered (no new task is created and
nextInSeriesTaskId isn't assigned.)
Instantiation of the new task usually happens immediately, which occasionally causes a
delay in the creation of the new task.
The new task has the following properties copied from the now-complete task: title,
description, checklist items (set to incomplete), assignments, priority, and categories.
The percentComplete of the new task is set to 0 . The dueDateTime of the new task is
set according to the recurrence schedule. The following sub-properties of recurrence are
copied: seriesId, recurrenceStartDateTime, and schedule;
schedule.nextOccurrenceDateTime is newly calculated for the new task. The other
recurrence properties are given appropriate values for the new task.
On the other hand, if task C is deleted, and the deletion triggers recurrence, a client
must discover the ID of task D by some other means. For example, by querying tasks in
the same bucket or by consuming the delta sync feed.
For example, a task with active recurrence and a schedule of weekly every Wednesday,
can have its schedule changed to monthly on the 15th day of each month.
Follow the previous steps for Create a recurring series. The same restrictions apply. The
original recurrence.seriesId and other sub-properties of recurrence are unchanged,
effectively reinstating or continuing the original series.
Completed tasks are hidden from most views. It is uncommon for a user to be viewing a
task that has been marked complete. Deleted tasks can't be viewed. This means that in
most cases, only one task with active recurrence exists in a recurrence series. If the task
with active recurrence has had its recurrence deactivated via the schedule being deleted,
no tasks with active recurrence in that series exist.
Rare exceptional scenarios
The following scenarios are rare, though possible. While they might appear to a client to
be exceptions, in fact the service always maintains integrity for the rule: a maximum of
one task with active recurrence in a given recurrence series. Guidance is given for
disambiguation.
Causes
The following shows two possible causes for information appearing to be out of sync:
Information hasn't yet reached the fast client-facing storage of Planner. The
authoritative information source of Planner has the data, but the data hasn't yet
been replicated to the request-optimized storage that returns data to clients.
The recurrence mechanism encountered a temporary failure. This means that the
new task to continue a series hasn't yet been created; it is usually created within a
few seconds or minutes.
If a client observes two tasks with active recurrence in the same recurrence series, the
task with the smaller occurrenceId can be assumed to have already had its recurrence
mechanism triggered. The back-end storage of Planner has the nextInSeriesTaskId set,
but that information hasn't reached the fast client-facing storage yet. The task with the
larger occurrenceId is the unique task with active recurrence.
Similar to the previous "two tasks with active recurrence", this second situation might be
observed if the task with the larger occurrenceId has its recurrence deactivated
(recurrence.schedule = null ). The existence of a task with a larger occurrenceId implies
that any tasks with smaller occurrenceId in that series don't have active recurrence, even
if the task with the larger occurrenceId doesn't have active recurrence either.
This is a truly ambiguous situation, as either of the following might be the case:
The first two are temporary states, that are guaranteed to be remedied by the service,
typically within a few seconds or minutes. The third is generally permanent. It's probably
inaccurate to describe this scenario as rare or exceptional; however, it was described
previously to bring attention to the fact that there is ambiguity in the observed state
due to the possibility of the first two cases.
Note:
If some tasks in the series have been deleted, the indices might contain gaps.
If users have moved the recurring series to a different plan, then you need to
look in other plans to see other tasks in the series; however, users are typically
primarily interested in the recurring series within one plan. Tasks may not be
moved across group boundaries; if all the plans in a group are queried, you
can find all the tasks that could have been moved out of the original plan.
Request
JSON
PATCH
https://graph.microsoft.com/beta/planner/tasks/Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV
{
"recurrence": {
"schedule": {
"pattern": {
"type": "daily",
"interval": 2
},
"patternStartDateTime": "2021-11-13T10:30:00Z"
}
},
"dueDateTime": "2021-11-13T10:30:00Z"
}
Response
JSON
Request
JSON
GET
https://graph.microsoft.com/beta/planner/tasks/Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV
Response
The following are notes about the response:
JSON
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#planner/tasks/$entity",
"@odata.etag": "W/\"JzEtVGFzayAgQEBAQEBAQEBAQEBAQEBASCc=\"",
"planId": "4CaQUsrKXkyMDBhpF9cu-JUAAZ1V",
"bucketId": "mVAeurfATUOEkpxi-60a9pUAJDxm",
"title": "Water the plants",
"orderHint": "8586352620867692777",
"assigneePriority": "",
"percentComplete": 0,
"priority": 5,
"startDate": null,
"createdDateTime": "2019-08-20T23:46:38.708303Z",
"hasDescription": false,
"previewType": "automatic",
"completedDateTime": null,
"completedBy": null,
"referenceCount": 0,
"checklistItemCount": 0,
"activeChecklistItemCount": 0,
"conversationThreadId": null,
"id": "Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV",
"createdBy": {
"user": {
"displayName": null,
"id": "edcfc4b0-be77-4866-948a-b93267e151f8"
}
},
"appliedCategories": {},
"assignments": {},
"recurrence": {
"seriesId": "w5tLb5HceUmpuiYlhdXyHg",
"occurrenceId": 1,
"previousInSeriesTaskId": null,
"nextInSeriesTaskId": null,
"recurrenceStartDateTime": "2021-11-13T10:30:00Z",
"schedule": {
"patternStartDateTime": "2021-11-13T10:30:00Z",
"nextOccurrenceDateTime": "2021-11-15T10:30:00Z",
"pattern": {
"type": "daily",
"interval": 2,
"firstDayOfWeek": "sunday",
"dayOfMonth": 0,
"daysOfWeek": [],
"index": "first",
"month": 0
}
}
},
"dueDateTime": "2021-11-13T10:30:00Z",
"creationSource": null
}
Request
The following is an example of a request that is identical for a task with or without
recurrence.
JSON
PATCH
https://graph.microsoft.com/beta/planner/tasks/Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV
{
"percentComplete": 100
}
Response
JSON
Request
JSON
GET
https://graph.microsoft.com/beta/planner/tasks/Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV
Response
The following is an example of the request. Because nextInSeriesTaskId is assigned, this
task can no longer have active recurrence configured.
JSON
HTTP/1.1 200 OK
Content-type: application/json
{
"_comment": "other fields omitted for brevity",
"percentComplete": 100,
"recurrence": {
"seriesId": "w5tLb5HceUmpuiYlhdXyHg",
"occurrenceId": 1,
"previousInSeriesTaskId": null,
"nextInSeriesTaskId": "GxOo0ms1iEu3eBI1-6lk85UAI5FI",
"recurrenceStartDateTime": "2021-11-13T10:30:00Z",
"schedule": {
"patternStartDateTime": "2021-11-13T10:30:00Z",
"nextOccurrenceDateTime": "2021-11-15T10:30:00Z",
"pattern": {
"type": "daily",
"interval": 2,
"firstDayOfWeek": "sunday",
"dayOfMonth": 0,
"daysOfWeek": [],
"index": "first",
"month": 0
}
}
},
"dueDateTime": "2021-11-13T10:30:00Z",
}
Request
JSON
GET https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI
Response
JSON
HTTP/1.1 200 OK
Content-type: application/json
{
"_comment": "other fields omitted for brevity",
"planId": "4CaQUsrKXkyMDBhpF9cu-JUAAZ1V",
"bucketId": "mVAeurfATUOEkpxi-60a9pUAJDxm",
"title": "Water the plants",
"percentComplete": 0,
"id": "GxOo0ms1iEu3eBI1-6lk85UAI5FI",
"appliedCategories": {},
"assignments": {},
"recurrence": {
"seriesId": "w5tLb5HceUmpuiYlhdXyHg",
"occurrenceId": 2,
"previousInSeriesTaskId": "Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV",
"nextInSeriesTaskId": null,
"recurrenceStartDateTime": "2021-11-13T10:30:00Z",
"schedule": {
"patternStartDateTime": "2021-11-13T10:30:00Z",
"nextOccurrenceDateTime": "2021-11-17T10:30:00Z",
"pattern": {
"type": "daily",
"interval": 2,
"firstDayOfWeek": "sunday",
"dayOfMonth": 0,
"daysOfWeek": [],
"index": "first",
"month": 0
}
}
},
"dueDateTime": "2021-11-15T10:30:00Z"
}
Request
JSON
PATCH https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI
{
"recurrence": {
"schedule": {
"pattern": {
"type": "weekly",
"interval": 1,
"daysOfWeek": [ "tuesday" ],
"firstDayOfWeek": "sunday"
}
}
},
"dueDateTime": null
}
Response
JSON
Request
JSON
GET https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI
Response
In the following example, a task can have active recurrence along with a null due date.
The nextOccurrenceDateTime is re-calculated and now is on November 23, a Tuesday,
from the daysOfWeek. This next occurrence is calculated based on the original
dueDateTime of the task of November 15, a Monday.
JSON
HTTP/1.1 200 OK
Content-type: application/json
{
"_comment": "other fields omitted for brevity",
"planId": "4CaQUsrKXkyMDBhpF9cu-JUAAZ1V",
"bucketId": "mVAeurfATUOEkpxi-60a9pUAJDxm",
"title": "Water the plants",
"percentComplete": 0,
"id": "GxOo0ms1iEu3eBI1-6lk85UAI5FI",
"appliedCategories": {},
"assignments": {},
"recurrence": {
"seriesId": "w5tLb5HceUmpuiYlhdXyHg",
"occurrenceId": 2,
"previousInSeriesTaskId": "Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV",
"nextInSeriesTaskId": null,
"recurrenceStartDateTime": "2021-11-13T10:30:00Z",
"schedule": {
"patternStartDateTime": "2021-11-13T10:30:00Z",
"nextOccurrenceDateTime": "2021-11-23T10:30:00Z",
"pattern": {
"type": "weekly",
"interval": 1,
"firstDayOfWeek": "sunday",
"dayOfMonth": 0,
"daysOfWeek": [ "tuesday" ],
"index": "first",
"month": 0
}
}
},
"dueDateTime": null
}
Request
JSON
PATCH https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI
{
"recurrence": {
"schedule": null
}
}
Response
JSON
Request
JSON
GET https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI
Response
The following is an example of the response that has the recurrence series info retained
(recurrence.schedule = null ). If a new schedule is specified, this task still belongs to the
same series.
JSON
HTTP/1.1 200 OK
Content-type: application/json
{
"_comment": "other fields omitted for brevity",
"recurrence": {
"seriesId": "w5tLb5HceUmpuiYlhdXyHg",
"occurrenceId": 2,
"previousInSeriesTaskId": "Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV",
"nextInSeriesTaskId": null,
"schedule": null,
"recurrenceStartDateTime": "2021-11-13T10:30:00Z"
},
"dueDateTime": null
}
Request
JSON
PATCH https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI
{
"recurrence": {
"schedule": {
"pattern": {
"type": "daily",
"interval": 5
}
}
}
}
Response
The following is an example of the response that shows an error that describes the
problem. The response object contains a bug because the error message should
mention Recurrence.Schedule.PatternStartDateTime rather than
Recurrence.Schedule.Range . This is currently a known issue.
JSON
{
"error": {
"code": "",
"message": "Schema validation has failed. Validation for field
'Recurrence.Schedule.Range', on entity 'Task' has failed: A non-null value
must be specified for this field.",
"innerError": {
"request-id": "922f7646-513a-4f63-a231-9cf2d7b647cb",
"date": "2021-06-22T21:37:35"
}
}
}
Request
JSON
PATCH https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI
{
"recurrence": {
"schedule": {
"pattern": {
"type": "absoluteMonthly",
"interval": 2,
"dayOfMonth": 25
},
"patternStartDateTime": "2021-11-25T10:30:00Z"
}
}
}
Response
JSON
Request
JSON
GET https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI
Response
JSON
HTTP/1.1 200 OK
Content-type: application/json
{
"_comment": "other fields omitted for brevity",
"planId": "4CaQUsrKXkyMDBhpF9cu-JUAAZ1V",
"bucketId": "mVAeurfATUOEkpxi-60a9pUAJDxm",
"title": "Water the plants",
"percentComplete": 0,
"id": "GxOo0ms1iEu3eBI1-6lk85UAI5FI",
"appliedCategories": {},
"assignments": {},
"recurrence": {
"seriesId": "w5tLb5HceUmpuiYlhdXyHg",
"occurrenceId": 2,
"previousInSeriesTaskId": "Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV",
"nextInSeriesTaskId": null,
"recurrenceStartDateTime": "2021-11-13T10:30:00Z",
"schedule": {
"patternStartDateTime": "2021-11-25T10:30:00Z",
"nextOccurrenceDateTime": "2022-01-25T10:30:00Z",
"pattern": {
"type": "absoluteMonthly",
"interval": 2,
"firstDayOfWeek": "sunday",
"dayOfMonth": 25,
"daysOfWeek": [],
"index": "first",
"month": 0
}
}
},
"dueDateTime": null
}
Error case: Attempt to edit a read-only property
The following example request and response show a bad request, an attempt to assign a
value to the recurrence.seriesId property that is read-only.
Request
JSON
PATCH https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI
{
"recurrence": {
"seriesId": "abc"
}
}
Response
The following response object shows an error that describes the problem.
JSON
{
"error": {
"code": "",
"message": "Invalid recurrence sub-property assignment(s):
\"seriesId\".",
"innerError": {
"request-id": "922f7646-513a-4f63-a231-9cf2d7b647cb",
"date": "2021-06-22T21:37:35"
}
}
}
JSON
PATCH https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI
{
"percentComplete": 100
}
Response
JSON
Request
JSON
GET https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI
Response
JSON
HTTP/1.1 200 OK
Content-type: application/json
{
"_comment": "other fields omitted for brevity",
"planId": "4CaQUsrKXkyMDBhpF9cu-JUAAZ1V",
"bucketId": "mVAeurfATUOEkpxi-60a9pUAJDxm",
"title": "Water the plants",
"percentComplete": 100,
"id": "GxOo0ms1iEu3eBI1-6lk85UAI5FI",
"appliedCategories": {},
"assignments": {},
"recurrence": {
"seriesId": "w5tLb5HceUmpuiYlhdXyHg",
"occurrenceId": 2,
"previousInSeriesTaskId": "Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV",
"nextInSeriesTaskId": "-6zr7XfE6E2JvxCSmE7Wdf8AClON",
"recurrenceStartDateTime": "2021-11-13T10:30:00Z",
"schedule": {
"patternStartDateTime": "2021-11-25T10:30:00Z",
"nextOccurrenceDateTime": "2022-01-25T10:30:00Z",
"pattern": {
"type": "absoluteMonthly",
"interval": 2,
"firstDayOfWeek": "sunday",
"dayOfMonth": 25,
"daysOfWeek": [],
"index": "first",
"month": 0
}
}
},
"dueDateTime": null
}
Request
JSON
PATCH
https://graph.microsoft.com/beta/planner/tasks/Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV
{
"recurrence": {
"schedule": null
}
}
Response
The following response object shows an error that describes the problem.
JSON
{
"error": {
"code": "",
"message": "Schema validation has failed. Validation for field
'Recurrence', on entity 'Task' has failed: Cannot add/edit/delete recurrence
when the next instance should already be created.",
"innerError": {
"request-id": "922f7646-513a-4f63-a231-9cf2d7b647cb",
"date": "2021-06-22T21:37:35"
}
}
}
Request
JSON
GET
https://graph.microsoft.com/beta/planner/tasks/-6zr7XfE6E2JvxCSmE7Wdf8AClON
Response
JSON
HTTP/1.1 200 OK
Content-type: application/json
{
"_comment": "other fields omitted for brevity",
"planId": "4CaQUsrKXkyMDBhpF9cu-JUAAZ1V",
"bucketId": "mVAeurfATUOEkpxi-60a9pUAJDxm",
"title": "Water the plants",
"percentComplete": 0,
"id": "-6zr7XfE6E2JvxCSmE7Wdf8AClON",
"appliedCategories": {},
"assignments": {},
"recurrence": {
"seriesId": "w5tLb5HceUmpuiYlhdXyHg",
"occurrenceId": 3,
"previousInSeriesTaskId": "GxOo0ms1iEu3eBI1-6lk85UAI5FI",
"nextInSeriesTaskId": null,
"recurrenceStartDateTime": "2021-11-13T10:30:00Z",
"schedule": {
"patternStartDateTime": "2021-11-25T10:30:00Z",
"nextOccurrenceDateTime": "2022-03-25T10:30:00Z",
"pattern": {
"type": "absoluteMonthly",
"interval": 2,
"firstDayOfWeek": "sunday",
"dayOfMonth": 25,
"daysOfWeek": [],
"index": "first",
"month": 0
}
}
},
"dueDateTime": "2022-01-25T10:30:00Z"
}
Configuring task rules in Planner
(preview)
Article • 01/11/2023
The Planner API in Microsoft Graph supports rules, which allow customization of what
can and can't be done on tasks. Task rules can be specified for tasks created from
various sources, such as business scenarios.
Task property rules are represented by the plannerTaskPropertyRule entity and describe
the allowed actions at the task-level and rules around each configurable property.
Depending on the specific entry, the rules specify either a collection of values or a
fieldRules object. Field rules specify a collection of values as default, and provide a
separate collection of values for override conditions. For any collection of values, the
specified values are what is allowed; omitted values aren't allowed.
In this article, you will learn the behaviors associated with each entry and the override
conditions supported by each property.
Configurable actions
delete
Specifies whether the task can be deleted. Accepted values are:
move
Specifies whether the task can be moved. This only includes a task moving between
buckets and plans with the same or different containers. However, it doesn't include
other operations similar to moves, which can be configured independently, such as
assignments, ordering of the task, percent complete, or priority. Accepted values are:
moveBetweenBuckets : Task can only be moved between the buckets of the plan it is
in.
moveBetweenPlans : Task can be moved between buckets and across the plans that
order
Specifies whether the task can be reordered in shared views. Accepted values are:
Configurable properties
appliedCategories
The appliedCategories property is configured with fieldRules, providing default values
and overrides for specific conditions. Accepted values are:
This property doesn't support any override conditions. The rules must be specified in the
defaultRules property.
assignments
The assignments property is configured with fieldRules, providing default values and
overrides for specific conditions. Accepted values are:
addOther : Users can assign the task to people other than themselves.
The collection can specify either a single allow or block value, or any combination of
other values.
This property supports the following override conditions. If an override doesn't have
rules specified, the values specified for the defaultRules property applies instead. The
defaultRules must be specified.
checkLists
The checkLists property is configured with fieldRules, providing default values and
overrides for specific conditions. Accepted values are:
The collection can specify either a single allow or block value, or any combination of
other values.
This property supports the following override conditions. If an override doesn't have
rules specified, the values specified for the defaultRules property applies instead. The
defaultRules must be specified.
applicationCreated : Rules apply if the checklist item was created using application
permissions.
dueDate
Specifies whether the task due date can be changed. Accepted values are:
block : Task due date can't be changed.
notes
Specifies whether the task notes can be changed. Accepted values are:
percentComplete
Specifies whether the task percentComplete property can be changed. Accepted values
are:
to 99 .
setToNotStarted : The task percentComplete property can be set to 0 .
The collection can specify either a single allow or block value, or any combination of
other values.
previewType
Specifies whether the task preview type can be changed. Accepted values are:
priority
Specifies whether the task priority can be changed. Accepted values are:
block : Task priority can't be changed.
references
Thereferences property is configured with fieldRules, providing default values and
overrides for specific conditions. Accepted values are:
The collection can specify either a single allow or block value, or any combination of
other values.
This property supports the following override conditions. If an override doesn't have
rules specified, the values specified for the defaultRules property apply instead. The
defaultRules must be specified.
applicationCreated : Rules apply if the task reference was created using application
permissions.
startDate
Specifies whether the task start date can be changed. Accepted values are:
title
Specifies whether the task title can be changed. Accepted values are:
Microsoft Teams is the ultimate hub for team collaboration and intelligent
communications, fostering a culture where employees can thrive. Built on the strength
and scale of Microsoft 365 with over 120 million users, Microsoft Teams delivers chat-
based collaboration, meetings, calling, and enterprise voice features. Available as apps
on Teams and as part of Microsoft Graph are Microsoft Shifts and Viva Learning .
Shifts and its API give employers and frontline workers real-time visibility into schedules
based on worker availability, and let them adjust schedules to their team's needs. Viva
Learning and its API let employers integrate content from learning management
systems, enabling employees to discover, share, and prioritize learning, and
incorporating learning into the flow of work.
https://www.youtube-nocookie.com/embed/KCvAhQEJmyY
Automate workflows
Automate workflows
You can create websites, services, and native platform applications that run outside the
Microsoft Teams user experience, and call the Teams API to automate Teams scenarios.
These collaboration tools include Microsoft Graph-enabled tabs or bots running inside
Microsoft Teams apps. You can also call Microsoft Graph outside of a Microsoft Teams
app, such as from a website or a web service. If you've already enabled your website for
Microsoft Graph, you can use that work for Microsoft Teams by using the Microsoft
Teams developer platform to create a tab that uses the existing website code.
Microsoft Teams APIs can enhance apps inside and outside of Teams:
App type Scenario description
Services Enhance your client applications with Microsoft Graph data via your web service.
Calling and Create Microsoft Teams apps with bots that can initiate and participate in
online audio/video calls, route/transfer calls based on interactive voice response (IVR)
meetings flows, and participate in online meetings.
(preview)
7 Note
You may not record or otherwise persist media content from calls or meetings that
your application accesses, or data derived from that media content. Make sure you
are compliant with the laws and regulations of your area regarding data protection
and confidentiality of communications. Please see the Terms of Use and consult
with your legal counsel for more information.
Cultivate workforce
API reference
Looking for the API reference for Teams, Shift, and Viva Learning?
The Microsoft Teams activity feed enables users to triage items that require attention by
notifying them of changes. You can use the activity feed notification APIs in Microsoft
Graph to extend this functionality to your apps. This allows your apps to provide richer
experiences and better engage users by helping to keep them up to date with changes
in the tools and workflows they use.
The following example shows how these components together provide the details about
a notification. This example is a notification about a user mentioned in a Yammer
community.
Requirements for using the activity feed
notification APIs
Activity feed APIs work with a Teams app. The following are the requirements for
sending activity feed notifications:
The Teams app manifest must have the Azure AD app ID added to the
webApplicationInfo section. For details, see manifest schema.
Activity types must be declared in the activities section. For details, see manifest
schema.
The Teams app must be installed for the recipient, either personally, or in a team or
chat they are part of. For more information, see Teams app installation.
JSON
"$schema": "https://developer.microsoft.com/json-
schemas/teams/v1.7/MicrosoftTeams.schema.json",
"manifestVersion": "1.7",
JSON
"webApplicationInfo":
{
"id": "a3111f15-658e-457c-9689-fd20fe907330",
"resource": "https://contosoapp.com"
}
resource string Resource associated with the Azure AD app. Also known as reply or redirect
URL in the Azure Portal.
7 Note
You might get an error if multiple Teams apps in the same scope (team, chat or
user) are using the same Azure AD app. Make sure that you're using unique Azure
AD apps.
JSON
"activities":
{
"activityTypes": [
{
"type": "taskCreated",
"description": "Task Created Activity",
"templateText": "{actor} created task {taskId} for you"
},
{
"type": "approvalRequired",
"description": "Deployment requires your approval",
"templateText": "{actor} created a new deployment {deploymentId}"
}
]
}
description string Human-readable short description. This will be visible on the Microsoft
Teams client.
templateText string Template text for the activity notification. You can declare your parameters
by encapsulating parameters in {} .
7 Note
actor is a special parameter that always takes the name of the caller. In delegated
calls, actor is the user's name. In application-only calls, it takes the name of the
Teams app.
You can also use Teams app installation APIs to manage Teams app installations.
For details about what topics are supported for each scenario, see the specific APIs.
Custom text-based topics are supported for all scenarios.
7 Note
The activity icon is based on the context the request is made in. If the request is
made with delegated permissions, the user's photo appears as the avatar, while the
Teams app icon appears as the activity icon. In an application-only context, the
Teams app icon is used as the avatar and the activity icon is omitted.
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/chats/{chatId}/sendActivityNotification
Content-Type: application/json
{
"topic": {
"source": "entityUrl",
"value": "https://graph.microsoft.com/v1.0/chats/{chatId}"
},
"activityType": "taskCreated",
"previewText": {
"content": "New Task Created"
},
"recipient": {
"@odata.type": "microsoft.graph.aadUserNotificationRecipient",
"userId": "569363e2-4e49-4661-87f2-16f245c5d66a"
},
"templateParameters": [
{
"name": "taskId",
"value": "12322"
}
]
}
Response
HTTP
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/teams/{teamId}/sendActivityNotification
Content-Type: application/json
{
"topic": {
"source": "entityUrl",
"value": "https://graph.microsoft.com/v1.0/teams/{teamId}"
},
"activityType": "taskCreated",
"previewText": {
"content": "New Task Created"
},
"recipient": {
"@odata.type": "microsoft.graph.aadUserNotificationRecipient",
"userId": "569363e2-4e49-4661-87f2-16f245c5d66a"
},
"templateParameters": [
{
"name": "taskId",
"value": "12322"
}
]
}
Response
HTTP
7 Note
webUrl must start with the Microsoft Teams domain (teams.microsoft.com for
example).
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/teams/{teamId}/sendActivityNotification
Content-Type: application/json
{
"topic": {
"source": "text",
"value": "Deployment Approvals Channel",
"webUrl":
"https://teams.microsoft.com/l/message/19:448cfd2ac2a7490a9084a9ed14cttr
[email protected]/1605223780000?tenantId=c8b1bf45-3834-4ecf-971a-
b4c755ee677d&groupId=d4c2a937-f097-435a-bc91-
5c1683ca7245&parentMessageId=1605223771864&teamName=Approvals&channelNam
e=Azure%20DevOps&createdTime=1605223780000"
},
"activityType": "approvalRequired",
"previewText": {
"content": "New deployment requires your approval"
},
"recipient": {
"@odata.type": "microsoft.graph.aadUserNotificationRecipient",
"userId": "569363e2-4e49-4661-87f2-16f245c5d66a"
},
"templateParameters": [
{
"name": "deploymentId",
"value": "6788662"
}
]
}
Response
HTTP
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/teams/7155e3c8-175e-4311-97ef-
572edc3aa3db/sendActivityNotification
Content-Type: application/json
{
"topic": {
"source": "text",
"value": "Weekly Virtual Social",
"webUrl": "Teams webUrl"
},
"previewText": {
"content": "It will be fun!"
},
"activityType": "eventCreated",
"recipient": {
"@odata.type":
"microsoft.graph.teamMembersNotificationRecipient",
"teamId": "7155e3c8-175e-4311-97ef-572edc3aa3db"
}
}
Response
HTTP
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/teams/7155e3c8-175e-4311-97ef-
572edc3aa3db/sendActivityNotification
Content-Type: application/json
{
"topic": {
"source": "text",
"value": "Weekly Virtual Social",
"webUrl": "Teams webUrl"
},
"previewText": {
"content": "It will be fun!"
},
"activityType": "eventCreated",
"recipient": {
"@odata.type":
"microsoft.graph.channelMembersNotificationRecipient",
"teamId": "7155e3c8-175e-4311-97ef-572edc3aa3db",
"channelId": "19:[email protected]"
}
}
Response
HTTP
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/chats/19:d65713bc498c4a428c71ef9353e6ce
[email protected]/sendActivityNotification
Content-Type: application/json
{
"topic": {
"source": "text",
"value": "Weekly Virtual Social",
"webUrl": "Teams webUrl"
},
"previewText": {
"content": "It will be fun!"
},
"activityType": "eventCreated",
"recipient": {
"@odata.type":
"microsoft.graph.chatMembersNotificationRecipient",
"chatId": "19:[email protected]"
}
}
Response
HTTP
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/teamwork/sendActivityNotificationToReci
pients
Content-Type: application/json
{
"topic": {
"source": "entityUrl",
"value":
"https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/{teamsAppId}"
},
"activityType": "pendingFinanceApprovalRequests",
"previewText": {
"content": "Internal spending team has a pending finance
approval requests"
},
"recipients": [
{
"@odata.type":
"microsoft.graph.aadUserNotificationRecipient",
"userId": "569363e2-4e49-4661-87f2-16f245c5d66a"
},
{
"@odata.type":
"microsoft.graph.aadUserNotificationRecipient",
"userId": "ab88234e-0874-477c-9638-d144296ed04f"
},
{
"@odata.type":
"microsoft.graph.aadUserNotificationRecipient",
"userId": "01c64f53-69aa-42c7-9b7f-9f75195d6bfc"
}
],
"templateParameters": [
{
"name": "pendingRequestCount",
"value": "5"
}
]
}
Response
HTTP
Users can click Edit next to an app and customize the notifications, as shown in the
following example. The description field in the Teams app manifest is displayed.
FAQs
Who needs to install the Teams app?
The target user must have the Teams app that is sending notifications installed.
you use unique Azure AD apps for unique Teams apps. Note that you can have the same
Teams app installed in multiple scopes (team + user for example).
See also
Best practices for using Microsoft Teams activity feed notifications
Design activity feed notifications for Microsoft Teams
Microsoft Teams API overview
Best practices for using Microsoft Teams
activity feed notifications
Article • 01/25/2023
This article covers best practices for using Microsoft Teams activity feed notifications in
Microsoft Graph. These best practices apply to:
When you implement activity feed notifications, keep the following points in mind:
Toast notifications redirect users to the activity feed, not to the app. To see another
activity, users must select the associated notification in the activity feed.
Users can manage notification settings only after the selected app sends a
notification.
The icon for each notification is included in the app manifest. Microsoft Graph
does not support customizing the icon.
Priority notifications are not supported.
Localize the content in a notification toast or feed. The localization happens only if
the app’s content is localized.
Provide appropriate titles and descriptions for your Activity Types. Use short titles,
such as @mention and Announcements. Avoid long titles, such as User at-
mentioned activity and Post creation activity.
Notifications should convey important information that is relevant to the user. For
example, Diego assigned a sales ticket to you is a relevant message; Joni left the
sales team is not.
Avoid sending notifications that are promotional in nature, such as Try the new
feature in the Cycling app.
Avoid duplicate notifications from bot messages and activity feed notifications. For
more information, see choose activity feed notifications or bot framework
messages.
Use the text preview section in notifications. Provide information to help the user
determine the importance of the notification and take action, if necessary.
Don't add a period at the end of the notification title, to be consistent with all
other notification settings in Teams.
Make the relationship between the notification and its content clear to the user.
For example, when a user receives a notification for approving a leave, the
notification should redirect them to the corresponding section of the app. If the
notification pertains to removal or deletion of entities, such as users and tasks,
direct the recipient to the content and indicate the required action.
Make sure that the feed experience is self-contained. For example, any pop-ups
and modals must remain in the app.
Verify that your app does not send more than 20 notifications per minute, per user.
Notifications will be automatically throttled if the count exceeds 20.
Ensure that the load time of your app does not negatively affect the experience for
users when they switch between notifications in the feed.
Inform the user about the notifications storage period in the activity feed. In
Microsoft Teams, the storage period is 30 days.
7 Note
The 30-day storage limit applies to all notifications. It's not specific to
notifications sent through the activity feed notifications API.
Choose activity feed notifications or bot
framework messages
You can use either activity feed notifications or bot framework messages, but don't use
both notification types. The following sections describe the notification types and when
to use each.
The activity feed notifications API allows users to configure notifications for each
notification type from notification settings.
If you use activity feed notifications, be aware that your app might send double
notifications, if it sends bot notifications to chats or channels and also to the activity
feed. Only send double notifications if your scenario requires it.
Use delegated notifications to create a better notification experience. The activity feed
notification API can send either delegated or application-only calls. In delegated calls,
the sender of the notification appears as the user who initiated the notification, and in
application-only calls, the sender appears as the app.
You can update an existing activity feed notification instead of creating a new
notification by using the chainId parameter.
It is useful for the alert to be consumed as a chat or channel message; for example, a
message that is consumed by all channel members.
See also
Design activity feed notifications for Microsoft Teams
Microsoft Teams API overview
Configure application access to online
meetings
Article • 09/02/2022
You can use the cloud communications API in Microsoft Graph to configure an
application access policy that allows applications to access online meetings on behalf of
a user.
In some cases, such as for background services or daemon apps that run on a server
without the presence of a signed-in user, it is appropriate for an app to call Microsoft
Graph to take actions on behalf of a user. For example, an app might need to call
Microsoft Graph to schedule multiple meetings based on published schedules (such as
courses) or external scheduling tools. In these cases, the user that the application acts
on behalf of is identified as the meeting organizer.
This article covers the basic steps to configure an application access policy. These steps
are specific to online meetings and do not apply to other Microsoft Graph resources.
1. Identify the app’s application (client) ID and the user IDs of the users on behalf of
which the app will be authorized to access online meetings.
Run the following cmdlet, replacing the Identity, AppIds, and Description
(optional) arguments.
PowerShell
4. Grant the policy to the user to allow the app IDs contained in the policy to access
online meetings on behalf of the granted user.
Run the following cmdlet, replacing the PolicyName and Identity arguments.
PowerShell
5. (Optional) Grant the policy to the whole tenant. This will apply to users who do not
have an application access policy assigned. For details, see the cmdlet links in the
see also section.
PowerShell
7 Note
Identity refers to the policy name when creating the policy, but the user ID
when granting the policy.
Changes to application access policies can take up to 30 minutes to take
effect in Microsoft Graph REST API calls.
OnlineMeetings.Read.All
OnlineMeetings.ReadWrite.All
OnlineMeetingArtifact.Read.All
For more information about configuring application access policy, see the PowerShell
cmdlet reference for New-ApplicationAccessPolicy.
Errors
You might encounter the following error when an API call is denied access due to an app
trying to access an online meeting when application access policy is not configured.
JSON
{
"error": {
"code": "Unauthorized",
"message": "App <app_ID_redacted> is not authorized to Create
meeting on behalf of user <user_ID_redacted>",
"innerError": {
"date": "<date_redacted>",
"request-id": "599d9cb0-56ac-4dc5-b6f8-1456a1414609"
}
}
}
Follow the steps in this article to create and/or grant an application access policy that
contains the app ID to the user ID.
See also
Permissions reference
New-CsApplicationAccessPolicy
Grant-CsApplicationAccessPolicy
Get-CsApplicationAccessPolicy
Set-CsApplicationAccessPolicy
Remove-CsApplicationAccessPolicy
Teams API overview
Configure the built-in tab types in
Microsoft Teams
Article • 10/12/2022
To create or configure a Microsoft Teams tab using the Microsoft Graph API, you need to
know the teamsAppId of the app, and the entityId , contentUrl , removeUrl , and
websiteUrl to provide for that kind of app. This article explains how to get those values
Custom tabs
To use Microsoft Graph to configure a tab associated with a tab provider that you wrote,
identify the entityId , contentUrl , removeUrl , and websiteUrl that the app's
configuration UI provides to Microsoft Teams, and pass the same entityId , contentUrl ,
removeUrl , and websiteUrl values to Microsoft Graph.
The teamsAppId is the same as the id in the app manifest schema for Microsoft Teams.
Website tabs
For website tabs, the teamsAppId is com.microsoft.teamspace.tab.web . The following is
the configuration.
entityId string The sourceDoc ID of the file. You can find this by opening the file in
SharePoint and looking at the address bar – the URL will have a
sourcedoc=%7B{sourceDocId}%7D clause. You can also derive this from the
webUrl of the SharePoint drive item for the document. For details, see GET
/groups/{group-id}/drive/items/{item-id}.
HTTP
POST https://graph.microsoft.com/v1.0/teams/{team-id}/channels/{channel-
id}/tabs
{
"displayName": "word",
"[email protected]" :
"https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/com.microsoft.teamsp
ace.tab.file.staticviewer.word",
"configuration": {
"entityId": "115A90F4-AC9C-4F79-9837-36D1EFB3BE08",
"contentUrl":
"https://m365x165177.sharepoint.com/sites/4NewCloneWithClonableParts/Shared%
20Documents/General/Employee Handbook.docx",
"removeUrl": null,
"websiteUrl": null
}
}
contentUrl string The URL of the root folder of the document library. You can find this URL by
opening the SharePoint folder in your browser, copying the URL, and
deleting "/Forms/AllItems.aspx" and everything after that.
HTTP
POST https://graph.microsoft.com/v1.0/teams/{team-id}/channels/{channel-
id}/tabs
{
"displayName": "Document%20Library1",
"[email protected]":
"https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/com.microsoft.teamsp
ace.tab.files.sharepoint",
"configuration": {
"entityId": "",
"contentUrl":
"https://microsoft.sharepoint.com/teams/WWWtest/Shared%20Documents",
"removeUrl": null,
"websiteUrl": null
}
}
Wiki tabs
For wiki tabs, the teamsAppId is com.microsoft.teamspace.tab.wiki . Wiki tabs do not
support configuration through Microsoft Graph. Note, however, that there isn't much to
configure - in an unconfigured wiki tab, the first user just needs to select Set up tab to
configure it.
Planner tabs
For Planner tabs, the teamsAppId is com.microsoft.teamspace.tab.planner . Configuration
is not supported.
OneNote tabs
For OneNote tabs, the teamsAppId is 0d820ecd-def2-4297-adad-78056cde7c78 .
Configuration is not supported.
Power BI tabs
For Power BI tabs, the teamsAppId is com.microsoft.teamspace.tab.powerbi .
Configuration is not supported.
See also
Microsoft Teams API overview
Get system messages for Microsoft
Teams
Article • 06/30/2022
Microsoft Teams generates system messages for events by using the Microsoft Graph
API. Events include members added to a chat, team name updated, and channel
description updated. System messages enable the caller to have insights about events
that happened in a team, a channel, or a chat.
Microsoft Graph exposes system messages as part of chatMessage GET operations and
Change notifications for chat and channel messages.
System messages are presented as chatMessage objects. In this case, the messageType
property is set to systemEventMessage and the eventDetail property provides the event
details.
GET /teams/{team-id}/channels/{channel-id}/messages
GET /teams/{team-td}/channels/{channel-id}/messages/{message-id}
GET /chats/{chat-id}/messages
GET /chats/{chat-id}/messages/{message-id}
7 Note
Call ended
JSON
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.callEndedEventMessageDetail",
"callId": "9c848c0e-f906-4dfc-b22e-c68a785a587c",
"callDuration": "PT59S",
"callEventType": "meeting",
"callParticipants": [{
"participant": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": "Adele Vance ",
"userIdentityType": "aadUser"
}
}
}],
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Call recording
JSON
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.callRecordingEventMessageDetail",
"callId": "c86c6052-410b-4e7c-b843-9a09f576e4d5",
"callRecordingDisplayName": "Meeting Recording.mp4",
"callRecordingUrl":
"https://testtenant.sharepoint.com/sites/TestTeam/Shared%20Documents/General
/Recordings/Meeting%20Recording.mp4?web=1",
"callRecordingDuration": "PT40M19.26S",
"callRecordingStatus": "success",
"meetingOrganizer": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
},
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Call started
JSON
{
"id": "1615943825123",
"replyToId": null,
"etag": "1615943825123",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-1706:47:05.123Z",
"lastModifiedDateTime": "2021-03-1706:47:05.123Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"channelIdentity": null,
"onBehalfOf": null,
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.callStartedEventMessageDetail",
"callId": "9c848c0e-f906-4dfc-b22e-c68a785a587c",
"callEventType": "call",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Call transcript
JSON
{
"id": "1615943825123",
"replyToId": null,
"etag": "1615943825123",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-1706:47:05.123Z",
"lastModifiedDateTime": "2021-03-1706:47:05.123Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"channelIdentity": null,
"onBehalfOf": null,
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.callTranscriptEventMessageDetail",
"callId": "5b927778-760b-429e-8c4e-65b1802dd6c9",
"callTranscriptICalUid":
"040000008200E00074C5B7101A82E00800000000002C743F89CDD6010000000000000000100
00000CA87F90D9372ED45A399B5D75E854EE9 ",
"meetingOrganizer": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Channel added
JSON
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.channelAddedEventMessageDetail",
"channelId": "19:[email protected]",
"channelDisplayName": "Standard channel",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Channel deleted
JSON
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.channelDeletedEventMessageDetail",
"channelId": "19:[email protected]",
"channelDisplayName": "Standard channel",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type":
"#microsoft.graph.channelDescriptionUpdatedEventMessageDetail",
"channelId": "19:[email protected]",
"channelDescription": "Channel description updated",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Channel renamed
JSON
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.channelRenamedEventMessageDetail",
"channelId": "19:[email protected]",
"channelDisplayName": "Standard channel rename",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "06a5b888-ad96-455e-88ef-c059ec4e4cf0",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type":
"#microsoft.graph.channelSetAsFavoriteByDefaultEventMessageDetail",
"channelId": "19:[email protected]",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type":
"#microsoft.graph.channelUnsetAsFavoriteByDefaultEventMessageDetail",
"channelId": "19:[email protected]",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Chat renamed
JSON
{
"id": "1615943825123",
"replyToId": null,
"etag": "1615943825123",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-1706:47:05.123Z",
"lastModifiedDateTime": "2021-03-1706:47:05.123Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"channelIdentity": null,
"onBehalfOf": null,
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.chatRenamedEventMessageDetail",
"chatId": "19:[email protected]",
"chatDisplayName": "Microsoft Teams Members",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type":
"#microsoft.graph.conversationMemberRoleUpdatedEventMessageDetail",
"conversationMemberRoles": [
"Owner"
],
"conversationMemberUser": {
"id": "06a5b888-ad96-455e-88ef-c059ec4e4cf0",
"displayName": null,
"userIdentityType": "aadUser"
},
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
{
"id": "1620732126822",
"replyToId": null,
"etag": "1620732126822",
"messageType": "systemEventMessage",
"createdDateTime": "2021-05-11T11:22:06.822Z",
"lastModifiedDateTime": "2021-05-11T11:22:06.822Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId":
"19:meeting_OTFkNDQzMjMtZWQyYi00ZjI4LTk1ZmUtZmI2NjBmNTFmMzg1@thread.v2",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"from": null,
"channelIdentity": null,
"onBehalfOf": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type":
"#microsoft.graph.meetingPolicyUpdatedEventMessageDetail",
"meetingChatId":
"19:meeting_OTFkNDQzMjMtZWQyYi00ZjI4LTk1ZmUtZmI2NjBmNTFmMzg1@thread.v2",
"meetingChatEnabled": true,
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Members added
JSON
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.membersAddedEventMessageDetail",
"visibleHistoryStartDateTime": "0001-01-01T00:00:00Z",
"members": [{
"id": "06a5b888-ad96-455e-88ef-c059ec4e4cf0",
"displayName": null,
"userIdentityType": "aadUser"
},
{
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
],
"initiator": {
"application": null,
"device": null,
"user": {
"id": "9ee3dc1b-6a70-4582-8bc5-5dd35336b6c3",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Members deleted
JSON
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.membersDeletedEventMessageDetail",
"members": [{
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}],
"initiator": {
"application": null,
"device": null,
"user": {
"id": "9ee3dc1b-6a70-4582-8bc5-5dd35336b6c3",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Members joined
JSON
{
"id": "1620050140712",
"replyToId": null,
"etag": "1620050140712",
"messageType": "systemEventMessage",
"createdDateTime": "2021-05-03T13:55:40.712Z",
"lastModifiedDateTime": "2021-05-03T13:55:40.712Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId":
"19:meeting_OTFkNDQzMjMtZWQyYi00ZjI4LTk1ZmUtZmI2NjBmNTFmMzg1@thread.v2",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"from": null,
"channelIdentity": null,
"onBehalfOf": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.membersJoinedEventMessageDetail",
"members": [{
"id": "2c3f5f34-ac9f-42e7-8b35-442ccac166cb",
"displayName": "Alex (Guest)",
"userIdentityType": "aadUser"
}],
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Members left
JSON
{
"id": "1620049976741",
"replyToId": null,
"etag": "1620049976741",
"messageType": "systemEventMessage",
"createdDateTime": "2021-05-03T13:52:56.741Z",
"lastModifiedDateTime": "2021-05-03T13:52:56.741Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId":
"19:meeting_OTFkNDQzMjMtZWQyYi00ZjI4LTk1ZmUtZmI2NjBmNTFmMzg1@thread.v2",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"from": null,
"channelIdentity": null,
"onBehalfOf": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.membersLeftEventMessageDetail",
"members": [{
"id": "ee8af8acd3184068a935a1f207865620",
"displayName": "Alex (Guest)",
"userIdentityType": "anonymousGuest"
}],
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Message pinned
JSON
{
"id": "1613453493532",
"replyToId": null,
"etag": "1613453493532",
"messageType": "systemEventMessage",
"createdDateTime": "2021-02-16T05:31:33.532Z",
"lastModifiedDateTime": "2021-02-16T05:31:33.532Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"channelIdentity": null,
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.messagePinnedEventMessageDetail",
"eventDateTime": "2022-05-02T20:11:08.335Z",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "28c10244-4bad-4fda-993c-f332faef94f0",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Message unpinned
JSON
{
"replyToId": null,
"etag": "1613453493532",
"messageType": "systemEventMessage",
"createdDateTime": "2021-02-16T05:31:33.532Z",
"lastModifiedDateTime": "2021-02-16T05:31:33.532Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"channelIdentity": null,
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.messageUnpinnedEventMessageDetail",
"eventDateTime": "2022-05-02T20:11:08.335Z",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "28c10244-4bad-4fda-993c-f332faef94f0",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Tab updated
JSON
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.tabUpdatedEventMessageDetail",
"tabId": "tab::e82fa916-3c9a-407e-806b-0b9d8d7492c0",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "9ee3dc1b-6a70-4582-8bc5-5dd35336b6c3",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Team archived
JSON
{
"id": "1623677858199",
"replyToId": null,
"etag": "1623677858199",
"messageType": "systemEventMessage",
"createdDateTime": "2021-06-14T13:37:38.199Z",
"lastModifiedDateTime": "2021-06-14T13:37:38.199Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A318c8c65f0794971a1a9b5e3413d77de
%40thread.tacv2/1623677858199?groupId=5e91c375-f755-4882-880e-
f1b9322faa87&tenantId=df81db53-c7e2-418a-8803-
0e68d4b88607&createdTime=1623677858199&parentMessageId=1623677858199",
"from": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "5e91c375-f755-4882-880e-f1b9322faa87",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.teamArchivedEventMessageDetail",
"teamId": "5e91c375-f755-4882-880e-f1b9322faa87",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Team created
JSON
{
"id": "1623677858199",
"replyToId": null,
"etag": "1623677858199",
"messageType": "systemEventMessage",
"createdDateTime": "2021-06-14T13:37:38.199Z",
"lastModifiedDateTime": "2021-06-14T13:37:38.199Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A318c8c65f0794971a1a9b5e3413d77de
%40thread.tacv2/1623677858199?groupId=5e91c375-f755-4882-880e-
f1b9322faa87&tenantId=df81db53-c7e2-418a-8803-
0e68d4b88607&createdTime=1623677858199&parentMessageId=1623677858199",
"from": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "5e91c375-f755-4882-880e-f1b9322faa87",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.teamCreatedEventMessageDetail",
"teamId": "19:[email protected]",
"teamDisplayName": "Test Team",
"teamDescription": "This is a test team.",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
{
"id": "1618907417096",
"replyToId": null,
"etag": "1618907417096",
"messageType": "systemEventMessage",
"createdDateTime": "2021-04-20T08:30:17.096Z",
"lastModifiedDateTime": "2021-04-20T08:30:17.096Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3Ad0891bf6638f48e8be186e2e92b4a554
%40thread.tacv2/1618907417096?groupId=97a5ecc4-300b-4c5a-9f87-
ca9a4969b3e0&tenantId=df81db53-c7e2-418a-8803-
0e68d4b88607&createdTime=1618907417096&parentMessageId=1618907417096",
"from": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "97a5ecc4-300b-4c5a-9f87-ca9a4969b3e0",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type":
"#microsoft.graph.teamDescriptionUpdatedEventMessageDetail",
"teamId": "97a5ecc4-300b-4c5a-9f87-ca9a4969b3e0",
"teamDescription": "Team description updated",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "9ee3dc1b-6a70-4582-8bc5-5dd35336b6c3",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
{
"id": "1618907417096",
"replyToId": null,
"etag": "1618907417096",
"messageType": "systemEventMessage",
"createdDateTime": "2021-04-20T08:30:17.096Z",
"lastModifiedDateTime": "2021-04-20T08:30:17.096Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3Ad0891bf6638f48e8be186e2e92b4a554
%40thread.tacv2/1618907417096?groupId=97a5ecc4-300b-4c5a-9f87-
ca9a4969b3e0&tenantId=df81db53-c7e2-418a-8803-
0e68d4b88607&createdTime=1618907417096&parentMessageId=1618907417096",
"from": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "97a5ecc4-300b-4c5a-9f87-ca9a4969b3e0",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.teamJoiningDisabledEventMessageDetail",
"teamId": "97a5ecc4-300b-4c5a-9f87-ca9a4969b3e0",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "9ee3dc1b-6a70-4582-8bc5-5dd35336b6c3",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
{
"id": "1618907417096",
"replyToId": null,
"etag": "1618907417096",
"messageType": "systemEventMessage",
"createdDateTime": "2021-04-20T08:30:17.096Z",
"lastModifiedDateTime": "2021-04-20T08:30:17.096Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3Ad0891bf6638f48e8be186e2e92b4a554
%40thread.tacv2/1618907417096?groupId=97a5ecc4-300b-4c5a-9f87-
ca9a4969b3e0&tenantId=df81db53-c7e2-418a-8803-
0e68d4b88607&createdTime=1618907417096&parentMessageId=1618907417096",
"from": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "97a5ecc4-300b-4c5a-9f87-ca9a4969b3e0",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.teamJoiningEnabledEventMessageDetail",
"teamId": "97a5ecc4-300b-4c5a-9f87-ca9a4969b3e0",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "9ee3dc1b-6a70-4582-8bc5-5dd35336b6c3",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Team renamed
JSON
{
"id": "1618821548765",
"replyToId": null,
"etag": "1618821548765",
"messageType": "systemEventMessage",
"createdDateTime": "2021-04-19T08:39:08.765Z",
"lastModifiedDateTime": "2021-04-19T08:39:08.765Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3Ad0891bf6638f48e8be186e2e92b4a554
%40thread.tacv2/1618821548765?groupId=97a5ecc4-300b-4c5a-9f87-
ca9a4969b3e0&tenantId=df81db53-c7e2-418a-8803-
0e68d4b88607&createdTime=1618821548765&parentMessageId=1618821548765",
"from": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "97a5ecc4-300b-4c5a-9f87-ca9a4969b3e0",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.teamRenamedEventMessageDetail",
"teamId": "97a5ecc4-300b-4c5a-9f87-ca9a4969b3e0",
"teamDisplayName": "Team rename",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "9ee3dc1b-6a70-4582-8bc5-5dd35336b6c3",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
{
"id": "1620046494994",
"replyToId": null,
"etag": "1620046494994",
"messageType": "systemEventMessage",
"createdDateTime": "2021-05-03T12:54:54.994Z",
"lastModifiedDateTime": "2021-05-03T12:54:54.994Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3Ad0891bf6638f48e8be186e2e92b4a554
%40thread.tacv2/1620046494994?groupId=97a5ecc4-300b-4c5a-9f87-
ca9a4969b3e0&tenantId=df81db53-c7e2-418a-8803-
0e68d4b88607&createdTime=1620046494994&parentMessageId=1620046494994",
"from": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "97a5ecc4-300b-4c5a-9f87-ca9a4969b3e0",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.teamsAppInstalledEventMessageDetail",
"teamsAppId": "aa5fe6c5-f91c-45ed-88de-640e235ad21b",
"teamsAppDisplayName": "Flipgrid",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "06a5b888-ad96-455e-88ef-c059ec4e4cf0",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
{
"id": "1620046597520",
"replyToId": null,
"etag": "1620046597520",
"messageType": "systemEventMessage",
"createdDateTime": "2021-05-03T12:56:37.52Z",
"lastModifiedDateTime": "2021-05-03T12:56:37.52Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3Ad0891bf6638f48e8be186e2e92b4a554
%40thread.tacv2/1620046597520?groupId=97a5ecc4-300b-4c5a-9f87-
ca9a4969b3e0&tenantId=df81db53-c7e2-418a-8803-
0e68d4b88607&createdTime=1620046597520&parentMessageId=1620046597520",
"from": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "97a5ecc4-300b-4c5a-9f87-ca9a4969b3e0",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.teamsAppRemovedEventMessageDetail",
"teamsAppId": "aa5fe6c5-f91c-45ed-88de-640e235ad21b",
"teamsAppDisplayName": "Flipgrid",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "06a5b888-ad96-455e-88ef-c059ec4e4cf0",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
{
"id": "1620046597520",
"replyToId": null,
"etag": "1620046597520",
"messageType": "systemEventMessage",
"createdDateTime": "2021-05-03T12:56:37.52Z",
"lastModifiedDateTime": "2021-05-03T12:56:37.52Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3Ad0891bf6638f48e8be186e2e92b4a554
%40thread.tacv2/1620046597520?groupId=97a5ecc4-300b-4c5a-9f87-
ca9a4969b3e0&tenantId=df81db53-c7e2-418a-8803-
0e68d4b88607&createdTime=1620046597520&parentMessageId=1620046597520",
"from": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "97a5ecc4-300b-4c5a-9f87-ca9a4969b3e0",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.teamsAppUpgradedEventMessageDetail",
"teamsAppId": "aa5fe6c5-f91c-45ed-88de-640e235ad21b",
"teamsAppDisplayName": "Flipgrid",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "06a5b888-ad96-455e-88ef-c059ec4e4cf0",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
Team unarchived
JSON
{
"id": "1623678060910",
"replyToId": null,
"etag": "1623678060910",
"messageType": "systemEventMessage",
"createdDateTime": "2021-06-14T13:41:00.91Z",
"lastModifiedDateTime": "2021-06-14T13:41:00.91Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A318c8c65f0794971a1a9b5e3413d77de
%40thread.tacv2/1623678060910?groupId=5e91c375-f755-4882-880e-
f1b9322faa87&tenantId=df81db53-c7e2-418a-8803-
0e68d4b88607&createdTime=1623678060910&parentMessageId=1623678060910",
"from": null,
"policyViolation": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "5e91c375-f755-4882-880e-f1b9322faa87",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.teamUnarchivedEventMessageDetail",
"teamId": "5e91c375-f755-4882-880e-f1b9322faa87",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
See also
Microsoft Teams API overview
Manage phone numbers for bots
Article • 11/02/2022
This article describes how to use the cloud communications API in Microsoft Graph to
create a bot that is reachable through a phone number. As you create your bot, it will be
helpful to be familiar with the following terms:
One application can have multiple application instances, and each tenant can have
multiple application instances, as shown in the following image.
Calls.AccessMedia.All
Calls.Initiate.All
Calls.JoinGroupCall.All
Calls.JoinGroupCallAsGuest.All
For more information about call-related permissions, see the Permissions reference.
To create a new application instance, the tenant admin runs the following cmdlet:
Assign a calling plan to your application instance. For details, see Calling plans for
Microsoft 365.
To assign the phone number to the application instance, the tenant admin assigns a
service phone number (+11D format) using the following cmdlet:
See also
Teams API overview
Incident bot sample
Deploying the sample
Register a bot with the cloud
communications API
Article • 09/02/2022
You can use the cloud communications API in Microsoft Graph to build bots to respond
to your customers' needs and facilitate collaboration. This article describes how to
register your bot and then manage the state of your bot.
Prerequisites
Before you get started, it will be helpful to familiarize yourself with the following:
Azure Active Directory (Azure AD) and how the service helps employees sign in
and access resources.
The Azure Bot Service and its capabilities.
Register a bot
The terms "service application" and "bot" can be used interchangeably. You can either
create a bot through the Azure portal directly or register a bot that isn't hosted on
Azure. For more details about the bot registration process, see Registering a calling
bot .
To make things easier later, it's helpful to understand the different types of permissions
within Azure AD. Apps with delegated permissions require a signed-in user. Application-
based permissions don't need a signed-in user, and can often run as a background
service.
After you register your bot, if you'd like to add your bot to Microsoft Teams, make sure
you understand how to use app studio and define the required metadata.
Next, you can decide whether it's best for your bot to be stateful or stateless .
Stateless bots
Any virtual machine can handle any bot instance, which means that if one machine goes
down, another can take care of it. This makes for a resilient solution.
On the other hand, a shared cache, such as REDIS, needs to be accessible to all the
virtual machines.
Stateful bots
A virtual machine can handle only one bot instance at a time. Because all the states are
on one machine, there aren't any extra memory checks or REDIS cache checks.
The drawback is that because the bot instance is just on one machine, it isn't as resilient.
7 Note
If you're using stateless bots, install the Graph Communications Core SDK .
If you're using stateful bots, install the Graph Communications Calling SDK .
Examples
Learn how to implement different scenarios using stateful bots, such as answering an
incoming call with either application-hosted or service-hosted media.
Ad-hoc The bot interjects a message without interrupting the conversation flow.
proactive
message
Dialog-based The bot creates a new dialog thread, takes control of a conversation, delivers
proactive the proactive message, closes, and returns control to the previous dialog.
message
Permissions
Microsoft Graph teamsAppInstallation resource type permissions help you to manage
your app's installation lifecycle for all user (personal) or team (channel) scopes within the
Microsoft Teams platform:
To use these permissions, you must add a webApplicationInfo key to your app manifest
with the following values:
7 Note
Your bot requires application and not user delegated permissions because the
installation is for others.
) Important
Microsoft Graph can only install apps published to your organization's app store or
the Teams store.
Tip
HTTP
GET https://graph.microsoft.com/v1.0/appCatalogs/teamsApps?
$filter=externalId eq '{IdFromManifest}'
The request must return a teamsApp object id , which is the app's catalog
generated app ID. This is different from the ID that you provided in your Teams
app manifest:
JSON
{
"value": [
{
"id": "b1c5353a-7aca-41b3-830f-27d5218fe0e5",
"externalId": "f31b1263-ba99-435a-a679-911d24850d7c",
"name": "Test App",
"version": "1.0.1",
"distributionMethod": "Organization"
}
]
}
If your app has already been uploaded or sideloaded for a user in personal scope:
HTTP
GET https://graph.microsoft.com/v1.0/users/{user-
id}/teamwork/installedApps?$expand=teamsApp&$filter=teamsApp/externalId
eq '{IdFromManifest}'
If your app has already been uploaded or sideloaded for a channel in team scope:
HTTP
GET https://graph.microsoft.com/v1.0/teams/{team-id}/installedApps?
$expand=teamsApp&$filter=teamsApp/externalId eq '{IdFromManifest}'
Tip
To narrow the list of results, you can filter any of the fields of the teamsApp
object.
HTTP
GET https://graph.microsoft.com/v1.0/users/{user-id}/teamwork/installedApps?
$expand=teamsApp&$filter=teamsApp/id eq '{teamsAppId}'
POST https://graph.microsoft.com/v1.0/users/{user-id}/teamwork/installedApps
Content-Type: application/json
{
"[email protected]" :
"https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/{teamsAppId}"
}
If the user has Microsoft Teams running, app installation occurs immediately. A restart
may be required to view the installed app.
1. You must have your app's {teamsAppInstallationId} . If you don't have it, use the
following:
HTTP
GET https://graph.microsoft.com/v1.0/users/{user-
id}/teamwork/installedApps?$expand=teamsApp&$filter=teamsApp/id eq
'{teamsAppId}'
HTTP
GET https://graph.microsoft.com/v1.0/users/{user-
id}/teamwork/installedApps/{teamsAppInstallationId}/chat
HTTP
GET https://graph.microsoft.com/v1.0/users/{user-id}/chats?
$filter=installedApps/any(a:a/teamsApp/id eq '{teamsAppId}')
Code snippets
The following code provides an example of sending proactive messages:
C#
SDK reference
C#
return msgSentCount;
}
Code sample
Sample Name Description .NET Node.js
Proactive installation of This sample shows how you can use proactive View View
app and sending installation of app for users and send proactive
proactive notifications notifications by calling Microsoft Graph APIs.
See also
Manage app setup policies in Microsoft Teams
Send proactive notifications to users SDK v4
Send activity feed notifications to users in Microsoft Teams
Add app to team - Microsoft Graph v1.0
Microsoft Teams service limits
Protected APIs in Microsoft Teams
Call records
Article • 03/23/2023
Call records provide usage and diagnostic information about the calls and online
meetings that occur within your organization when using Microsoft Teams or Skype for
Business. Usage and diagnostic data can be consumed to produce custom reporting for
your business to help monitor adoption or to troubleshoot call quality issues.
Organizations can subscribe to changes to call records using the Microsoft Graph
webhook subscriptions capability, allowing them to build near-real-time reports from
the data or to alert on certain scenarios like emergency calls.
) Important
See also
Call records permissions
Teams API overview
Supported call types
Article • 09/02/2022
This article describes the supported call types in the cloud communications API in
Microsoft Graph and how they're used for the signaling process.
Peer-to-peer calls
A call is peer-to-peer (P2P) when one participant is directly calling another participant. If
a bot calls a user, and the user is the only calling target specified, this is an example of a
P2P call.
If a user wants to call a bot, the bot doesn't need any additional permissions in order to
respond to the P2P call. In order for a bot to call a user, it must have the Calls.Initiate.All
permission for a P2P call.
Group calls
A group call occurs if there are either three or more participants in the call, or if meeting
coordinates were specified when the call was initially created.
You can create a group call through Microsoft Teams, for example.
Currently, bots are able to:
See also
Teams API overview
Permissions for calls
Create or join online meetings
Article • 09/02/2022
Use the cloud communications API in Microsoft Graph to create or join online meetings.
Online meetings provide the ability to specify certain details, such as the subject of the
meeting and who all the attendees are. You can also set the date and time for when the
meeting starts and ends.
Online meetings provide the flexibility to create a meeting that takes place in the future
or instantaneously. The ability to set up a meeting that starts immediately after it is
created is ideal for unexpected issues and other incidents that require the immediate
attention of the attendees.
7 Note
This set of APIs allows the flexibility and richer integration with Microsoft Teams or
Skype capabilities; it does not update or create any event in a calendar. For a
convenient approach to add an online meeting to an Outlook calendar, use the
calendar API. See Choose an API in Microsoft Graph to create and join online
meetings for more information.
When all the participants leave the group call, the group call will end. Participants can
still rejoin the meeting afterward using the same meeting coordinates, but this will
create another group call.
7 Note
2. Through the create call API, which requires that you provide the meeting
coordinates, (organizermeetinginfo, and chatInfo).
See also
Online meeting permissions
Choose an API in Microsoft Graph to create and join online meetings
Teams API overview
Choose an API in Microsoft Graph to
create and join online meetings
Article • 11/15/2022
Microsoft Graph offers two API sets that arrange and join online meetings on Microsoft
Teams or Skype:
Programmatic support:
Apps can directly create or update an event as an online meeting in the Outlook
calendar, with a join-Teams-meeting blob inserted in the Outlook calendar
event.
Apps get properties for joining meeting over the Internet or by dialing in.
Attendees' UI experience with the programmatically created calendar event is in
full parity with any event that has been created through the Outlook UI:
Attendees can choose to meet online or in person.
Attendees can click in the join-Teams-meeting blob to join meeting over the
Internet or by dialing in.
Attendees can use other rich features of Teams, including video conferencing
and meeting lobby, if configured.
7 Note
Integration with Outlook calendar assumes an administrator has set up Outlook for
online meetings. Verify the support before using the API.
Choose the cloud communications API for flexibility and broader programmatic support:
Apps have more flexibility to further integrate the API results with line of business
and other apps. The API is decoupled with any specific calendar, and does not
create an event in any calendar.
Apps can provide the following capabilities for attendees:
Locale-based join information.
Joining meeting over the Internet or by dialing in.
Video-conferencing.
Additional security features such as meeting lobby and automating attendee
admission (preview).
Associating meeting with a Microsoft Teams chat.
Meeting lobby - No direct API integration. - API differentiates attendees from the
and - In the injected join-Teams- organizer’s company and federated
automating meeting blob of the event, companies, and other attendees including
attendee attendee can click a Meeting anonymous ones.
admission into options link to access meeting - Use the lobbyBypassSettings property.
online lobby, if enabled by the
meeting administrator.
Use the cloud communications API in Microsoft Graph to enable your bots to send and
receive audio- and video-related content. By making use of media, you can create a
more interactive experience between your bots and users.
This article helps you determine which media hosting option is right for you based on
your needs: service-hosted media or application-hosted media.
If your media needs are simpler, explore this option first. Because the heavy media
processing is offloaded remotely, this is a lighter weight solution that allows you to
build your bot in a more flexible way.
For an example that shows you how to create a bot that uses service-hosted media, see
the Remote media calling bot samples .
) Important
You cannot use the Media Access API to record or otherwise persist media content
from calls or meetings that your application accesses, or data derived from that
media content ("record" or "recording"), without first calling the
updateRecordingStatus API to indicate that recording has begun, and receiving a
success reply from that API.
If your application begins recording any meeting/call, it must end the recording
prior to calling the updateRecordingStatus API to indicate that the recording has
ended. Make sure you are compliant with the laws and regulations of your area
regarding data protection and confidentiality of communications. See the Terms of
Use and consult with your legal counsel for more information.
If you'd like more control over your media, choose this option. You'll have direct
access to media streams and will be able to make use of video-based screen sharing.
You'll be able to build more sophisticated IVR scenarios that are speech enabled. This is
a heavier weight solution that gives you the most flexibility in how you want to program
your media.
See also the requirements and considerations for application-hosted media bots.
For an example that shows you how to create a bot that uses application-hosted media,
see the local media samples .
See also
Calls permissions
Teams API overview
Online meeting artifacts and
permissions
Article • 09/10/2022
Online meeting artifacts are content produced for the duration of an online meeting or
Microsoft Teams live event. You can use the Get onlineMeeting operation to get the
following meeting artifacts:
Permissions
The following permissions are available to manage meeting artifacts:
OnlineMeeting.Read
OnlineMeeting.ReadWrite
OnlineMeeting.Read.All
OnlineMeeting.ReadWrite.All
After that date, the OnlineMeetingArtifact.Read.All permissions will be required to fetch
meeting artifacts; requests that do not have those permissions will be rejected.
See also
Teams API overview
Identify large gallery view participants
in a roster
Article • 09/02/2022
The cloud communications API in Microsoft Graph provides an endpoint for adding the
large gallery view to a call. After the large gallery view is successfully added to a call, you
can subscribe to a participant's video feed.
This article describes how to identify a large gallery view participant in a roster so that
you can retrieve the relevant data to subscribe to the video feed.
JSON
{
"@odata.type": "#microsoft.graph.commsNotifications",
"value": [
{
"@odata.type": "#microsoft.graph.commsNotification",
"changeType": "updated",
"resource": "/app/calls/5f201300-df95-4800-bd3a-
75b0af63dd2b/participants",
"resourceUrl": "/communications/calls/5f201300-df95-4800-bd3a-
75b0af63dd2b/participants",
"resourceData": [
{
"@odata.type": "#microsoft.graph.participant",
"info": {
"@odata.type": "#microsoft.graph.participantInfo",
"identity": {
"@odata.type": "#microsoft.graph.identitySet",
"application": {
"@odata.type": "#microsoft.graph.identity",
"id": "(redacted)",
"displayName": "(redacted)",
"identityProvider": "AAD",
}
},
"endpointType": "default",
"endpointId": "40213cfb-0934-4dce-9b3a-57c09adf6967",
"participantId": "23aeb644-6227-4f4a-b5c9-4d61c1f196d3",
},
"mediaStreams": [
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "audio",
"label": "main-audio",
"sourceId": "2472",
"direction": "sendReceive",
"serverMuted": false
}
],
"isMuted": false,
"isInLobby": false,
"meetingRole": "presenter",
"id": "23aeb644-6227-4f4a-b5c9-4d61c1f196d3"
},
{
"@odata.type": "#microsoft.graph.participant",
"info": {
"@odata.type": "#microsoft.graph.participantInfo",
"identity": {
"@odata.type": "#microsoft.graph.identitySet",
"user": {
"@odata.type": "#microsoft.graph.identity",
"id": "(redacted)",
"displayName": "(redacted)",
"identityProvider": "AAD"
}
},
"endpointType": "default",
"endpointId": "4a767d9b-dca5-4176-8f1b-2a0f98923569",
"participantId": "63ce9188-e754-4733-9e71-ccc829499a63",
},
"mediaStreams": [
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "audio",
"label": "main-audio",
"sourceId": "1652",
"direction": "sendReceive",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "video",
"label": "main-video",
"sourceId": "1653",
"direction": "sendReceive",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "videoBasedScreenSharing",
"label": "applicationsharing-video",
"sourceId": "1655",
"direction": "receiveOnly",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "data",
"label": "data",
"sourceId": "1656",
"direction": "sendReceive",
"serverMuted": false
}
],
"isMuted": false,
"isInLobby": false,
"meetingRole": "presenter",
"id": "63ce9188-e754-4733-9e71-ccc829499a63"
},
{
"@odata.type": "#microsoft.graph.participant",
"info": {
"@odata.type": "#microsoft.graph.participantInfo",
"identity": {
"@odata.type": "#microsoft.graph.identitySet",
"application": {
"@odata.type": "#microsoft.graph.identity",
"id": "(redacted)",
"identityProvider": "AAD",
"ApplicationType": "LargeGallery-V2"
}
},
"endpointType": "default",
"endpointId": "ccf24195-bd6d-4cbe-bc46-180a7fd3e9ba",
"participantId": "a34eae65-7aca-43ab-8332-80ab28629a54",
},
"mediaStreams": [
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "audio",
"label": "main-audio",
"sourceId": "2886",
"direction": "receiveOnly",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "video",
"label": "main-video",
"sourceId": "2887",
"direction": "sendReceive",
"serverMuted": false
}
],
"metadata": "{\"__platform\":{\"ui\":
{\"hidden\":true}},\"audienceView\":{\"id\":\"3c28fd97-6d51-4f2f-8bba-
82dcbf408ff6/1\",\"page\":1,\"status\":\"active\",\"type\":\"lg\",\"aspectRa
tio\":\"widescreen\"}}",
"isMuted": false,
"isInLobby": false,
"meetingRole": "presenter",
"id": "a34eae65-7aca-43ab-8332-80ab28629a54"
},
{
"@odata.type": "#microsoft.graph.participant",
"info": {
"@odata.type": "#microsoft.graph.participantInfo",
"identity": {
"@odata.type": "#microsoft.graph.identitySet",
"application": {
"@odata.type": "#microsoft.graph.identity",
"id": "(redacted)",
"identityProvider": "AAD",
"ApplicationType": "LargeGallery-V2"
}
},
"endpointType": "default",
"endpointId": "22726e72-fbf4-46c7-a5d7-36c682c3ba86",
"participantId": "8c4ca6bc-33e1-4da5-b6d6-a2fe61af605d",
},
"mediaStreams": [
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "audio",
"label": "main-audio",
"sourceId": "2673",
"direction": "receiveOnly",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "video",
"label": "main-video",
"sourceId": "2674",
"direction": "receiveOnly",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "data",
"label": "data",
"sourceId": "2685",
"direction": "sendReceive",
"serverMuted": false
}
],
"metadata": "{\"__platform\":{\"ui\":{\"hidden\":true}}}",
"isMuted": false,
"isInLobby": false,
"meetingRole": "presenter",
"id": "8c4ca6bc-33e1-4da5-b6d6-a2fe61af605d"
},
{
"@odata.type": "#microsoft.graph.participant",
"info": {
"@odata.type": "#microsoft.graph.participantInfo",
"identity": {
"@odata.type": "#microsoft.graph.identitySet",
"user": {
"@odata.type": "#microsoft.graph.identity",
"id": "(redacted)",
"displayName": "(redacted)",
"identityProvider": "AAD"
}
},
"endpointType": "default",
"endpointId": "c2bba3c4-ffff-ffff-eca6-782d381190f4",
"participantId": "3855ce6a-064e-402c-a1cf-2d78b4e1efbb",
},
"mediaStreams": [
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "audio",
"label": "main-audio",
"sourceId": "201",
"direction": "sendReceive",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "video",
"label": "main-video",
"sourceId": "202",
"direction": "receiveOnly",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "videoBasedScreenSharing",
"label": "applicationsharing-video",
"sourceId": "212",
"direction": "receiveOnly",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "data",
"label": "data",
"sourceId": "213",
"direction": "sendReceive",
"serverMuted": false
}
],
"metadata": "{\"holographicCapabilities\":3}",
"isMuted": true,
"isInLobby": false,
"meetingRole": "organizer",
"id": "3855ce6a-064e-402c-a1cf-2d78b4e1efbb"
},
{
"@odata.type": "#microsoft.graph.participant",
"info": {
"@odata.type": "#microsoft.graph.participantInfo",
"identity": {
"@odata.type": "#microsoft.graph.identitySet",
"user": {
"@odata.type": "#microsoft.graph.identity",
"id": "(redacted)",
"displayName": "(redacted)",
"identityProvider": "AAD"
}
},
"endpointType": "default",
"endpointId": "b8e00934-5ae7-4e8b-9933-1ed41d70e8c0",
"participantId": "f65b97d2-efda-471e-a2c5-bfe40146b11f",
},
"mediaStreams": [
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "audio",
"label": "main-audio",
"sourceId": "2267",
"direction": "sendReceive",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "video",
"label": "main-video",
"sourceId": "2268",
"direction": "sendReceive",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "videoBasedScreenSharing",
"label": "applicationsharing-video",
"sourceId": "2270",
"direction": "receiveOnly",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "data",
"label": "data",
"sourceId": "2271",
"direction": "sendReceive",
"serverMuted": false
}
],
"isMuted": false,
"isInLobby": false,
"publishedStates": [],
"meetingRole": "presenter",
"id": "f65b97d2-efda-471e-a2c5-bfe40146b11f"
}
]
}
]
}
JSON
{
"@odata.type": "#microsoft.graph.participant",
"info": {
"@odata.type": "#microsoft.graph.participantInfo",
"identity": {
"@odata.type": "#microsoft.graph.identitySet",
"application": {
"@odata.type": "#microsoft.graph.identity",
"id": "(redacted)",
"identityProvider": "AAD",
"ApplicationType": "LargeGallery-V2"
}
},
"endpointType": "default",
"endpointId": "ccf24195-bd6d-4cbe-bc46-180a7fd3e9ba",
"participantId": "a34eae65-7aca-43ab-8332-80ab28629a54",
},
"mediaStreams": [
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "audio",
"label": "main-audio",
"sourceId": "2886",
"direction": "receiveOnly",
"serverMuted": false
},
{
"@odata.type": "#microsoft.graph.mediaStream",
"mediaType": "video",
"label": "main-video",
"sourceId": "2887",
"direction": "sendReceive",
"serverMuted": false
}
],
"metadata": "{\"__platform\":{\"ui\":
{\"hidden\":true}},\"audienceView\":{\"id\":\"3c28fd97-6d51-4f2f-8bba-
82dcbf408ff6/1\",\"page\":1,\"status\":\"active\",\"type\":\"lg\",\"aspectRa
tio\":\"widescreen\"}}",
"isMuted": false,
"isInLobby": false,
"meetingRole": "presenter",
"id": "a34eae65-7aca-43ab-8332-80ab28629a54"
}
C#
/// <summary>
/// Metadata for large gallery view
/// </summary>
[DataContract]
public class AudienceView
{
/// <summary>
/// Unique view id
/// </summary>
[DataMember(Name = "id")]
public string Id { get; set; }
/// <summary>
/// Page Number
/// </summary>
[DataMember(Name = "page")]
public int Page { get; set; }
/// <summary>
/// Signal that page is Active/Inactive
/// </summary>
[DataMember(Name = "status")]
public string Status { get; set; }
}
See also
Teams API overview
Manage watermarks for sensitive Teams
meetings
Article • 04/08/2023
This article describes how to use the cloud communications API in Microsoft Graph to
manage the watermark option for sensitive Microsoft Teams meetings. For a description
of the watermark meetings feature, licensing, and policy requirements to use this
feature, see Require a watermark for sensitive Teams meetings.
Use the following REST calls to manage watermark protection for sensitive Teams
meetings.
Request
HTTP
POST /me/onlineMeetings
{
"subject": "meeting",
"startDateTime": "2022-07-01T22:57:47.6388574Z",
"endDateTime": "2022-07-01T23:57:47.6388574Z",
"watermarkProtection": {
"isEnabledForContentSharing": true,
"isEnabledForVideo": false
}
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"subject": "meeting",
"startDateTime": "2022-07-01T22:57:47.6388574Z",
"endDateTime": "2022-07-01T23:57:47.6388574Z",
"watermarkProtection": {
"isEnabledForContentSharing": true,
"isEnabledForVideo": false
},
...
}
7 Note
Updating the watermark properties has no effect on meeting calls that have already
started.
Request
HTTP
PATCH /me/onlineMeetings/{meetingId}
{
...
"watermarkProtection": {
"isEnabledForContentSharing" : true,
"isEnabledForVideo" : false
}
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
...
"watermarkProtection": {
"isEnabledForContentSharing" : true,
"isEnabledForVideo" : false
}
}
Request
HTTP
GET /me/onlineMeetings/{meetingId}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
...
"watermarkProtection": {
"isEnabledForContentSharing" : true,
"isEnabledForVideo" : false
}
}
To indicate this restricted experience, each participant in the call roster and the list
participants API have a new restrictedExperience property that shows
watermarkProtection as the reason for the restricted media experience.
Request
HTTP
GET
https://graph.microsoft.com/beta/communications/calls/{callId}/participants
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"value":[
{
"@odata.type":"#microsoft.graph.participant",
"info":{
"@odata.type":"#microsoft.graph.participantInfo",
"identity":{
"@odata.type":"#microsoft.graph.identitySet",
"user":{
"@odata.type":"#microsoft.graph.identity",
"id":"f2fa86af-3c51-4bc2-8fc0-475452d9764f",
"displayName":"Organizer"
}
},
},
"id":"14319a53-bae8-4129-9cf1-9619ab278b28",
"metadata":null,
"restrictedExperience": {
"videoDisabled": "watermarkProtection"
}
},
{
"@odata.type":"#microsoft.graph.participant",
"info":{
"@odata.type":"#microsoft.graph.participantInfo",
"identity":{
"@odata.type":"#microsoft.graph.identitySet",
"guest":{
"@odata.type":"#microsoft.graph.identity",
"id":"9714e06e-8c29-4703-8e89-9c3cdaa56391",
"displayName":"AnonymousUser1"
}
},
},
"id":"a7ebfb2d-871e-419c-87af-27290b22e8db",
"metadata":null,
"restrictedExperience": {
"videoDisabled": "watermarkProtection"
}
},
{
"@odata.type":"#microsoft.graph.participant",
"info":{
"@odata.type":"#microsoft.graph.participantInfo",
"identity":{
"@odata.type":"#microsoft.graph.identitySet",
"guest":{
"@odata.type":"#microsoft.graph.identity",
"id":"38ef1c9d-6a01-4bc2-b5aa-5535952298f7",
"displayName":"AnonymousUser2"
}
},
},
"id":"b35e843e-7771-478a-9dde-2dfed177bfe0",
"metadata":null,
"restrictedExperience": {
"videoDisabled": "watermarkProtection"
}
}
],
"@odata.context":"https://graph.microsoft.com/beta/$metadata#communications/
calls{callId}/participants"
}
Change notifications for Microsoft
Teams resources
Article • 10/04/2022
Change notifications for Microsoft Teams resources using Microsoft Graph enable you to
subscribe to changes (create, update, and delete) to a resource. Change notifications
provide a low latency model by allowing you to maintain a subscription. You can also
get the resource data in the notifications and therefore avoid calling the API to get the
payload.
7 Note
Change notification to track all changes related to a resource across the tenant:
For example, you can subscribe to changes in messages in any channel across the
tenant and get notified whenever a message is created, updated, or deleted in any
channel in the tenant. These notifications may have licensing and payment
requirements, such as change notifications for messages and membership.
Change notification to track all changes for a specific resource: For example, you
can subscribe to changes in messages in a particular channel and get notified
whenever a message is created, updated, or deleted in that channel.
For details about which resources support which types of change notifications, see
Microsoft Graph change notifications.
Supported resources
The following table lists the Microsoft Teams resources that support change notifications
and their corresponding resource paths. Apply the resource path for your scenario as
specified when creating a subscription. The type of the resource path payload is the type
under the "Resource" column, or a collection of that type.
Resource Supported resource paths Resource
data can be
included in
notifications
Teams chatMessage Changes to chat messages in all channels in all teams: Yes
/teams/getAllMessages
Changes to chat messages in a specific channel:
/teams/{id}/channels/{id}/messages
Changes to chat messages in all chats:
/chats/getAllMessages
Changes to chat messages in a specific chat:
/chats/{id}/messages
Changes to chat messages in all chats a particular user is part
of:
/users/{id}/chats/getAllMessages
Changes to chat messages in all the chats in the tenant where
a particular Teams app is installed:
/appCatalogs/teamsApps/{id}/installedToChats/getAllMessages
Notification payloads
Depending on your subscription, you can either get the notification with resource data,
or without resource data. Subscribing with resource data allows you to get the message
payload along with the notification, which removes the need to call back and get the
content.
JSON
{
"value": [{
"subscriptionId": "10493aa0-4d29-4df5-bc0c-ef742cc6cd7f",
"changeType": "created",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-02-02T10:30:34.9097561-
08:00",
"resource": "chats('19:8ea0e38b-efb3-4757-924a-
5f94061cf8c2_97f62344-57dc-409c-88ad-
[email protected]')/messages('1612289765949')",
"resourceData": {
"id": "1612289765949",
"@odata.type": "#Microsoft.Graph.chatMessage",
"@odata.id": "chats('19:8ea0e38b-efb3-4757-924a-
5f94061cf8c2_97f62344-57dc-409c-88ad-
[email protected]')/messages('1612289765949')"
},
"encryptedContent": {
"data": "<<--EncryptedContent-->",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}],
"validationTokens": ["<<--ValidationTokens-->>"]
}
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
The decrypted notification payload looks like the following. The decrypted payload for
the previous example conforms to the chatMessage schema. The payload is similar to
that returned by GET operations.
JSON
{
"id": "1612289992105",
"replyToId": null,
"etag": "1612289992105",
"messageType": "message",
"createdDateTime": "2021-02-02T18:19:52Z",
"lastModifiedDateTime": "2021-02-02T18:19:52.105Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:8ea0e38b-efb3-4757-924a-5f94061cf8c2_97f62344-57dc-409c-
[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"from": {
"application": null,
"device": null,
"user": {
"id": "8ea0e38b-efb3-4757-924a-5f94061cf8c2",
"displayName": "Ramjot Singh",
"userIdentityType": "aadUser"
},
"conversation": null
},
"body": {
"contentType": "text",
"content": "test"
},
"channelIdentity": null,
"attachments": [],
"mentions": [],
"policyViolation": null,
"reactions": [],
"replies": [],
"hostedContents": []
}
The payload looks like the following. This payload is for a message sent in a channel.
JSON
{
"subscriptionId": "9f9d1ed0-c9cc-42e7-8d80-a7fc4b0cda3c",
"changeType": "created",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"clientState": "<<--SpecifiedClientState-->>",
"subscriptionExpirationDateTime": "2021-02-02T11:26:41.0537895-08:00",
"resource": "teams('fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b')/channels('19:[email protected]')/
messages('1612293113399')",
"resourceData": {
"id": "1612293113399",
"@odata.type": "#Microsoft.Graph.chatMessage",
"@odata.id": "teams('fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b')/channels('19:[email protected]')/
messages('1612293113399')"
}
}
7 Note
GET calls always return the current state of the resource. If the resource is changed
between when the notification is sent and when the resource is retrieved, the
operation returns the updated resource.
See also
Microsoft Graph change notifications
Get change notifications for teams and channels using Microsoft Graph
Get change notifications for membership changes in teams and channels using
Microsoft Graph
Get change notifications for messages in Teams channels and chats using
Microsoft Graph
Get change notifications for chats using Microsoft Graph
Get change notifications for chat membership using Microsoft Graph
Microsoft Teams API overview
Get change notifications for Microsoft
Teams meeting call updates
Article • 03/01/2023
A subscription has a max expiry period of 3 days. To persist the subscription for more
than this period, a subscription renewal request must be made. For details, see Update
subscription. Alternatively, a user can wait for the subscription to expire and create a
new subscription with the same meeting resource.
This resource supports notifications with resource data. For more information about
setting up notifications with resource data, see Set up change notifications that include
resource data.
Permissions
Example
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-Type: application/json
{
"changeType": "updated",
"notificationUrl":
"https://webhook.azurewebsites.net/api/resourceNotifications",
"resource": "/communications/onlineMeetings/?$filter=JoinWebUrl eq
'{JoinWebUrl}'",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2021-02-01T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}
7 Note
Replace {JoinWebUrl} with the actual value when specifying the resource. The
JoinWebURL for the meeting is included in the joinWebUrl property of the
onlineMeeting resource, or in the Teams client for a meeting.
{
"value": [{
"subscriptionId": "{Subscription id}",
"clientState": "{secret client state}",
"changeType": "updated",
"tenantId": "{Organization/Tenant id}",
"resource": "communications/onlineMeetings?
$filter=joinWebUrl+eq+'{joinWebUrl}'",
"subscriptionExpirationDateTime": "2022-02-28T00:00:00.0000000Z",
"resourceData": {
"@odata.id": "communications/onlineMeetings?
$filter=joinWebUrl+eq+'{joinWebUrl}'",
"@odata.type": "#microsoft.graph.onlineMeeting",
"id": "communications/onlineMeetings?
$filter=joinWebUrl+eq+'{joinWebUrl}'"
},
"organizationId": "{Organization/Tenant id}",
"encryptedContent": {
"data": "{Encrypted content}",
"dataSignature": "{Encrypted data signature}",
"dataKey": "{Encrypted data key for encrypting content}",
"encryptionCertificateId": "{User specified id of encryption
certificate}",
"encryptionCertificateThumbprint": "{Encrpytion certification
thumbprint}"
}
}],
"validationTokens": ["{Validation Tokens}"]
}
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
CallStarted
JSON
{
"@odata.type":"#Microsoft.Graph.onlineMeeting",
"@odata.id":"communications/onlineMeetings?
$filter=joinWebUrl+eq+'{joinWebUrl}'",
"id":"communications/onlineMeetings?$filter=joinWebUrl+eq+'{joinWebUrl}'",
"eventType":"{Microsoft.Communication.CallStarted}",
"eventDateTime":"2022-02-28T00:00:00.0000000Z",
"state":"active"
}
CallEnded
JSON
{
"@odata.type":"#Microsoft.Graph.onlineMeeting",
"@odata.id":"communications/onlineMeetings?
$filter=joinWebUrl+eq+'{joinWebUrl}'",
"id":"communications/onlineMeetings?$filter=joinWebUrl+eq+'{joinWebUrl}'",
"eventType":"{Microsoft.Communication.CallEnded}",
"eventDateTime":"2022-02-28T00:00:00.0000000Z",
"state":"inactive"
}
CallRosterUpdate
JSON
{
"@odata.type":"#Microsoft.Graph.onlineMeeting",
"@odata.id":"communications/onlineMeetings?
$filter=joinWebUrl+eq+'{joinWebUrl}'",
"id":"communications/onlineMeetings?$filter=joinWebUrl+eq+'{joinWebUrl}'",
"eventType":"Microsoft.Communication.CallRosterUpdate",
"eventDateTime":"2022-02-28T00:00:00.0000000Z",
"activeParticipants@joined": [
{
"Id": "a4d67b60-56a5-4202-9f1c-f123ff40621e",
"Identity":
{
"User":
{
"Id": "f92ca67f-0564-414b-8caa-8c95b8099928",
"DisplayName": "user display name",
"TenantId": "85045508-f5bd-405e-a553-52700f86e29c"
}
}
}
],
"activeParticipants@exited": [
{
"Id": "11141402-1b62-4795-b540-4ffee8544231",
"Identity":
{
"AzureCommunicationServicesUser":
{
"AzureCommunicationServicesResourceId": "534c244d-49f8-47a1-9e8e-
70d115a2ef4d",
"Id": "8:acs:534c244d-49f8-47a1-9e8e-70d115a2ef4d_28f01a7b-42cd-
4e37-ae1a-bd653377f4b7",
"DisplayName": "acs user display name"
}
}
}
]
}
JSON
{
"Id": "string",
"Identity": "microsoft.graph.communicationsIdentitySet"
}
See also
Microsoft Graph change notifications
Microsoft Teams API overview
Online meeting resource
Meeting notification C# sample
Meeting notification Node.js sample
Create teams and manage members
using the Microsoft Teams API
Article • 06/30/2022
You can use the Microsoft Teams API in Microsoft Graph to create teams in multiple
ways. This article describes the approach that we recommend for the best results.
Create a team
All teams are backed by Microsoft 365 groups. The quickest way to get your team up
and running when you create new teams via Microsoft Graph is to set up a new
Microsoft 365 group, all owners and members, and convert that into a team.
1. Create a Microsoft 365 group using the create group operation. You can specify
owners and members. Make sure that you have the right owners for the newly
created group, as described in Step 2.
To create a team for this group, you need to set the following property values, as
shown:
groupTypes = { "Unified" }
mailEnabled = true
securityEnabled = false
HTTP
POST /groups
{
"displayName":"Flight 157",
"mailNickname":"flight157",
"description":"Everything about flight 157",
"visibility":"Private",
"groupTypes":["Unified"],
"mailEnabled":true,
"securityEnabled":false,
"[email protected]":[
"https://graph.microsoft.com/v1.0/users/bec05f3d-a818-4b58-
8c2e-2b4e74b0246d",
"https://graph.microsoft.com/v1.0/users/ae67a4f4-2308-4522-
9021-9f402ff0fba8",
"https://graph.microsoft.com/v1.0/users/eab978dd-35d0-4885-
8c46-891b7d618783",
"https://graph.microsoft.com/v1.0/users/6a1272b5-f6fc-45c4-
95fe-fe7c5a676133"
],
"[email protected]":[
"https://graph.microsoft.com/v1.0/users/6a1272b5-f6fc-45c4-
95fe-fe7c5a676133",
"https://graph.microsoft.com/v1.0/users/eab978dd-35d0-4885-
8c46-891b7d618783"
]
}
Note: The response object shown might be shortened for readability. All the
properties will be returned from an actual call.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups/$en
tity",
"id":"b7f968af-ca51-42f6-a77e-82c7147bc8f2"
}
2. Ensure the group has two or more owners. You can do so via the add owner
operation. These should be real user accounts and not service accounts. Having
two owners helps handle cases where one owner leaves the company or is
unavailable to perform team management operations.
3. Add all members (and guests if necessary) to the group using the add member
operation, if you didn't do so in Step 1. If you're adding multiple members, add a 1
second delay after each add operation.
4. After the group is successfully created, which can take up to 15 minutes after
completing Step 1, create a Microsoft Teams team using the create team from
group operation. If you run into an error, the group creation process might not be
completed; try waiting a few more minutes.
HTTP
POST https://graph.microsoft.com/v1.0/teams
Content-Type: application/json
{
"[email protected]":
"https://graph.microsoft.com/v1.0/teamsTemplates('standard')",
"[email protected]":
"https://graph.microsoft.com/v1.0/groups('groupId')"
}
Note: The response object shown might be shortened for readability. All the
properties will be returned from an actual call.
HTTP
5. After this process finishes, all owners and members should be able to see the
newly created team in their Teams client.
2. The background process is triggered only if one or more users in the team (owner
or member) is active in the Teams desktop client. Launching the Teams application
and/or having it running constitutes activity — a user doesn't need to visit the
team that is being modified specifically.
7 Note
The Teams mobile clients don't trigger the membership sync. At least one user
should be on the desktop client to that ensure this background process goes
smoothly.
Checklist for validation
After you create a team, you can use the following checklist to verify that the team was
created successfully.
2. Verify that the team creation succeeded via the Teams admin portal.
3. Verify that the team has the correct owners and members listed via the Teams
admin portal.
4. Verify that the team owners can see the team after signing into the Teams desktop
or web client.
5. Verify that members can see the team after signing into the Teams desktop or web
client.
2. Verify that newly added members can see the team after signing into the Teams
desktop or web client.
See also
Microsoft Teams API overview
List all teams in Microsoft Teams for an
organization
Article • 06/30/2022
To use the Microsoft Teams API in Microsoft Graph to list all teams in an organization
(tenant), you find all groups that have teams, and then get information for each team.
Use the API with $filter to return only the groups that have teams.
Request
HTTP
7 Note
Certain unused old teams will not have resourceProvisioningOptions set. For
details, see known issues.
Response
The following is an example of the response.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#groups",
"value": [
{
"id": "02bd9fd6-8f93-4758-87c3-1fb73740a315",
"description": "Welcome to the HR Taskforce team.",
"displayName": "HR Taskforce",
"groupTypes": [
"Unified"
],
"mailEnabled": true,
"mailNickname": "HRTaskforce",
"resourceBehaviorOptions": [],
"resourceProvisioningOptions": [
"Team"
],
"securityEnabled": false,
"visibility": "Private"
},
{
"id": "8090c93e-ba7c-433e-9f39-08c7ba07c0b3",
"description": "Welcome to the team that we've assembled to
launch our product.",
"displayName": "X1050 Launch Team",
"groupTypes": [
"Unified"
],
"mailEnabled": true,
"mailNickname": "X1050LaunchTeam",
"resourceBehaviorOptions": [],
"resourceProvisioningOptions": [
"Team"
],
"securityEnabled": false,
"visibility": "Private"
}
]
}
Request
HTTP
GET /groups?$select=id,resourceProvisioningOptions
7 Note
Certain unused old teams will not have resourceProvisioningOptions set. For
details, see known issues.
Response
The following is an example of the response.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#groups",
"value": [
{
"id": "00e897b1-70ba-4cb9-9126-fd5f95c4bb78",
"resourceProvisioningOptions": []
},
{
"id": "00f6e045-f884-4359-a617-d459ee626862",
"resourceProvisioningOptions": [
"Team"
]
}
]
}
Request
HTTP
GET /teams/{group-id}
Response
The following example shows the response.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"isArchived" : false,
"memberSettings": {
"allowCreateUpdateChannels": true,
"allowDeleteChannels": true,
"allowAddRemoveApps": true,
"allowCreateUpdateRemoveTabs": true,
"allowCreateUpdateRemoveConnectors": true
},
"guestSettings": {
"allowCreateUpdateChannels": true,
"allowDeleteChannels": true
},
"messagingSettings": {
"allowUserEditMessages": true,
"allowUserDeleteMessages": true,
"allowOwnerDeleteMessages": true,
"allowTeamMentions": true,
"allowChannelMentions": true
},
"funSettings": {
"allowGiphy": true,
"giphyContentRating": "strict",
"allowStickersAndMemes": true,
"allowCustomMemes": true
}
}
See also
List joinedTeams
List groups
Microsoft Teams API overview
Embed Microsoft Teams in your app
Article • 03/30/2023
This article describes how to embed the Microsoft Teams experience within your
application. When you embed Teams in your app, your users can read and send Teams
messages directly from your app, without having to switch between your app and
Teams.
To improve your app's response time and help lower costs, you'll want to minimize the
number of times a message is read from Microsoft Graph. This article explains how to
retrieve messages once and cache them, and then use change notifications to get only
the subsequent messages.
7 Note
You might also choose to have the server component, instead of the chat UI,
make all the API requests to Teams APIs, and cache all the messages. For
example, if you have another backend system component that also needs to
make API requests, such as for compliance and auditing, you might choose to
centralize the API requests and caching on the server component instead.
A cache that persists messages. To improve the response time for your application
and to potentially lower the costs for you, minimize reading the same message
multiple times by storing messages in this cache. You do not want to be surprised
by the API consumption charges later. To learn how to set up a cache, see Add
caching to improve performance in Azure API Management.
Some Teams APIs have licensing and payment requirements. For details, see
Payment models and licensing requirements for details.
After you set up these components, you can start using Teams APIs.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/chats
Content-Type: application/json
{
"chatType": "group",
"members": [
{
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": [
"owner"
],
"[email protected]":
"https://graph.microsoft.com/v1.0/users('[email protected]')"
},
{
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": [
"owner"
],
"[email protected]":
"https://graph.microsoft.com/v1.0/users('[email protected]')"
},
{
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": [
"owner"
],
"[email protected]":
"https://graph.microsoft.com/v1.0/users('4562bcc8-c436-4f95-b7c0-
4f8ce89dca5e')"
}
]
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#chats/$entity",
"id": "19:[email protected]",
"topic": null,
"createdDateTime": "2023-01-11T01:34:18.929Z",
"lastUpdatedDateTime": "2023-01-11T01:34:18.929Z",
"chatType": "group",
"webUrl":
"https://teams.microsoft.com/l/chat/19%3Ab1234aaa12345a123aa12aa12aaaa1a9%40
thread.v2/0?tenantId=4dc1fe35-8ac6-4f0d-904a-7ebcd364bea1",
"tenantId": "4dc1fe35-8ac6-4f0d-904a-7ebcd364bea1",
"viewpoint": null,
"onlineMeetingInfo": null
}
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/chats/19:b1234aaa12345a123aa12aa12aaaa1
[email protected]/messages
Content-type: application/json
{
"body": {
"content": "Hello World"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#chats('19:b1234aaa12345a123aa12a
a12aaaa1a9%40thread.v2')/messages/$entity",
"id": "1673482643198",
"replyToId": null,
"etag": "1673482643198",
"messageType": "message",
"createdDateTime": "2023-01-12T00:17:23.198Z",
"lastModifiedDateTime": "2023-01-12T00:17:23.198Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"channelIdentity": null,
"policyViolation": null,
"eventDetail": null,
"from": {
"application": null,
"device": null,
"user": {
"id": "87d349ed-44d7-43e1-9a83-5f2406dee5bd",
"displayName": "John Smith",
"userIdentityType": "aadUser"
}
},
"body": {
"contentType": "text",
"content": "Hello world"
},
"attachments": [],
"mentions": [],
"reactions": []
}
To improve the response time for your application, to minimize throttling, and to
potentially lower the costs for you, minimize reading the same message multiple times.
Use the GET HTTP method as a one-time export, or when the change notifications have
expired and you want to sync the messages again. Otherwise, rely on your cache and
change notifications.
Get all messages from all chats (across all chats): GET /users/{user-id | user-
principal-name}/chats/getAllMessages
List messages in a chat (per chat): GET /chats/{chat-id}/messages
By using /getAllMessages , you can get messages across all chats for a user. This API is
designed for backend applications, such as audit and compliance applications, which
often get messages across all chats at once. It supports application permissions only.
Also, this is a metered API.
By using /messages , you can make API calls from the UI using delegated permissions, as
described in Step 1.
Different APIs have different throttling limits. For example, the per-chat /messages API
has a limit of 30 requests per second (rps) per app per tenant. If a tenant has 50 users
and each user has 15 chats on average, and you want to retrieve messages for all users
and all chats at the start of your system, you would need at least 50 users x 15 chat
requests/user = 750 requests. In this case, it's best to spread the requests over at least
750 requests / 30 rps = 25 seconds. Because there is a limit (maximum $top=50 ) to the
number of messages that are returned in a response, you might need to make multiple
requests to get all the messages.
The following example shows how to use the per-chat /messages API. By default, the
returned list of messages is sorted by lastModifiedDateTime . This example sorts by
createdDateTime. The sorting is specified via the orderBy query parameter in the
request.
Typical interactive messaging apps display only the most recent messages by default,
and users can then load older messages by paging, scrolling, or clicking. To retrieve only
the messages that you need, both APIs above also support filtering (for example,
$top=10 , $filter=lastModifiedDateTime gt 2019-03-17T07:13:28.000z ).
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users/87d349ed-44d7-43e1-9a83-
5f2406dee5bd/chats/19:[email protected]/message
s?$top=2&$filter=lastModifiedDateTime gt 2021-03-
17T07:13:28.000z&$orderBy=createdDateTime desc
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('87d349ed-44d7-43e1-9a83-
5f2406dee5bd')/chats('19%3Ab1234aaa12345a123aa12aa12aaaa1a9%40thread.v2')/me
ssages",
"@odata.count": 2,
"@odata.nextLink": "https://graph.microsoft.com/v1.0/users/87d349ed-
44d7-43e1-9a83-
5f2406dee5bd/chats/19:[email protected]/messages?
$top=2&$filter=lastModifiedDateTime+gt+2021-03-
17T07%3a13%3a28.000z&$orderBy=createdDateTime+desc&$skiptoken=A111wwAwAA1ww1
AwA1wwA1Aww111AA1wAwAAwAAwAAAwA1w1AAAwAAwww1Aww1AwAAwwAAA1AA1wAwAAw111wA11AA
Aww11Aw1wwww1wAwwwAAwwAwAwAAw1",
"value": [
{
"id": "1673543687527",
"replyToId": null,
"etag": "1673543687527",
"messageType": "message",
"createdDateTime": "2023-01-12T17:14:47.527Z",
"lastModifiedDateTime": "2023-01-12T17:14:47.527Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"channelIdentity": null,
"policyViolation": null,
"eventDetail": null,
"from": {
"application": null,
"device": null,
"user": {
"id": "6789f158-72b1-4a63-9959-1f006381132b",
"displayName": "Adele Vance",
"userIdentityType": "aadUser",
"tenantId": "4dc1fe35-8ac6-4f0d-904a-7ebcd364bea1"
}
},
"body": {
"contentType": "html",
"content": "<p>Good morning, world!</p>"
},
"attachments": [],
"mentions": [],
"reactions": []
},
{
"id": "1673482643198",
"replyToId": null,
"etag": "1673482643198",
"messageType": "message",
"createdDateTime": "2023-01-12T00:17:23.198Z",
"lastModifiedDateTime": "2023-01-12T00:17:23.198Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": "19:[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"channelIdentity": null,
"policyViolation": null,
"eventDetail": null,
"from": {
"application": null,
"device": null,
"user": {
"id": "87d349ed-44d7-43e1-9a83-5f2406dee5bd",
"displayName": "John Smith",
"userIdentityType": "aadUser",
"tenantId": "4dc1fe35-8ac6-4f0d-904a-7ebcd364bea1"
}
},
"body": {
"contentType": "text",
"content": "Hello world"
},
"attachments": [],
"mentions": [],
"reactions": []
}
]
}
In this example, the contentType can be either text or html ; make sure that your
application can display both.
To get images embedded in the chat message, make a second call to retrieve
chatMessageHostedContent. For details, see Get chatMessageHostedContent.
JSON
{
"id": "1616883610266",
"replyToId": null,
"etag": "1616883610266",
"messageType": "systemEventMessage",
"createdDateTime": "2021-03-28T03:50:10.266Z",
"lastModifiedDateTime": "2021-03-28T03:50:10.266Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": null,
"summary": null,
"chatId": null,
"importance": "normal",
"locale": "en-us",
"webUrl":
"https://teams.microsoft.com/l/message/19%3A4a95f7d8db4c4e7fae857bcebe0623e6
%40thread.tacv2/1616883610266?groupId=fbe2bf47-16c8-47cf-b4a5-
4b9b187c508b&tenantId=2432b57b-0abd-43db-aa7b-
16eadd115d34&createdTime=1616883610266&parentMessageId=1616883610266",
"policyViolation": null,
"from": null,
"body": {
"contentType": "html",
"content": "<systemEventMessage/>"
},
"channelIdentity": {
"teamId": "fbe2bf47-16c8-47cf-b4a5-4b9b187c508b",
"channelId": "19:[email protected]"
},
"onBehalfOf": null,
"attachments": [],
"mentions": [],
"reactions": [],
"eventDetail": {
"@odata.type": "#microsoft.graph.membersAddedEventMessageDetail",
"visibleHistoryStartDateTime": "0001-01-01T00:00:00Z",
"members": [{
"id": "06a5b888-ad96-455e-88ef-c059ec4e4cf0",
"displayName": null,
"userIdentityType": "aadUser"
},
{
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
],
"initiator": {
"application": null,
"device": null,
"user": {
"id": "9ee3dc1b-6a70-4582-8bc5-5dd35336b6c3",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}
If you want to track only specific chats, /messages is an option, but you should consider
how many different chats you’ll need to track. There’s a limit (for example, 10,000) on
the number of per-chat change notifications; for details, see subscriptions. Instead,
consider subscribing to one of the three /getAllMessages options, which get messages
across all chats of a user, tenant, or app.
All four options are called by your backend server component. Because they all support
application permissions, pay attention to the access control logic to show and hide chats
accordingly as users join or leave. The per-user option, which also supports delegated
permissions, might be easier to implement, because the change notifications are already
user specific; however, this it might be more expensive in the long run because the same
message would trigger multiple change notifications, one for each subscribed user, and
you might need a bigger cache to store the duplicated messages. For more details
about permissions and licensing requirements for the different subscribed resources, see
Create subscription.
When creating the subscription, make sure that the includeResourceData property is set
to true , and that you have specified the encryptionCertificate and
encryptionCertificateId properties. Otherwise, the encrypted content won't be returned
in the change notifications. For details, see Set up change notifications that include
resource data.
The following example shows how to get all messages per user. Before you use this
example, the subscription notification endpoint (specified in the notificationUrl
property) must be able to respond to a validation request, as described in Set up
notifications for changes in user data. If the validation fails, the request to create the
subscription returns a 400 Bad Request error.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-type: application/json
{
"changeType": "created,updated,deleted",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "/users/87d349ed-44d7-43e1-9a83-
5f2406dee5bd/chats/getAllMessages?model=B",
"expirationDateTime": "2023-01-10T18:56:49.112603+00:00",
"clientState": "ClientSecret",
"includeResourceData": true,
"encryptionCertificate":
"MMMM/sMMMsssMsMMMsMMsMMMs4sMMsM4ssMsMsMMMss4ssMMMssss...s4sMMMMsM444ssM
4MMsssMMMMsM4MMM4sMsM4MMsM44MMM4ssss4Ms4sMM4MMMMM4MMs+ss4MsMssMss4s==",
"encryptionCertificateId": "44M4444M4444M4M44MM4444MM4444MMMM44MM4M4"
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
"id": "88aa8a88-88a8-88a8-8888-88a8aa88a88a",
"resource": "/users/87d349ed-44d7-43e1-9a83-
5f2406dee5bd/chats/getAllMessages?model=B",
"applicationId": "aa8aaaa8-8aa8-88a8-888a-aaaa8a8aa88a",
"changeType": "created,updated,deleted",
"clientState": "ClientSecret",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2023-01-10T18:56:49.112603Z",
"creatorId": "8888a8a8-8a88-888a-88aa-8a888a88888a",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate":
"MMMM/sMMMsssMsMMMsMMsMMMs4sMMsM4ssMsMsMMMss4ssMMMssssssM4s4MMMsMMMMMMMMsMMM
MMMMssMMsMMMMMMMMM4MMMMMsMMMMMMMssMMsMMMMMMMMMM4MMMssMsMMMMMMMs4MMMMsMM4sssM
sM4MsMMMsMssMMsMsMMM4MMssMMMsMssMMsMsMMMsMMssMMMsMsMsMMssMsMMMMMMMsM4MMMss4s
sMMMsMMssM4MsMsM4Ms4sM4MssMssMsMssMMMMMMsMMMMMsMMsssMMMMMMMMMssMMMMMMMMsMssM
MMMM4ssMMs4sMsM/+MM4444s4M/+4sss4MMMMMsMsMsss/s/sMMsMss4sMsMMMss4M4Ms44M4M4M
sssssM4M4MMMM444Mss4+s4M44MsssMMMs4Ms4MsMMsMMsMsMMM4sMMMMsssMssssMMss44MMs+M
MssMsMsM4sMMs4MsMsM4ssM4MMMsMMs4sMMM4MsM+MsMss+sMsMM4sMM4sMMM4ss4ssssMMMsssM
4MMssM+MsM/sMMss4MsMMM44+/MMMsMs4s44M++ssssssMMs/MsMMMMsMMssMsssssMMss4MMMsM
4s4MssMsMssMsMMMMMMs4sMMssMsMMMM/ss4sMMsMMsMMMsMMMMMsssM4MMsMMMsMMMMMsssMMsM
sMMssMsMMMsMMMMMMMsMsMsMMMsMMMMMMMsMsMMMMMsMMMMMMMsMMMMMsMsMsMsMMMMMMMsMMssM
sMMMMsMsM4Ms+sMssMs4sMsMsssM4M4Ms4MMMMMMMMMssssMMMsssMsMMMMsMMMMMMs4sssM4MMM
MMMsMMMMMMsMMsssssMMsMs4sM4MsMs4sM4Mss44ssM4ss44ssMsssM4sssMsM4MssMMsM44sMMs
MMM4MM4MsMM4MMMMsM4MMM4MMMMMsMMssMsMsMMMsM4MsMsMsMM4sssMsMsMMMsMMMMMMMMMMM4s
4sMM4Ms4sssssMsMsMM4sMsssMMssM4MMMMMMMMsMMMMMMMMsMM4MMssMMM4MMMMsMsMMssMsMMM
sMMMMMMMsMMMsM4M4MMMMMMsMMMMMMsMMsssssMMsMs4sM4MsMs4ssMMsM4MsM4MsMM4MMsMMM4s
MMsMMMMMsMsMMMM4MMsssMM4MMMMsMM4sssMsMsMMMMMsMMM4MsMssMMMMsssMsMMMMssMsMMsMM
4sMssM4MssMMsMM4sMssssM4ssMMsM44sMMsMMM4MM4MsMM4MMMMsM4MMM4MMMMMsMMssMsMsMMM
sM4MsMsMsMM4sssMsMsMMMsMMMMMMMMMMM4s4sMM4Ms4ssss4MsMsMM4sMsssMMssM4MMMMMMMMs
MMMMMMMMsMM4MMssMMM4MMMMsMsMMssMsMMMsMMMMMMMsMMMsM4M4MM4MM4MsMsMMMMMsM4M4ssM
MMssssMMMMMsM/s4MsMMMMsMMMM4MMs4MMMMMMsMsMsMMMM4MMMMsMsMssMMssMMsssMssM4ss4M
ssM4ssMMssssssMMsss4ss44sssMsMsMMMM4MssMsMMMMMMMMMMMsssMMsMMMMMM/sMM4sMssM4M
ssM4ssMMss4MsMsMsM44sM4MssMssMsMsM4MMMM4MMMMsMsMMssMsMMMsMMMMMMMsMMMsM4MsssM
ssMMsMs4sM4MsMM4ssMMsM4MsM4MssM4MMMMsMsMMssMsMMMsMMMMMMMsMMMsM4MsssMssMMsMs4
sM4MsMs4ssMMsM4MsM4MssM4MMMMsMsMMssMsMMMsMMMMMMMsMMMsM4MsssMssMMsMs4sM4MsMs4
ssMMsM4MsM4MssM4MMMMsMsMMssMsMMMsMMMMMMMsMMMsM4MsssMssMMsMs4sM4MsMM4ssMMsM4M
sM4MssM4MMMMsMsMMssMsMMMsMMMMMMMsMMMsM4MsMM4MM4MsMsMMMMsMMMsMMMMssMssss4s+MM
M44MMMsMsMM4MM4MsMMMMMMMMMMsMMMMMMsMMMsssMsMMMMsMMsMMMssssssM4s4MMMsMMMMMMMM
MMMM4MMMMssss444MsMsMMM44MM/444sMMMs4sMsMM4sMMMssMM4+M4sssMs+MsMMMMM/M/s4MMs
sM4ssss/4MMMsssMsMMss44sMsss4++ss/4s+s4sMs+4sM4MsM/4/MssMMMsMssMs4MsMss4MMsM
sMssssssMMM4MsMM4s+MMM4M4sMMMMs4s4sMMMMsM444ssM4MMsssMMMMsM4MsMsMMM4sMsMs4sM
sMMMMMs4MsMsMsMsM4sMs4sMMMMMsssMssMsMsMMss4MMM4sMsM4sMMssMMsM44MM4ss4s4Ms44s
MMM4ssss4Ms4sMM4MMMMM4MMs+ss4MsMssMss4s==",
"encryptionCertificateId": "44M4444M4444M4M44MM4444MM4444MMMM44MM4M4",
"notificationUrlAppId": null
}
When you create the subscription, make sure that the includeResourceData property is
set to true , and that you have specified the encryptionCertificate and
encryptionCertificateId properties. Otherwise, the encrypted content won't be returned
in the change notifications. For details, see Notification endpoint validation.
POST https://webhook.azurewebsites.net/api/send/myNotifyClient
Content-type: application/json
{
"value": [
{
"subscriptionId": "88aa8a88-88a8-88a8-8888-88a8aa88a88a",
"changeType": "created",
"clientState": "ClientSecret",
"subscriptionExpirationDateTime": "2023-01-10T11:03:37.0068432-08:00",
"resource":
"chats('19:[email protected]')/messages('1677774058
888')",
"resourceData": {
"id": "1677774058888",
"@odata.type": "#Microsoft.Graph.chatMessage",
"@odata.id":
"chats('19:[email protected]')/messages('1677774058
888')"
},
"encryptedContent": {
"data":
"sMMsMsMM+3MMMs8MMsMMsss5M+M0+8sMMsM96MM/8MMMsM4MM12sMsssMMsssMsMMssMs8Mss6s
ssMMsM2ssssssssMss7sssMs4s35ssMs+0ss1sssMsMssMMMMsssss5MsMssssss+sMsMMMM8s4M
3MMsMssM54s1ssssMs4ssMsss3MMM8M4sM+3MMss7MM8sMsMMMs3sssss5MssMss6s+Ms7sMssMM
ssMsMMss1sMs2sM6sss6sMssssMss7s1MMs7/Msssss5M9M7sMsMMMsMs+MMs+MsMMsMsMMMMsMM
Mss1M2ssMM8M3sMMMsMss2MMMMsM+ss0M+sssMM4M+sMsM69sMs+sMsssM+MMsMsMM/ssssMMMMM
ss/s6/47Ms0s5Ms6MsssM2sss4MMMMMMsMsMMM+s8MssMsMMssMMs+MMMM56ss0sMM+sssMsss1s
sMsMs21s3MssM9ssMsss9M2+MM3sMMMMMM7MM770MMM2MMsssM11MsssMssMsMsMM2sM1s+84MMs
6sss8MsMMsMMsMM3MMssMss1MssMsMsMMMMsMsssMMsssM1sssssM9MMM6s4MMss524sMMMssMs4
ss3/+ssssss8MMs2ssMMs2MsMsMMssM8MMMMsMM0sss4MMs/sMsMMs0sMMsssss135sssss9+sss
MsMMsMsssMsMsMsMsMM7Ms+MssMsMM1sMssss5s64sMss6sMs6sM0MMs3s29MMssM62ssMsMMssM
sM0ssssssss+sM1MsM3sMM9sssssMMMsssMMsMsMsssMssssssMsMssMMMsM8Ms5MsssMM9ss/4M
ssMs3s5M81sMMssssMMMssMMs7Ms2M9M+7MsssMss6sM0sssM7M0ssMssssMMsMMs9s4MsMsMM6M
MsMMssMMssM+Mss6MM8MMM6MM1s75MsssMMsM+MMMs2s9M1MMMsMMs1MssMsssssssMs8MsMsMMM
MMM7sMsss0MssMsMMssMMM/sM0M01s2M7MsssssMs37MMs140sMMM0ssMMM/ssMMs3sMsM+Ms+sM
MsM3MMssMssMsssss6MMssMMMs1MMMMMsssMs0sM9sMMMss+sssss2sssMssMsMMM1MssMMMs8MM
MssssMM99ssMsssMssss2Ms5sMs1/5MMssssMsMM3MMMMM1MsMsMsMMsMMssMsMMsssssMs9Mss6
Mss+sM+73Msss0ssMsss8sMssMssssssssssMM9MMMMsMMMMMMMM5MMMM27sM+ssMG",
"dataSignature": "sMM+sss2sMssMMsMMMMMMMM6ssMs93MssMMM8sMMMMM=",
"dataKey":
"MMsMMMMMss7sssM34sMMsMMsMssMss7MssMssss+MM+4sMsssMss6Msss9sMssMssMsssMM0+MM
sss0sMs8MMsMssss2MMMMsMsssMMsMsM3MssMs9ss5sssMMsMssMsMMM6MMssMsM1M+MMMMsMss3
MMsssMs9s0ssMs/1sM6ssMMssM+Ms9MsssMMM8MMssssMMs2s94MsMssMMM92/MMMs4Ms8/sssss
sMs5+0s+Ms2M7sMMMMsMMsMsMs+5MMM3sssMsMMMsM8sMss+MssssMsMs/MMsMM5ssssM8M0s0MM
06sssMMsMM4MsssMMsMssMM9M9MsMMMMM7sMsMM==",
"encryptionCertificateId":
"44M4444M4444M4M44MM4444MM4444MMMM44MM4M4",
"encryptionCertificateThumbprint":
"07M3411M4904M3M78MM8211MM4589MMMM47MM7M6"
},
"tenantId": "4dc1fe35-8ac6-4f0d-904a-7ebcd364bea1"
}
],
"validationTokens": [
"ssM0sMMsMsMMM1MsMMMssMssMsMMMsM1MsMsMss1sMM6Ms1MMMMMMM5MMsssMs9ssM1sMs9MsMM
MMsssssMsMsssMMM6Ms1MMMMMMM5MMsssMs9ssM1sMs9MsMMMMsssssM9.ssMssMMsMsMsMsssMM
MsMs04M2M2MMM1MMMsMMs4MM1sM2MsMMM5MsM3MsMsMMMss3MsMsMssMMsssssM3M0ss53sM5ss3
ssMs5ssM8sMMMsMsM3Ms0sMMMsMMMsMMMsMMM3Ms0sMsMsMMMsMMMsMsMsMssssMM0MsssMsssMs
ssMsMsMMMsMsMsMsM2MsMsMsM3MMMsMsM4sMM6MMM3MsM2MMM1MMssMMssMsssMMMsM1sMssM5MM
s4ssMsMMssMMMMM2MsMMMsMMsMMM0sMMMssMMsMMM6MsMsMsMsMsMsMMMsMMMsMMssMs05MMssMM
MsMMssMMM0MMM4MsMsMsMssMssMMMsMsssMsMsMssssMM6Mss0sMMsMs8ss3MsMsssssMss3Msss
M0MsM0MsMsMMssMMMsMsMsMMMsMs1sMMssMMM2MMMsMMMsMMMsMM8sMMMssMMsMsMsMsMsMsMsMM
1sMsssMMMsMMMsMsssMM1sMMMsMMM0M2M2MMssMMMssMM6MsMsMMMsMMM3MMsMMMMMMsMMsMM4Ms
MsMsMsMssMsMMsMMMsM05MsMssMMssMMM5sMsMMMMMMsMsMsM1MsM6MsMsMsMsMsM1MMM3MMMsMM
M5Ms1sM2M1MMMsMMM0MMMsMsM1MsMsMsMsMMM6MsM0MsMsMMssMMMsMsMsMMMsMs1sMMssMMM2MM
MsMMMsMMMsMMMsMsM0sMM6MssMMs1sMMMssMsMMMMMssMMss16MMMsMMM2MMMsMsMsMsMssM.s16
ssMMM97sM_MMs_ss8s8s3MMs95ssMMM8M6ss4M4Ms3sMMMs-
M_7ss80MMMsss6ssM0sMM20MsMMs15sMM_ssMsssMMMs9ssM0M_sss5sMssMsMss4s-M-
8Ms1ssM8sMsMMss9sMsMsMMMMMMMsMs6MMss2MMMsMMss0MMssMMssMssMMMMMMMMsMs817sssss
sMss8MMMssMMMMsss0sMs1ssM0sM1ssMMMs6MMMMss6ss_sMMss3M4MM3sMss45s4s8MMss6s75s
sMsM5sssMM0MMMMMM_1ssMMMMsMMMssMs44sMs4MssM5s-__ss5MMs6sMM_MMss5MsMMMM"
]
}
Decrypted content
JSON
{
"@odata.context":
"https://graph.microsoft.com/$metadata#chats('19%3Ab1234aaa12345a123aa12aa12
aaaa1a9%40thread.v2')/messages/$entity",
"id": "1677774058888",
"replyToId": null,
"etag": "1677774058888",
"messageType": "message",
"createdDateTime": "2023-01-10T18:07:30.302Z",
"lastModifiedDateTime": "2023-01-10T18:07:30.302Z",
"lastEditedDateTime": null,
"deletedDateTime": null,
"subject": "",
"summary": null,
"chatId": "19:[email protected]",
"importance": "normal",
"locale": "en-us",
"webUrl": null,
"from": {
"application": null,
"device": null,
"user": {
"userIdentityType": "aadUser",
"id": "87d349ed-44d7-43e1-9a83-5f2406dee5bd",
"displayName": "John Smith",
"tenantId": "4dc1fe35-8ac6-4f0d-904a-7ebcd364bea1"
}
},
"body": {
"contentType": "html",
"content": "<p>Hello world</p>"
},
"channelIdentity": null,
"attachments": [
],
"mentions": [
],
"onBehalfOf": null,
"policyViolation": null,
"reactions": [
],
"messageHistory": [
],
"replies": [
],
"hostedContents": [
],
"eventDetail": null
}
Change notifications are sometimes delivered out of order, because they are
asynchronous. If your application requires the resources to be sorted in a particular
order, make sure that you sort the decrypted content by the appropriate property. For
example, if the messages should be displayed in chronological order in your chat
application, sort the decrypted chatMessages by createdDateTime.
When a chat message is edited, a change notification is sent for the edit, with an
updated lastEditedDateTime . Your chat application should display the edited message
instead of the original message, if the intent is to display the latest version of messages.
The notes about contentType, images, data loss prevention (DLP), and retention policies
in Step 4: Retrieve messages apply to the decrypted messages as well.
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/subscriptions/88aa8a88-88a8-88a8-
8888-88a8aa88a88a
Content-type: application/json
{
"expirationDateTime":"2023-01-12T18:23:45.9356913Z"
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
"id": "88aa8a88-88a8-88a8-8888-88a8aa88a88a",
"resource": "/users/87d349ed-44d7-43e1-9a83-
5f2406dee5bd/chats/getAllMessages",
"applicationId": "aa8aaaa8-8aa8-88a8-888a-aaaa8a8aa88a",
"changeType": "created",
"clientState": null,
"notificationUrl": "https://function-ms-teams-subscription-webhook-
z2a2ig2bfq-uc.a.run.app",
"notificationQueryOptions": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2023-01-12T18:23:45.9356913Z",
"creatorId": "8888a8a8-8a88-888a-88aa-8a888a88888a",
"includeResourceData": null,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": null,
"encryptionCertificateId": null,
"notificationUrlAppId": null
}
To get the viewpoint of a chat, use the GET HTTP method on the chats resource, as
shown in the following example.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users/87d349ed-44d7-43e1-9a83-
5f2406dee5bd/chats/19:[email protected]
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#chats/$entity",
"id": "19:[email protected]",
"topic": null,
"createdDateTime": "2023-01-11T01:34:18.929Z",
"lastUpdatedDateTime": "2023-01-11T01:34:18.929Z",
"chatType": "group",
"webUrl":
"https://teams.microsoft.com/l/chat/19%3Ab1234aaa12345a123aa12aa12aaaa1a9%40
thread.v2/0?tenantId=4dc1fe35-8ac6-4f0d-904a-7ebcd364bea1",
"tenantId": "4dc1fe35-8ac6-4f0d-904a-7ebcd364bea1",
"onlineMeetingInfo": null,
"viewpoint": {
"isHidden": false,
"lastMessageReadDateTime": "2021-05-27T22:13:01.577Z"
}
}
The viewpoint of a chat for a user is updated whenever the user marks the chat as read,
marks the chat as unread, hides the chat, or unhides the chat.
Cost estimation
Currently, retrieving messages per-user, per-chat (Step 4) does not involve
consumptions charges (but has throttling limits). Only change notifications have
consumption charges of $0.00075 per message.
If your app has 50 users, and each user receives messages from 20 users and sends 300
messages per month, the approximate cost would be:
For the most up-to-date pricing information, see Microsoft Teams API licensing and
payment requirements.
See also
Add reactions to chat messages
Add @metions, images, attachments, HTML styling, adaptive cards to chat
messages
Hide a chat from users
Remove a member from a chat
Check chat membership
Subscribe to change notifications of other resources
Payment models and licensing
requirements for Microsoft Teams APIs
Article • 03/16/2023
This article describes the payment models and licensing requirements for Microsoft
Teams APIs in Microsoft Graph. For a high-level description of metered APIs and services
in Microsoft Graph, see Overview of metered APIs and services in Microsoft Graph.
Some APIs provide the option to choose a licensing and payment model via the model
query parameter; others only support one model or do not support a licensing and
payment model.
The following table lists the APIs that currently support payment models.
Scenario APIs
7 Note
Billing for these APIs started on July 5th, 2022. To set up an active Azure
subscription for your application for billing purposes, see Enable metered
Microsoft 365 APIs and services. For more details, see Payment and billing
updates.
Payment models
The following payment models are available:
Evaluation mode (default) enables access to APIs with limited usage per requesting
application for evaluation purposes. Change notifications are not sent if the limit is
exceeded.
7 Note
Most of these APIs are also protected APIs; you must get approval from Microsoft
before you can use them. If your application is using protected APIs, please submit
a request for access . For details, see Protected APIs in Microsoft Teams.
model=A requirements
Get messages across Named 1600 $0.00075 The named user is the user
all chats for user user messages per identified in the GET request URL.
per user per message Requests returning an empty list,
month per will be charged 1 message.
app Seeded capacity is shared with
channel export.
API Who Seeded Price for Notes
needs a capacity additional
license use
Get messages across Any 1600 $0.00075 Requests returning an empty list
all channels team messages per will be charged 1 message.
member per user per message Seeded capacity is shared with
month per chat export.
app
Guest users are exempt from these licensing requirements. Similarly, messages sent
from outside the tenant (federated chat) are exempt. Consumption meters still apply.
It is the responsibility of the tenant owner (not the app owner) to ensure that users are
properly licensed. Admins can use the Information protection license report in Teams
admin center to see which users don't have a supported license.
Many supported licenses offer free trials. Office 365 E5 for instance has a Free trial
link under the Buy button.
You can get a free Microsoft 365 E5 developer sandbox subscription with 25 user
licenses through the Microsoft 365 Developer Program.
7 Note
The Microsoft Communications DLP service plan must be enabled before it can be
licensed. You can manage licenses in the Azure portal or the Microsoft 365
admin center . You can also assign licenses to a group account by using
PowerShell and Microsoft Graph.
model=B requirements
model=B is restricted to applications that do not perform a security or compliance
function. For details, see the API Terms for Security & Compliance Applications section
of the product terms for Microsoft Azure Services.
Get messages across all None $0.00075 per Requests returning an empty list will
chats for user message be charged 1 message.
Get messages across all None $0.00075 per Requests returning an empty list will
channels message be charged 1 message.
Get messages across all 500 messages per N/A Requests returning an empty list
chats for user month per app will be charged 1 message.
Get messages across all 500 messages per N/A Requests returning an empty list
channels month per app will be charged 1 message.
If your applications are or will be calling any of the following APIs, you must follow the
steps described in Enable metered Microsoft 365 APIs and services to set up an active
Azure subscription for billing purposes.
Note that the organization that owns the app registration is responsible for the
payment. The Azure subscription should also be active in the same tenant. For
multitenant apps, the organization that registered the app might be different than the
organization that runs the app.
Payment-related errors
In the event that incorrect licensing is detected, the API call will fail and data will not be
returned. Specifically, for most APIs, attempting to GET messages for an unlicensed user
will result in a 402 error code. For change notifications, messages sent by unlicensed
users will not generate a change notification. Similarly, API calls and change notifications
used in evaluation mode in excess of the seeded capacity will fail.
402 Calling Patch API ...query parameter 'model' does not support value 'B'
(Payment passing model=B for this API. Use billing model 'A'...
Required)
402 Evaluation mode ...evaluation mode capacity has been exceeded. Use a
(Payment capacity exceeded valid billing model...
Required)
7 Note
A successful API call does not mean that the required licensing is in place. Similarly,
API success in evaluation model does not guarantee that the call is within seeded
capacity.
A subscription owner, or anyone with appropriate RBAC (Roles Based Access Control)
permissions, can use Cost Analysis to track metered API consumption, as follows:
You can also use the pie charts near the bottom to further break down the costs for
analysis, using the Resource and Meter filters.
For more details about cost management, see Cost Management + Billing
documentation.
A subscription owner, or anyone with required RBAC (Roles Based Access Control)
permissions, can set up a report, in CSV format, with the billing details for the entire
subscription. You can export the report periodically (daily, weekly, monthly). For details,
see Tutorial: Create and manage exported data.
Estimate the number of messages in your
Teams
This section describes how to look up the number of messages in your Teams tenant.
This can help you estimate the cost for using the metered APIs. Note that if a message is
retrieved through metered APIs multitple times, it is billed multiple times. Keep this in
mind when you estimate the cost based on the number of messages in your Teams
tenant. For example, if you called getAllMessages (without any filters) yesterday, and
then call it again (without any filters) today, all messages from earlier than today will be
billed twice. For this reason, when using metered APIs, we recommend that you use
filters (for example, $top=10 , $filter=lastModifiedDateTime gt 2019-03-
17T07:13:28.000z ) or change notifications to avoid retrieving the same message multiple
times.
You can also call the getTeamsUserActivityUserDetail API, or you can use the Microsoft
Teams Admin Center as follows:
Note: You must be either a global admin, global reader, or Teams service admin to
view the report in the Microsoft Teams Admin Center . For details, see Use Teams
administrator roles to manage Teams.
1. In the left pane, choose Analytics & reports > Usage reports.
2. On the View reports tab, under Report, choose Teams user activity.
3. Under Date range, select a range.
4. Choose Run report.
Frequently asked questions
Scenario Details
Did billing actually Yes, we are onboarding partners in phases. For continued access, follow the
started on July instructions on Enable metered Microsoft 365 APIs and services to set up an
5th? active Azure subscription for billing purposes.
What should I Billing will be effective immediately. You can monitor the costs as described
expect after setting in the View the costs billed for the metered Microsoft Teams APIs section
up an Azure above.
subscription?
What happens if • No payment-related errors will occur if the application is not calling
no Azure metered APIs.
subscription is • If no model parameter is passed, the evaluation model value will be used
provided? by default.
• If calling a metered API passing model=A , provide a Microsoft 365 E5
eligible license and Azure subscription.
• If passing model=B when calling metered APIs, provide an active Azure
subscription.
How do I create an The Azure subscription must be available in the same tenant where the app
Azure is registered. Customers with MCA or EA agreements can get a subscription
subscription? from their existing account. Is also possible to create a PAYG subscription
using a credit card or pay by check or wire transfer. For details, see cost
management and billing.
Is possible to Yes, this information must be provided as part of Azure billing details.
differentiate billing
from multitenant
or single tenant
app?
Is there a charge To discourage frequent polling, API requests that return an empty list of
when no message messages will be charged one message. In the case of evaluation model ,
is returned using the call will count toward the 500 messages per month per app allowed.
any model?
Scenario Details
Where can I A subscription owner, or anyone with appropriate RBAC (Roles Based Access
monitor the cost Control) can use Azure Cost Analysis tool to track consumption per day or
and billing? filter by meter, service name, resource ID among other parameters. For
more details, please see View the costs billed for the metered Microsoft
Teams APIs above.
Microsoft Teams APIs in Microsoft Graph that access sensitive data are considered
protected APIs. These APIs require that you have additional validation beyond
permissions and consent before you can use them.
The following APIs are currently protected, and all use Microsoft Graph application
permissions:
7 Note
To verify whether your request has been approved, test your application access on the
next applicable Monday. If we have additional questions about the request, we will
contact the email specified in the form.
See also
Microsoft Teams API overview
Microsoft Teams API implementation
differences in national clouds
Article • 02/16/2023
This article describes Microsoft Teams API implementation differences between the
Microsoft Graph global endpoint and the national clouds.
For general information about national cloud availability for Microsoft Graph APIs, see
National cloud deployments.
7 Note
Microsoft Teams APIs are not available in the Microsoft Cloud China operated by
21Vianet national cloud.
List transcripts
Get transcript
The Microsoft To Do API in Microsoft Graph provides a simple way for people to
manage their tasks and plan their day. Tasks are organized in task lists, which can be
accessed across To Do clients, Outlook, and Teams from any device.
To Do Windows app
Update a PATCH
task https://graph.microsoft.com/v1.0/me/todo/lists/{todoTaskListId}/tasks/{todoTaskId}
Delete a DELETE
task https://graph.microsoft.com/v1.0/me/todo/lists/{todoTaskListId}/tasks/{todoTaskId}
API reference
Looking for the API reference for this service?
Using the To Do API in Microsoft Graph, you can attach files up to 25 MB to a todoTask.
Depending on the file size, choose one of two ways to attach the file:
For attaching files of any size, create an upload session, and iteratively use PUT to
upload ranges of bytes of the file until you have uploaded the entire file. A header
in the final successful PUT response includes a URL with the attachment ID.
If the file size is under 3 MB, do a single POST on the attachments navigation
property of a todoTask; see how to do this for a task. The successful POST response
includes the ID of the file attachment.
This article illustrates the first approach. You will learn step-by-step how to create and
use an upload session to add a file attachment to a task.
A successful operation returns HTTP 201 Created and a new uploadSession instance,
which contains an opaque URL that you can use in subsequent PUT operations to
upload portions of the file. The uploadSession provides a temporary storage location
where the bytes of the file are saved until you have uploaded the complete file.
Permissions
One of the following permissions is required to call this API. To learn more, including
how to choose permissions, see Permissions.
Request
The following is an example of a request to create an upload session.
HTTP
HTTP
POST
https://graph.microsoft.com/beta/me/todo/lists/AAMDiFkfh=/tasks/AAMkADli
Mm=/attachments/createUploadSession
Content-Type: application/json
{
"attachmentInfo": {
"attachmentType": "file",
"name": "flower",
"size": 3483322
}
}
Response
The following example shows the uploadSession resource returned for the task in the
response body.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#microsoft.graph.uploadSession",
"uploadUrl": "https://graph.microsoft.com/beta/users/6f9a2a92-8527-4d64-
837e-
b5312852f36d/todo/lists/AAMDiFkfh=/tasks/AAMkADliMm=/attachmentSessions/AAMk
ADliMm=",
"expirationDateTime": "2022-06-09T10:45:27.4324526Z",
"nextExpectedRanges": [
"0-"
]
}
Specify the request headers and the request body as described in the following sections.
Request headers
Content- Int32 The number of bytes being uploaded in this operation. The upper limit of
Length the number of bytes for each PUT operation is 4 MB. The request will fail
for anything higher than 4 MB. Required.
Content- String The 0-based byte range of the file being uploaded in this operation,
Range expressed in the format bytes {start}-{end}/{total} . Required.
Request body
Specify the actual bytes of the file to be attached, that are in the location range
specified by the Content-Range request header.
Response
A successful upload returns a HTTP 200 OK response code and an uploadSession object.
Note the following in the response object:
The expirationDateTime property value remains the same as returned by the initial
uploadSession in step 1.
The nextExpectedRanges specifies the next byte location to start uploading from,
for example, "nextExpectedRanges":["2097152"] . You must upload bytes in a file in
order.
The uploadUrl property is not explicitly returned, because all PUT operations of an
upload session use the same URL returned when you create the session (step 1).
Request
The following is an example of a request.
HTTP
PUT https://graph.microsoft.com/beta/users/6f9a2a92-8527-4d64-837e-
b5312852f36d/todo/lists/AAMDiFkfh=/tasks/AAMkADliMm=/attachmentSessions/AAMk
ADliMm=/content
Content-Type: application/octet-stream
Content-Length: 2097152
Content-Range: bytes 0-2097151/3483322
{
<bytes 0-2097151 of the file to be attached, in binary format>
}
Response
The following is an example of the response that shows in the nextExpectedRanges
property the start of the next byte range that the server expects.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"ExpirationDateTime":"2022-06-09T10:45:27.4324526Z",
"NextExpectedRanges":["2097152"]
}
Once the last byte of the file has been successfully uploaded, the final PUT operation
returns a HTTP 201 Created response code and a Location header that indicates the
URL to the file attachment. You can get the attachment ID from the URL and save it for
later use.
The following examples show how to upload the last byte range of the file to the
todoTask in the preceding steps.
Request
The following is an example of a request.
HTTP
PUT https://graph.microsoft.com/beta/users/6f9a2a92-8527-4d64-837e-
b5312852f36d/todo/lists/AAMDiFkfh=/tasks/AAMkADliMm=/attachmentSessions/AAMk
ADliMm=/content
Content-Type: application/octet-stream
Content-Length: 1386170
Content-Range: bytes 2097152-3483321/3483322
{
<bytes 2097152-3483321 of the file to be attached, in binary format>
}
Response
The following is an example of the response that shows a Location response header
from which you can save the attachment ID
( AAMkADI5MAAIT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0= ) for later use.
HTTP
HTTP/1.1 201 Created
Location: https://graph.microsoft.com/beta/users/6f9a2a92-8527-4d64-837e-
b5312852f36d/todo/lists/AAMDiFkfh=/tasks/AAMkADliMm=/Attachments/AAMkADI5MAA
IT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=
Content-Length: 0
Request
HTTP
DELETE https://graph.microsoft.com/beta/users/6f9a2a92-8527-4d64-837e-
b5312852f36d/todo/lists/AAMDiFkfh=/tasks/AAMkADliMm=/attachmentSessions/AAMk
ADliMm=
Response
HTTP
You can use the Excel REST API in Microsoft Graph to extend the value of your Excel
data, calculations, reporting, and dashboards.
Excel is an indispensable productivity tool. Users across all industries and job functions
embrace it as a tool for storing, tracking, and manipulating all kinds of data. It's used for
everything from simple task tracking and data management to complex calculations and
professional reporting.
https://www.youtube-nocookie.com/embed/I1rSkJww2Dk
Perform calculations
Users love the ease with which they can perform deep and complex calculations within
Excel. You can now access Excel’s powerful calculation engine with instant results. For
example, a mortgage calculator can take advantage of the PMT function from Excel by
making a simple API call that includes principal, rate and number of payments. Excel
does all the difficult work and returns the monthly payment instantly. With more than
300 Excel worksheet functions currently available, you have full access to the breadth of
formulas supported by Excel today. Complex business models don’t need to be rebuilt
repeatedly. Developers can program Excel to perform those calculations instantly and
retrieve the results with simple API calls.
7 Note
The Excel REST API supports only Office Open XML file formatted workbooks (files
with the .xlsx extension). The .xls extension workbooks are not supported.
https://graph.microsoft.com/{version}/me/drive/items/{id}/workbook/
https://graph.microsoft.com/{version}/me/drive/root:/{item-path}:/workbook/
You can access a set of Excel objects (such as Table, Range, or Chart) by using standard
REST APIs to perform create, read, update, and delete (CRUD) operations on the
workbook.
API reference
Looking for the API reference for this service?
Next steps
Manage sessions in Excel with Microsoft Graph
Write to an Excel workbook using Microsoft Graph
Use workbook functions in Excel with Microsoft Graph
Update a range’s format in Excel with Microsoft Graph
Display a chart image in Excel with Microsoft Graph
Manage sessions and persistence in
Excel
Article • 06/29/2022
If your application needs to make more than one or two calls to the Excel API in
Microsoft Graph, create a session and pass the session ID with each request. The
presence of a session ID in the requests ensures that you are using the Excel API in the
most efficient way possible.
Persistent session: All changes made to the workbook are persisted (saved) to the
workbook. This is the most efficient and best-performing way to use the Excel API.
Non-persistent session: Changes made by the API are not saved to the source
location. Instead, the Excel backend server keeps a temporary copy of the file that
reflects the changes made during that particular API session. When the Excel
session expires, the changes are lost. This mode is useful for apps that need to do
analysis or obtain the results of a calculation or a chart image, but do not need to
affect the document state.
Sessionless: The API calls do not pass a session ID. The Excel servers have to locate
the server's copy of the workbook for each operation. This is not an efficient way
to call the Excel API, but it is suitable for making certain types of isolated requests.
To represent the session in the API, use the workbook-session-id: {session-id} header.
7 Note
The session header is not required for an Excel API to work. However, we
recommend that you use the session header to improve performance. If you don't
use a session header, changes made during the API call are persisted to the file.
Request types
Suggested error handling for Excel APIs is based on request type, error code, and status
code. The following are the request types:
Next steps
To learn how to create and use sessions, see the Create session reference topic.
See also
Write to an Excel workbook using Microsoft Graph
Use workbook functions in Excel with Microsoft Graph
Update a range’s format in Excel with Microsoft Graph
Display a chart image in Excel with Microsoft Graph
Use the Excel REST API
Display a chart image in Excel
Article • 06/29/2022
When you perform a GET operation to retrieve a chart image, the Excel API in Microsoft
Graph returns the image as a base-64 string. You can display the base-64 string inside
an HTML image tag:
HTML
If you want to customize the display of the image, specify a height, width, and a fitting
mode. Here is what the same chart image looks like if you retrieve it with these
parameters: Image(width=500,height=500,fittingMode='Fill') .
See also
Manage sessions in Excel with Microsoft Graph
Write to an Excel workbook using Microsoft Graph
Use workbook functions in Excel with Microsoft Graph
Update a range’s format in Excel with Microsoft Graph
Use the Excel REST API
Use workbook functions in Excel
Article • 06/29/2022
You can use the workbook functions in Excel with Microsoft Graph to invoke any
workbook function by using the following syntax: POST
/me/drive/root/workbook/functions/{function-name} . You provide the function
arguments in the body using a JSON object. The function's resulting value and any
error strings are returned in the function result object. The error value of null
For a complete list of supported functions, see Excel.Functions class. Refer to the
function signature for specific parameter names and data types.
) Important
The range input parameter is supplied using a range object instead of the
range address string.
The index parameter is 1-indexed unlike the 0-index used in most of the APIs.
Example: vlookup
In an Excel spreadsheet, the vlookup function takes the following arguments:
table_array (required): The range of cells where the lookup value is located.
Remember that the lookup value should always be in the first column in the range
for VLOOKUP to work correctly. For example, if your lookup value is in cell C2, then
your range should start with C.
col_index_num (required): The column number in the range that contains the
return value. For example, if you specify B2: D11 as the range, you should count B
as the first column, C as the second, and so on.
range_lookup (optional): The logical value that specifies whether you want
VLOOKUP to find an approximate or an exact match. Specify TRUE if you want an
approximate match or FALSE if you want an exact match of the return value. If you
don't specify anything, the default value will always be TRUE or an approximate
match.
Inside a cell, the vlookup function looks like this:
=VLOOKUP (lookup value, range containing the lookup value, the column number in the
range containing the return value, optionally specify TRUE for approximate match or
FALSE for an exact match)
For more information, see the documentation for the VLOOKUP Excel function .
Request
The following example shows how to call the vlookup function and pass these
parameters with the Excel REST API.
HTTP
POST
https://graph.microsoft.com/beta/me/drive/root:/book1.xlsx:/workbook/functio
ns/vlookup
content-type: Application/Json
authorization: Bearer {access-token}
workbook-session-id: {session-id}
{
"lookupValue": "Temperature",
"tableArray": { "Address": "Sheet1!E1:G5" },
"colIndexNum": 2,
"rangeLookup": false
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#workbookFunctionResult",
"@odata.type": "#microsoft.graph.workbookFunctionResult",
"@odata.id": "/users('f6d92604-4b76-4b70-9a4c-
93dfbcc054d5')/drive/root/workbook/functions/vlookup()",
"error": null,
"value": "28.3"
}
Example: median
In an Excel spreadsheet, the median function takes an array of one or more input ranges.
=MEDIAN(A2:A6)
For more information, see the documentation for the MEDIAN Excel function .
Request
The following example shows how to call the median function and one or more input
ranges with the Excel REST API.
HTTP
POST
https://graph.microsoft.com/beta/me/drive/root:/book1.xlsx:/workbook/functio
ns/median
content-type: Application/Json
authorization: Bearer {access-token}
workbook-session-id: {session-id}
{
"values" : [
{ "address": "Sheet2!A1:A5" },
{ "address": "Sheet2!B1:B5" },
]
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#workbookFunctionResult",
"@odata.type": "#microsoft.graph.workbookFunctionResult",
"@odata.id": "/users('2abcad6a-2fca-4b6e-9577-
e358a757d77d')/drive/root/workbook/functions/median()",
"error": null,
"value": 30
}
See also
Manage sessions in Excel with Microsoft Graph
Write to an Excel workbook using Microsoft Graph
Update a range’s format in Excel with Microsoft Graph
Display a chart image in Excel with Microsoft Graph
Use the Excel REST API
Update a range format in Excel
Article • 03/02/2023
The following examples demonstrate how to use Excel in Microsoft Graph to update
properties of the RangeFormat, RangeFill, and RangeFont properties of a specified
range.
The result of this set of requests is a table with three cells formatted like the top three
cells in the following image.
Request
HTTP
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/worksheets
/Sheet1/range(address='$A$1')/format
Content-type: application/json
{
"columnWidth": 135,
"verticalAlignment": "Top",
"rowHeight": 49,
"wrapText": false
}
Response
This is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"columnWidth": 135,
"horizontalAlignment": "General",
"rowHeight": 49,
"verticalAlignment": "Top",
"wrapText": false
}
Request
HTTP
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/worksheets
/Sheet1/range(address='$A$1')/format/font
Content-type: application/json
{
"bold": true,
"color": "#4B180E",
"size": 26
}
Response
This is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"bold": true,
"color": "#4B180E",
"italic": false,
"name": "Calibri",
"size": 26,
"underline": "None"
}
Request
HTTP
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/worksheets
/Sheet1/range(address='$A$1')/format/fill
Content-type: application/json
{
"color": "#FF0000"
}
Response
This is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"color": "#FF0000"
}
Request
HTTP
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/worksheets
/Sheet1/range(address='$B$1')/format
Content-type: application/json
{
"columnWidth": 135,
"horizontalAlignment": "Center",
"verticalAlignment": "Center",
"rowHeight": 49,
"wrapText": false
}
Response
This is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"columnWidth": 135,
"horizontalAlignment": "Center",
"rowHeight": 49,
"verticalAlignment": "Center",
"wrapText": false
}
Request
HTTP
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/worksheets
/Sheet1/range(address='$B$1')/format/font
Content-type: application/json
{
"italic": true,
"size": 26
}
Response
This is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"bold": false,
"color": "#000000",
"italic": true,
"name": "Calibri",
"size": 26,
"underline": "None"
}
Request
HTTP
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/worksheets
/Sheet1/range(address='$B$1')/format/fill
Content-type: application/json
{
"color": "#00FF00"
}
Response
This is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"color": "#00FF00"
}
Request
HTTP
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/worksheets
/Sheet1/range(address='$C$1')/format
Content-type: application/json
{
"columnWidth": 135,
"horizontalAlignment": "Right",
"verticalAlignment": "Top",
"rowHeight": 49,
"wrapText": false
}
Response
This is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"columnWidth": 135,
"horizontalAlignment": "Right",
"rowHeight": 49,
"verticalAlignment": "Top",
"wrapText": false
}
Request
HTTP
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/worksheets
/Sheet1/range(address='$C$1')/format/font
Content-type: application/json
{
"underline": "Single",
"color": "#FFFFFF",
"size": 26
}
Response
This is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"bold": false,
"color": "#FFFFFF",
"italic": false,
"name": "Calibri",
"size": 26,
"underline": "Single"
}
Request
HTTP
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/worksheets
/Sheet1/range(address='$C$1')/format/fill
Content-type: application/json
{
"color": "#0000FF"
}
Response
This is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"color": "#0000FF"
}
See also
Manage sessions in Excel with Microsoft Graph
Write to an Excel workbook using Microsoft Graph
Use workbook functions in Excel with Microsoft Graph
Display a chart image in Excel with Microsoft Graph
Use the Excel REST API
Write data to an Excel workbook
Article • 06/29/2022
The Excel REST API in Microsoft Graph provides an easy, platform-agnostic way to
upload information to an Excel workbook.
This article shows you how to write simple data sets to an Excel workbook on three web
development frameworks: ASP.NET, Angular, and React. You can look at the code
samples featured in this article by visiting the Microsoft Graph Excel starter samples on
GitHub .
7 Note
All three of the samples write data to an Excel workbook named demo.xlsx. They
provide this workbook for you so that you can upload it to your own OneDrive, but
you can also use Microsoft Graph to upload files to OneDrive. If you're interested in
learning the REST calls that you need to upload a file of any type to your root
OneDrive folder, see the Microsoft Graph Excel REST API ASP.NET to-do list
sample .
All three of the Excel starter samples do the same thing: retrieve the name and address
of the signed-in user and add those two pieces of information to a new row in the
demo.xlsx workbook. You can modify the samples to add additional rows simply by
adding information to the two-dimensional array that represents the row or rows that
you want to add.
https://graph.microsoft.com/v1.0/me/drive/root:/demo.xlsx:/workbook/tables/Table1/r
ows/add
For more information about how to reach files in OneDrive folders, see the DriveItem
resource type in our reference documentation.
7 Note
You can look at the existing row collection of the workbook by making a GET
request to the part of the path that ends at /rows .
JSON
{
"index": null,
"values": [
["alex darrow", "[email protected]"]
]
}
The value of the first index parameter specifies the relative position of the row that
you're adding to the zero-indexed array of rows. Rows below the inserted row will be
shifted downwards. The null parameter indicates that the new row will be added to the
end.
The value of the second values parameter is a two-dimensional string array that
contains the unformatted values of each row that you want to add. The array in the
sample contains only one row, but you can add more rows by adding more string arrays.
You can test this query with your own OneDrive account by uploading the demo.xlsx file
to your OneDrive root folder and executing this query on the Microsoft Graph Explorer.
That is all you need to know in order to write data to an Excel workbook. You do need to
know how to construct and make the request in your own framework, and the Excel
starter samples demonstrate three separate ways of doing this.
The GraphResources.cs file provides a helper class for encapsulating both the user data
you're retrieving from Microsoft Graph and the request body that you'll use when you
write to your workbook.
C#
C#
Since this sample uses TypeScript, it takes advantage of the Microsoft Graph JavaScript
Client Library and the Microsoft Graph TypeScript Types .
TypeScript
addInfoToExcel(user: MicrosoftGraph.User) {
const userInfo = [];
const userEmail = user.mail || user.userPrincipalName;
userInfo.push([user.displayName, userEmail]);
const userInfoRequestBody = {
index: null,
values: userInfo
};
The onWriteToExcel function constructs the two-dimensional string array and passes it
as the request body. It uses axios to make the HTTP request.
TypeScript
onWriteToExcel() {
const { token, me } = this.state;
values.push([me.displayName, myEmailAddress]);
axios
.post('https://graph.microsoft.com/v1.0/me/drive/root:/demo.xlsx:/workbook/t
ables/Table1/rows/add',
{ index: null, values },
{ headers: { Authorization: `Bearer ${token}` }}
)
.then(res => {
console.log(res);
const successMessage = "Successfully wrote your data to
demo.xlsx!";
this.setState ({ successMessage });
})
.catch(err => console.error(err));
}
See also
Manage sessions in Excel with Microsoft Graph
Use workbook functions in Excel with Microsoft Graph
Update a range’s format in Excel with Microsoft Graph
Display a chart image in Excel with Microsoft Graph
Use the Excel REST API
Best practices for working with the Excel
API
Article • 04/12/2023
This article provides recommendations for working with the Excel APIs in Microsoft
Graph.
The following example shows you how to add a new number to a table and then find
one record in a workbook using this approach.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/createSess
ion
Content-type: application/json
{
"persistChanges": true
}
Response
The following is a successful response.
HTTP
HTTP/1.1 201 Created
Content-type: application/json
{
"id": "id-value",
"persistChanges": true
}
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/tables/Tab
le1/rows/add
Content-type: application/json
workbook-session-id: {session-id}
{
"values": [[“east”, “pear”, 4]]
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"index": 6,
"values": [[“east”, “pear”, 4]]
}
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/functions/
vlookup
Content-type: application/json
workbook-session-id: {session-id}
{
"lookupValue":"pear",
"tableArray":{"Address":"Sheet1!B2:C7"},
"colIndexNum":2,
"rangeLookup":false
}
Response
HTTP
{
"value": 5
}
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/closeSessi
on
Content-type: application/json
workbook-session-id: {session-id}
{
}
Response
HTTP
Currently, the session creation Excel API in Microsoft Graph has the long-running
operation pattern enabled. This pattern involves the following steps:
4. After the operation completes, you can get the session creation result through the
specified URL in the succeeded response.
The following example creates a session using the long-running operation pattern.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/me/drive/items/{drive-item-
id}/workbook/createSession
Prefer: respond-async
Content-type: application/json
{
"persistChanges": true
}
Response
The long-running operation pattern will return a 202 Accepted response similar to the
following.
HTTP
{
}
In some cases, if the creation succeeds within seconds, it won't enter the long-running
operation pattern; instead, it returns as a regular create session and the successful
request will return a 201 Created response.
HTTP
{
"id": "id-value",
"persistChanges": true
}
The following example shows the response when the request fails.
Note: The response object shown here might be shortened for readability.
HTTP
{
"error":{
"code": "internalServerError",
"message": "An internal server error occurred while processing the
request.",
"innerError": {
"code": "internalServerErrorUncategorized",
"message": "An unspecified error has occurred.",
"innerError": {
"code": "GenericFileOpenError",
"message": "The workbook cannot be opened."
}
}
}
}
Request
HTTP
GET https://graph.microsoft.com/v1.0/me/drive/items/{drive-item-
id}/workbook/operations/{operation-id}
{
}
Response
The following is the response when the operation has a status of running .
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"id": {operation-id},
"status": "running"
}
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"id": {operation-id},
"status": "succeeded",
"resourceLocation":
"https://graph.microsoft.com/v1.0/me/drive/items/{drive-item-
id}/workbook/sessionInfoResource(key='{key}')
}
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"id": {operation-id},
"status": "failed",
"error":{
"code": "internalServerError",
"message": "An internal server error occurred while processing the
request.",
"innerError": {
"code": ""internalServerErrorUncategorized",
"message": "An unspecified error has occurred.",
"innerError": {
"code": "GenericFileOpenError",
"message": "The workbook cannot be opened."
}
}
}
}
For more details about errors, see Error codes and messages.
Request
With a status of succeeded , you can get the created session information through
resourceLocation with a request similar to the following.
HTTP
GET https://graph.microsoft.com/v1.0/me/drive/items/{drive-item-
id}/workbook/sessionInfoResource(key='{key}')
{
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"id": "id-value",
"persistChanges": true
}
7 Note
Acquire session information depends on the initial request. You don't need to
acquire the result if the initial request doesn't return a response body.
Even with the same API, parameters and target workbooks can introduce significant
differences. Therefore Excel API throttling isn't defined with simple and universal limit
numbers, as they would result in more restrictive limits. The following best practices will
help you complete tasks more quickly with fewer throttling errors.
Retry-After header
In many cases, a throttling response includes a Retry-After header. Respecting the
value of the header and delaying similar requests would help the client recover from
throttling. For details about handling error responses from Excel APIs in Microsoft
Graph, see Error handling for Excel APIs in Microsoft Graph.
Concurrent write requests to the same workbook don’t usually run in parallel (although
in some cases they do); rather, they are often the cause of throttling, timeout (when
requests are queued on servers), merge conflict (when concurrent sessions are involved)
and other types of failures. They also complicate error handling; for example, when you
receive a failure response, there is no way to confirm the status of other pending
requests, which makes it difficult to determine or to recover the state of the workbook.
See also
Use the Excel REST API
Error codes for workbooks and charts
APIs
Article • 06/30/2022
This article describes error codes that are returned by the workbooks and charts APIs in
Microsoft Graph when a request sent through these APIs fails. For details about
handling error responses from workbooks and charts APIs in Microsoft Graph, see Error
handling for Excel APIs in Microsoft Graph. For more details about error responses and
resource types in Microsoft Graph, see Microsoft Graph error responses and resource
types.
403 forbidden The caller doesn't have permission to perform the action.
405 methodNotAllowed The HTTP method in the request is not allowed on the resource.
409 conflict The current state conflicts with what the request expects.
500 internalServerError An internal server error occurred while processing the request.
502 badGateway The server encountered a temporary error and could not
complete your request.
503 serviceUnavailable The service is not available. Please try your request again.
Status Error Code Error Message
Code
504 gatewayTimeout The server, while acting as a proxy, did not receive a timely
response from the upstream server in order to complete the
request.
accessConflict
badRequestUncategorized
conflictUncategorized
forbiddenUncategorized
gatewayTimeoutUncategorized
internalServerErrorUncategorized
invalidSessionAccessConflict
invalidSessionAuthentication
invalidSessionNotFound
invalidSessionReCreatable
invalidSessionRestricted
invalidSessionUnexpected
invalidSessionUnsupportedWorkbook
methodNotAllowedUncategorized
notFoundUncategorized
notImplementedUncategorized
payloadTooLargeUncategorized
serviceUnavailableUncategorized
tooManyRequestsUncategorized
transientFailure
unauthorizedUncategorized
unsupportedWorkbook
For examples of optional error codes within the first-level of nested innerError objects,
see Optional second-level error code examples.
7 Note
The innerError object might recursively contain more deeper innerError objects
with additional, more specific error codes. These deeper innerError codes are
intended for diagnostics purpose only.
See also
Use the Excel REST API
Error handling for Excel APIs
Article • 07/06/2022
This article provides general instructions and suggestions for handling errors that are
returned by the Excel APIs in Microsoft Graph when a request sent through the API fails.
HTTP
{
"error": <Error object>
}
The second is from the long-running operation pattern, which can return a 200 OK HTTP
status code and failed operation status in response body, as in the following example.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"status": "failed",
"error": <Error object>
}
For both of these error responses, the error object has the following structure.
7 Note
Error responses follow the definition in the OData v4 specification for error
responses.
JSON
{
"code": "string",
"message": "string",
"innerError": { "@odata.type": "odata.error" }
}
The innerError object might recursively contain more innerError objects with additional,
more specific error codes. For example, the error object might contain more detailed
error information in the second-level error code and message, as shown.
JSON
{
"code": "Top-level error code",
"message": "Top-level error message",
"innerError": {
"code": "Second-level error code",
"message": "Second-level error message",
"innerError": { "@odata.type": "odata.error" }
}
}
Code Instructions
accessConflict The failed request conflicts with other clients accessing the
workbook (for example, another client has locked the
workbook for edit). The Microsoft Graph client is not
expected to resend the failed request until the conflict is
resolved. An end user can choose to manually perform the
same operations with Excel Online to get more details
about the conflict.
conflictUncategorized The failed request conflicts with certain server state. The
Microsoft Graph client is not expected to resend the failed
request until the conflict is resolved. An end user can
choose to manually perform the same operations with Excel
Online to get more details about the conflict.
gatewayTimeoutUncategorized The service wasn’t able to complete the request within the
time limit.
payloadTooLargeUncategorized The request payload exceeds the size limit. The Microsoft
Graph client is not expected to resend the failed request.
7 Note
For the regular pattern, the failed request is defined as the request that
corresponds to the response. For the long-running operation pattern, the failed
request is the one that triggers the failed operation.
Code Instructions
accessDenied You cannot perform the requested operation (for example, performing
changes to locked cells). The Microsoft Graph client is not expected to
resend the failed request.
filteredRangeConflict The operation failed because it conflicts with a filtered range. The
Microsoft Graph client is not expected to resend the failed request.
generalException An internal error occurred while processing the request. The Microsoft
Graph client is not expected to resend the failed request.
invalidReference This reference is not valid for the current operation. The Microsoft
Graph client is not expected to resend the failed request.
itemAlreadyExists The resource being created already exists. The Microsoft Graph client is
not expected to resend the failed request.
itemNotFound The requested resource doesn't exist. The Microsoft Graph client is not
expected to resend the failed request.
methodNotAllowed The HTTP method specified in the request is not allowed on the
resource. The Microsoft Graph client is not expected to resend the failed
request.
nonBlankCellOffSheet Can't insert new cells because it would push non-empty cells off the end
of the worksheet. The Microsoft Graph client is not expected to resend
the failed request. An end user can delete rows or columns to make
room for content to be inserted and then try again.
rangeExceedsLimit The cell count in range has exceeded the maximum supported number.
The Microsoft Graph client can try to send a request with smaller range
size. For more information, see Resource limits and performance
optimization for Office Add-ins.
requestAborted The request was aborted during run time, which was usually caused by
long time calculation from functions in the workbook. The Microsoft
Graph client is not expected to resend the failed request.
Code Instructions
unsupportedOperation The operation being attempted is not supported. The Microsoft Graph
client is not expected to resend the failed request.
7 Note
For the regular pattern, the failed request is defined as the request that
corresponds to the response. For the long-running operation pattern, the failed
request is the one that triggers the failed operation.
Diagnostic information
All contents in the response that are not used in the previous steps are for diagnostics
purpose only (including strings in the message fields). We don't recommend that you
take a dependency on these contents as they might change without notice.
See also
Use the Excel REST API
Microsoft Graph authentication and
authorization overview
Learn how to authenticate and work with permissions to securely access data through
Microsoft Graph. Explore the following documentation to learn about app registration,
authentication libraries, authorization, and other parts of the Microsoft identity platform
that support Microsoft Graph development.
Get started
p CONCEPT
App registration
Permissions overview
q VIDEO
c HOW-TO GUIDE
i REFERENCE
Permissions reference
c HOW-TO GUIDE
c
Manage app access
i REFERENCE
Authorization errors
a DOWNLOAD
Android
Angular
ASP.NET
iOS
JavaScript
Python
UWP
Xamarin
a DOWNLOAD
Android
iOS
Java
JavaScript
Node.js
PHP
Python
Ruby
React Native
Authentication and authorization basics
Article • 05/26/2023
Microsoft Graph is a protected web API for accessing data in Microsoft cloud services
like Azure Active Directory and Microsoft 365. It's protected by the Microsoft identity
platform, which uses OAuth access tokens to verify that an app is authorized to call
Microsoft Graph.
This article provides an overview of the Microsoft identity platform, access tokens, and
how your app can get access tokens. For more information about the Microsoft identity
platform, see What is the Microsoft identity platform?. If you know how to integrate an
app with the Microsoft identity platform to get tokens, see information and samples
specific to Microsoft Graph in the next steps section.
For more information, see Register an application with the Microsoft identity platform.
Access scenarios
The method that an app uses to authenticate with the Microsoft identity platform
depends on how you want the app to access the data. This access can be in one of two
ways as illustrated in the following image.
Delegated access requires delegated permissions, also referred to as scopes. Scopes are
permissions that are exposed by a given resource and they represent the operations
that an app can perform on behalf of a user.
Because both the app and the user must be authorized to make the request, the
resource grants the client app the delegated permissions, for the client app to access
data on behalf of the specified user. For the user, the actions that they can perform on
the resource rely on the permissions that they have to access the resource. For example,
the user might be the owner of the resource, or they might be assigned a particular role
through a role-based access control system (RBAC) such as Azure AD RBAC.
Apps get privileges to call Microsoft Graph with their own identity through one of the
following ways:
When the app is assigned application permissions, also called app roles
When the app is assigned ownership of the resource that it intends to manage
7 Note
An app can also get privileges through permissions granted by a role-based access
control system such as Azure AD RBAC.
Microsoft Graph exposes two types of permissions for the supported access scenarios:
Delegated permissions: Also called scopes, allow the application to act on behalf of
the signed-in user.
Application permissions: Also called app roles, allow the app to access data on its
own, without a signed-in user.
When a user signs in to an app, the app must specify the permissions it needs to be
included in the access token. These permissions:
For more information about permissions and consent, see Introduction to permissions
and consent.
7 Note
As a best practice, request the least privileged permissions that your app needs in
order to access data and function correctly. Requesting permissions with more than
the necessary privileges is poor security practice, which may cause users to refrain
from consenting and affect your app's usage.
For more information about Microsoft Graph permissions and how to use them, see the
Overview of Microsoft Graph permissions.
Access tokens
An application makes an authentication request to the Microsoft identity platform to get
access tokens that it uses to call an API, such as Microsoft Graph. Access tokens that the
Microsoft identity platform issues contain claims which are details about the application
and in delegated access scenarios, the user. Web APIs that are secured by the Microsoft
identity platform, such as Microsoft Graph, use the claims to validate the caller and to
ensure that the caller has the proper privileges to perform the operation they're
requesting. The caller should treat access tokens as opaque strings because the contents
of the token are intended for the API only. When calling Microsoft Graph, always protect
access tokens by transmitting them over a secure channel that uses transport layer
security (TLS).
jwt
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5
SEpsWSJ9.eyJhdWQiOiI2ZTc0MTcyYi1iZTU2LTQ4NDMtOWZmNC1lNjZhMzliYjEyZTMiLCJpc3M
iOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vNzJmOTg4YmYtODZmMS00MWFmLTk
xYWItMmQ3Y2QwMTFkYjQ3L3YyLjAiLCJpYXQiOjE1MzcyMzEwNDgsIm5iZiI6MTUzNzIzMTA0OCw
iZXhwIjoxNTM3MjM0OTQ4LCJhaW8iOiJBWFFBaS84SUFBQUF0QWFaTG8zQ2hNaWY2S09udHRSQjd
lQnE0L0RjY1F6amNKR3hQWXkvQzNqRGFOR3hYZDZ3TklJVkdSZ2hOUm53SjFsT2NBbk5aY2p2a29
5ckZ4Q3R0djMzMTQwUmlvT0ZKNGJDQ0dWdW9DYWcxdU9UVDIyMjIyZ0h3TFBZUS91Zjc5UVgrMEt
JaWpkcm1wNjlSY3R6bVE9PSIsImF6cCI6IjZlNzQxNzJiLWJlNTYtNDg0My05ZmY0LWU2NmEzOWJ
iMTJlMyIsImF6cGFjciI6IjAiLCJuYW1lIjoiQWJlIExpbmNvbG4iLCJvaWQiOiI2OTAyMjJiZS1
mZjFhLTRkNTYtYWJkMS03ZTRmN2QzOGU0NzQiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhYmVsaUB
taWNyb3NvZnQuY29tIiwicmgiOiJJIiwic2NwIjoiYWNjZXNzX2FzX3VzZXIiLCJzdWIiOiJIS1p
wZmFIeVdhZGVPb3VZbGl0anJJLUtmZlRtMjIyWDVyclYzeERxZktRIiwidGlkIjoiNzJmOTg4YmY
tODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjQ3IiwidXRpIjoiZnFpQnFYTFBqMGVRYTgyUy1JWUZ
BQSIsInZlciI6IjIuMCJ9.pj4N-w_3Us9DrBLfpCt
Access tokens are a kind of security token that the Microsoft identity platform provides.
They're short-lived but with variable default lifetimes.
To call Microsoft Graph, the app makes an authorization request by attaching the access
token as a Bearer token to the Authorization header in an HTTP request. For example,
the following call that returns the profile information of the signed-in user (the access
token has been shortened for readability):
HTTP
Microsoft Authentication Library (MSAL) client libraries are available for various
frameworks including for .NET, JavaScript, Android, and iOS. All platforms are in
production-supported preview, and, in the event breaking changes are introduced,
Microsoft guarantees a path to upgrade.
Server middleware from Microsoft is available for .NET core and ASP.NET (OWIN
OpenID Connect and OAuth) and for Node.js (Microsoft identity platform
Passport.js).
The Microsoft identity platform is also compatible with many third-party
authentication libraries.
For a complete list of Microsoft client libraries, Microsoft server middleware, and
compatible third-party libraries, see Microsoft identity platform documentation.
You don't need to use an authentication library to get an access token. To learn about
directly using the Microsoft identity platform endpoints without the help of an
authentication library, see the following articles:
See also
Microsoft identity platform documentation.
Choose a Microsoft Graph authentication provider based on scenario.
Overview of Microsoft Graph permissions.
Use the Get started page to find the libraries, samples, training content, and other
resources for your favorite platform.
See our Microsoft Graph samples on GitHub.
Register an application with the
Microsoft identity platform
Article • 01/27/2023
Get started with the Microsoft identity platform by registering an application in the
Azure portal.
The Microsoft identity platform performs identity and access management (IAM) only
for registered applications. Whether it's a client application like a web or mobile app, or
it's a web API that backs a client app, registering it establishes a trust relationship
between your application and the identity provider, the Microsoft identity platform.
Tip
To register an application for Azure AD B2C, follow the steps in Tutorial: Register a
web application in Azure AD B2C.
Prerequisites
An Azure account that has an active subscription. Create an account for free .
The Azure account must have permission to manage applications in Azure Active
Directory (Azure AD). Any of the following Azure AD roles include the required
permissions:
Application administrator
Application developer
Cloud application administrator
Completion of the Set up a tenant quickstart.
Register an application
Registering your application establishes a trust relationship between your app and the
Microsoft identity platform. The trust is unidirectional: your app trusts the Microsoft
identity platform, and not the other way around.
5. Enter a display Name for your application. Users of your application might see the
display name when they use the app, for example during sign-in. You can change
the display name at any time and multiple app registrations can share the same
name. The app registration's automatically generated Application (client) ID, not its
display name, uniquely identifies your app within the identity platform.
6. Specify who can use the application, sometimes called its sign-in audience.
Supported Description
account types
Accounts in this Select this option if you're building an application for use only by users
organizational (or guests) in your tenant.
directory only
Often called a line-of-business (LOB) application, this app is a single-
tenant application in the Microsoft identity platform.
Accounts in any Select this option if you want users in any Azure Active Directory
organizational (Azure AD) tenant to be able to use your application. This option is
directory appropriate if, for example, you're building a software-as-a-service
(SaaS) application that you intend to provide to multiple organizations.
Accounts in any Select this option to target the widest set of customers.
organizational
directory and By selecting this option, you're registering a multitenant application
personal that can also support users who have personal Microsoft accounts.
Microsoft
accounts
Personal Select this option if you're building an application only for users who
Microsoft have personal Microsoft accounts. Personal Microsoft accounts include
accounts Skype, Xbox, Live, and Hotmail accounts.
7. Don't enter anything for Redirect URI (optional). You'll configure a redirect URI in
the next section.
) Important
New app registrations are hidden to users by default. When you are ready for users
to see the app on their My Apps page you can enable it. To enable the app, in
the Azure portal navigate to Azure Active Directory > Enterprise applications and
select the app. Then on the Properties page toggle Visible to users? to Yes.
In a production web application, for example, the redirect URI is often a public endpoint
where your app is running, like https://contoso.com/auth-response . During
development, it's common to also add the endpoint where you run your app locally, like
https://127.0.0.1/auth-response or http://localhost/auth-response .
You add and modify redirect URIs for your registered applications by configuring their
platform settings.
4. Under Configure platforms, select the tile for your application type (platform) to
configure its settings.
Web Enter a Redirect URI for your app. This URI is the location where the
Microsoft identity platform redirects a user's client and sends security tokens
after authentication.
Select this platform for standard web applications that run on a server.
Single-page Enter a Redirect URI for your app. This URI is the location where the
application Microsoft identity platform redirects a user's client and sends security tokens
after authentication.
iOS / Enter the app Bundle ID. Find it in Build Settings or in Xcode in Info.plist.
macOS
A redirect URI is generated for you when you specify a Bundle ID.
Android Enter the app Package name. Find it in the AndroidManifest.xml file. Also
generate and enter the Signature hash.
A redirect URI is generated for you when you specify these settings.
Mobile and Select one of the Suggested redirect URIs. Or specify a Custom redirect
desktop URI.
applications
For desktop applications using embedded browser, we recommend
https://login.microsoftonline.com/common/oauth2/nativeclient
Select this platform for mobile applications that aren't using the latest
Microsoft Authentication Library (MSAL) or aren't using a broker. Also select
this platform for desktop applications.
Add credentials
Credentials are used by confidential client applications that access a web API. Examples
of confidential clients are web apps, other web APIs, or service-type and daemon-type
applications. Credentials allow your application to authenticate as itself, requiring no
interaction from a user at runtime.
You can add both certificates and client secrets (a string) as credentials to your
confidential client app registration.
Option 1: Add a certificate
Sometimes called a public key, a certificate is the recommended credential type because
they're considered more secure than client secrets. For more information about using a
certificate as an authentication method in your application, see Microsoft identity
platform application authentication certificate credentials.
Client secrets are considered less secure than certificate credentials. Application
developers sometimes use client secrets during local app development because of their
ease of use. However, you should use certificate credentials for any of your applications
that are running in production.
1. In the Azure portal, in App registrations, select your application.
2. Select Certificates & secrets > Client secrets > New client secret.
3. Add a description for your client secret.
4. Select an expiration for the secret or specify a custom lifetime.
Client secret lifetime is limited to two years (24 months) or less. You can't
specify a custom lifetime longer than 24 months.
Microsoft recommends that you set an expiration value of less than 12
months.
5. Select Add.
6. Record the secret's value for use in your client application code. This secret value is
never displayed again after you leave this page.
For application security recommendations, see Microsoft identity platform best practices
and recommendations.
2. Select Certificates & secrets > Federated credentials > Add a credential.
3. In the Federated credential scenario drop-down box, select one of the supported
scenarios, and follow the corresponding guidance to complete the configuration.
Customer managed keys for encrypt data in your tenant using Azure Key
Vault in another tenant.
GitHub actions deploying Azure resources to configure a GitHub workflow
to get tokens for your application and deploy assets to Azure.
Kubernetes accessing Azure resources to configure a Kubernetes service
account to get tokens for your application and access Azure resources.
Other issuer to configure an identity managed by an external OpenID
Connect provider to get tokens for your application and access Azure
resources.
For more information, how to get an access token with a federated credential, check out
the Microsoft identity platform and the OAuth 2.0 client credentials flow article.
Next steps
Learn more about permissions and consent in the Microsoft identity platform or
how permissions work in Microsoft Graph.
Choose a quick start that walks you through adding core identity and access
management (IAM) features to your applications and best practices for keeping
your apps secure and available.
Learn more about the two Azure AD objects that represent a registered application
and the relationship between them: Application objects and service principal
objects.
Get access on behalf of a user
Article • 05/26/2023
This article is part of a series on authentication and authorization for Microsoft Graph
through the Microsoft identity platform. The preceding article is Register an application
with the Microsoft identity platform.
To call Microsoft Graph, an app must obtain an access token from the Microsoft identity
platform. This access token includes information about whether the app is authorized to
access Microsoft Graph on behalf of a signed-in user or with its own identity. This article
provides guidance on how an app can access Microsoft Graph on behalf of a user, also
called delegated access.
This article details the raw HTTP requests involved for an app to get access on behalf of
a user using a popular flow called the OAuth 2.0 authorization code grant flow.
Alternatively, you can avoid writing raw HTTP requests and use a Microsoft-built or
supported authentication library that handles many of these details for you and helps
you to get access tokens and call Microsoft Graph. For more information, see Use the
Microsoft Authentication Library (MSAL).
Prerequisites
Before proceeding with the steps in this article:
Try steps 2-5 in Postman. Don't forget to replace tokens and IDs!
2. Request authorization
The first step in the authorization code flow is for the user to authorize the app to act on
their behalf.
In the flow, the app redirects the user to the Microsoft identity platform /authorize
endpoint. Through this endpoint, Azure AD signs the user in and requests their consent
for the permissions that the app requests. After consent is obtained, Azure AD will
return an authorization code to the app. The app can then redeem this code at the
Microsoft identity platform /token endpoint for an access token.
Authorization request
The following example shows a request to the /authorize endpoint.
In the request URL, you call the /authorize endpoint and specify the required and
recommended properties as query parameters.
In the following example, the app requests the User.Read and Mail.Read Microsoft Graph
permissions, which allow the app to read the profile and mail of the signed-in user
respectively. The offline_access permission is a standard OIDC scope that's requested so
that the app can get a refresh token. The app can use the refresh token to get a new
access token when the current one expires.
HTTP
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=11111111-1111-1111-1111-111111111111
&response_type=code
&redirect_uri=https%3A%2F%2Fptop.only.wip.la%3A443%2Fhttp%2Flocalhost%2Fmyapp%2F
&response_mode=query
&scope=offline_access%20user.read%20mail.read
&state=12345
Parameters
tenant Required The {tenant} value in the path of the request can be used to
control who can sign into the application. The allowed values
are:
common for both Microsoft accounts and work or school
accounts
organizations for work or school accounts only
consumers for Microsoft accounts only
tenant identifiers such as the tenant ID or domain name.
For more information, see protocol basics.
client_id Required The Application (client) ID that the registration portal assigned
the app. Also referred to as appId in the Microsoft Graph
application and service principal object.
response_type Required Must include code for the OAuth 2.0 authorization code flow.
redirect_uri Recommended The redirect URI of the app, where authentication responses are
sent to and received by the app. It must exactly match one of the
redirect URIs you registered in the app registration portal, except
it must be URL encoded. For native and mobile apps, you should
use the default value of
https://login.microsoftonline.com/common/oauth2/nativeclient .
Parameter Required Description
response_mode Recommended Specifies the method that should be used to send the resulting
token back to the app. Can be query or form_post .
state Recommended A value included in the request that's also returned in the token
response. It can be a string of any content that you wish. A
randomly generated unique value is typically used for preventing
cross-site request forgery attacks . This property is also used to
encode information about the user's state in the app before the
authentication request occurred, such as the page or view they
were on.
The following screenshot is an example of the consent dialog box presented for a
Microsoft account user.
Authorization response
If the user consents to the permissions the app requested, the response contains the
authorization code in the code parameter. Here's an example of a successful response
to the previous request. Because the response_mode parameter in the request was set to
query , the response is returned in the query string of the redirect URL.
HTTP/1.1 200 OK
https://localhost/myapp/?code=M0ab92efe-b6fd-df08-87dc-
2c6500a7f84d&state=12345&session_state=fe1540c3-a69a-469a-9fa3-8a2470936421#
Query parameters
Parameter Description
code The authorization code that the app requested. The app uses the authorization
code to request an access token for the target resource. Authorization codes are
short lived, typically they expire after about 10 minutes.
state If a state parameter is included in the request, the same value should appear in
the response. The app should verify that the state values in the request and
response are identical. This check helps to detect Cross-Site Request Forgery
(CSRF) attacks against the client.
session_state A unique value that identifies the current user session. This value is a GUID, but
should be treated as an opaque value that is passed without examination.
Token request
HTTP
client_id=11111111-1111-1111-1111-111111111111
&scope=user.read%20mail.read
&code=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq3n8b2JRLk4OxV
Xr...
&redirect_uri=https%3A%2F%2Fptop.only.wip.la%3A443%2Fhttp%2Flocalhost%2Fmyapp%2F
&grant_type=authorization_code
&client_secret=HF8Q~Krjqh4r... // NOTE: Only required for web apps
Parameters
tenant Required The {tenant} value in the path of the request can be used to control
who can sign into the application. The allowed values are:
common for both Microsoft accounts and work or school accounts
organizations for work or school accounts only
consumers for Microsoft accounts only
tenant identifiers such as the tenant ID or domain name.
For more information, see protocol basics.
client_id Required The Application (client) ID that the registration portal assigned the
app. Also referred to as appId in the Microsoft Graph application and
service principal object.
code Required The authorization code that you acquired in the authorization leg in
Step 2.
redirect_uri Required The same redirect URI value that was used to acquire the authorization
code in Step 2.
client_secret Required The client secret that you created in the app registration portal for
for web your app. It shouldn't be used in a native app, because client secrets
apps can't be reliably stored on devices. It's required for web apps and web
APIs, which have the ability to store the client_secret securely on the
server side.
Token response
The access token contains a list of the permissions that the access token is good for in
the scope parameter. The response is similar to the following sample.
JSON
HTTP/1.1 200 OK
Content-type: application/json
{
"token_type": "Bearer",
"scope": "Mail.Read User.Read",
"expires_in": 3736,
"ext_expires_in": 3736,
"access_token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...",
"refresh_token": "AwABAAAAvPM1KaPlrEqdFSBzjqfTGAMxZGUTdM0t4B4..."
}
Parameter Description
token_type Indicates the token type value. The only type that Azure AD supports is Bearer .
scope A space separated list of the Microsoft Graph permissions that the access token is
valid for.
ext_expires_in Indicates an extended lifetime for the access token (in seconds) and used to
support resiliency when the token issuance service isn't responding.
access_token The requested access token. The app can use this token to call Microsoft Graph.
refresh_token An OAuth 2.0 refresh token. The app can use this token to acquire additional
access tokens after the current access token expires. Refresh tokens are long-
lived, and can be used to retain access to resources for extended periods of time.
A refresh token will only be returned if offline_access was included as a scope
parameter. For details, see the v2.0 token reference.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me
Authorization: Bearer eyJ0eXAiO ... 0X2tnSQLEANnSPHY0gKcgw
Host: graph.microsoft.com
Response
A successful response looks similar to the following (some response headers have been
removed).
HTTP/1.1 200 OK
Content-Type:
application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatib
le=false;charset=utf-8
request-id: f45d08c0-6901-473a-90f5-7867287de97f
client-request-id: f45d08c0-6901-473a-90f5-7867287de97f
OData-Version: 4.0
Duration: 727.0022
Date: Thu, 20 Apr 2017 05:21:18 GMT
Content-Length: 407
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"businessPhones": [
"425-555-0100"
],
"displayName": "MOD Administrator",
"givenName": "MOD",
"jobTitle": null,
"mail": "[email protected]",
"mobilePhone": "425-555-0101",
"officeLocation": null,
"preferredLanguage": "en-US",
"surname": "Administrator",
"userPrincipalName": "[email protected]",
"id": "10a08e2e-3ea2-4ce0-80cb-d5fdd4b05ea6"
}
Request
HTTP
client_id=11111111-1111-1111-1111-111111111111
&scope=user.read%20mail.read
&refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
&grant_type=refresh_token
&client_secret=jXoM3iz... // NOTE: Only required for web apps
Parameters
tenant Required The {tenant} value in the path of the request can be used to control
who can sign into the application. The allowed values are:
common for both Microsoft accounts and work or school accounts
organizations for work or school accounts only
consumers for Microsoft accounts only
tenant identifiers such as the tenant ID or domain name.
For more information, see protocol basics.
client_id Required The Application (client) ID that the registration portal assigned
your app. Also referred to as appId in the Microsoft Graph
application and service principal object.
refresh_token Required The refresh_token that your app acquired during the token request in
Step 3.
client_secret Required The client secret that you created in the app registration portal for
for web your app. Don't use the secret in a native app, because client_secrets
apps can't be reliably stored on devices. It's required for web apps and
web APIs, which have the ability to store the client_secret securely on
the server side.
Response
A successful token response looks similar to the following.
JSON
HTTP/1.1 200 OK
Content-type: application/json
{
"access_token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...",
"token_type": "Bearer",
"expires_in": 3599,
"scope": "Mail.Read User.Read",
"refresh_token": "AwABAAAAvPM1KaPlrEqdFSBzjqfTGAMxZGUTdM0t4B4...",
}
Parameter Description
access_token The requested access token. The app can use this token in calls to Microsoft
Graph.
token_type Indicates the token type value. The only type that Azure AD supports is Bearer .
refresh_token A new OAuth 2.0 refresh token. Replace the old refresh token with this newly
acquired refresh token to ensure your refresh tokens remain valid for as long as
possible.
Additional resources
You can call Microsoft Graph on behalf of a user from different types of apps, such as
single-page apps, web apps, and mobile apps. For more information, see Authentication
flows and application scenarios.
In addition to the OAuth 2.0 authorization code grant flow, the Microsoft identity
platform supports different authentication flows for delegated and app-only access
scenarios. For more information, see Scenarios and supported authentication flows.
MSAL and other supported authentication libraries simplify the process for you by
handling details such as validation, cookie handling, token caching, and secure
connections, allowing you to focus on the functionality of your application.
Microsoft has built and maintains a wide selection of code samples that demonstrate
usage of supported authentication libraries with the Microsoft identity platform. To
access these code samples, see the Next steps.
Next steps
This article is part of the following series of articles on authentication and authorization
for Microsoft Graph through the Microsoft identity platform.
Next, choose from code samples that are built and maintained by Microsoft to run
custom apps that use supported authentication libraries, sign-in users, and call
Microsoft Graph.
Microsoft Graph tutorials >
Get access without a user
Article • 05/26/2023
This article is part of a series on authentication and authorization for Microsoft Graph
through the Microsoft identity platform. The preceding article is Register an application
with the Microsoft identity platform.
To call Microsoft Graph, an app must obtain an access token from the Microsoft identity
platform. This access token includes information about whether the app is authorized to
access Microsoft Graph on behalf of a signed-in user or with its own identity. This article
provides guidance on how an app can access Microsoft Graph with its own identity, also
called app-only access.
This article details the raw HTTP requests involved for an app to call Microsoft Graph
with its own identity using a popular flow called the OAuth 2.0 client credentials grant
flow. Alternatively, you can avoid writing raw HTTP requests and use a Microsoft-built or
supported authentication library that handles many of these details for you and helps
you to get access tokens and call Microsoft Graph. For more information, see Use the
Microsoft Authentication Library (MSAL).
Prerequisites
Before proceeding with the steps in this article:
Try steps 2-5 in Postman. Don't forget to replace tokens and IDs!
You pre-configure the application permissions the app needs when you register the app.
An administrator can consent to these permissions either using the Azure portal when
they install the app in their organization, or you can provide a sign-up experience in the
app through which administrators can consent to the permissions you configured. Once
Azure AD records the administrator consent, the app can request tokens without having
to request consent again.
To configure application permissions for the app in the Azure app registrations portal ,
follow these steps:
The following screenshot shows the Select Permissions dialog box for Microsoft Graph
application permissions.
) Important
Always configure the least privileged set of permissions required by the app. For
more information, see Best practices for using Microsoft Graph permissions.
) Important
When you change the configured permissions, you must also repeat the admin
consent process. Changes made in the app registration portal will not be reflected
until an authorized administrator such as a global administrator reconsents to the
app.
Request
HTTP
HTTP
GET https://login.microsoftonline.com/{tenant}/adminconsent
?client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&state=12345
&redirect_uri=https://localhost/myapp/permissions
tenant Required The directory tenant that you want to request permission from.
The value can be in GUID or a friendly name format. If you don't
know which tenant the user belongs to and you want to let them
sign in with any tenant, use common .
client_id Required The application ID that the Azure app registration portal
assigned to your app.
redirect_uri Required The redirect URI where you want the response to be sent for your
app to handle. It must match one of the redirect URIs that you
registered in the portal. It must be URL encoded and it can have
additional path segments.
state Recommended A value that is included in the request that also is returned in the
token response. It can be a string of any content that you want.
The state is used to encode information about the user's state in
the app before the authentication request occurred, such as the
page or view they were on.
The following screenshot is an example of the consent dialog that Azure AD presents to
the administrator:
Response
If the administrator approves the permissions for your application, the successful
response looks like this:
HTTP
https://localhost/myapp/permissions?admin_consent=True&tenant=38d49456-54d4-
455d-a8d6-c383c71e0a6d&state=12345#
Parameter Description
tenant The directory tenant that granted your application the permissions that it
requested, in GUID format.
state A value that is included in the request that also is returned in the token
response. It can be a string of any content that you want. The state is used to
encode information about the user's state in the app before the authentication
request occurred, such as the page or view they were on.
Try: You can try this for yourself by pasting the following request in a browser. If you
sign in as a global administrator for an Azure AD tenant, you will be presented with
the administrator consent dialog box for the app.
https://login.microsoftonline.com/common/adminconsent?client_id=6731de76-
14a6-49ae-97bc-
6eba6914391e&state=12345&redirect_uri=https://localhost/myapp/permissions
Token request
Send a POST request to the /token identity platform endpoint to acquire an access
token. In this request, the client uses the client secret.
HTTP
HTTP
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=535fb089-9ff3-47b6-9bfb-4f1264799865
&scope=https%3A%2F%2Fptop.only.wip.la%3A443%2Fhttps%2Fgraph.microsoft.com%2F.default
&client_secret=qWgdYAmab0YSkuL1qKv5bPX
&grant_type=client_credentials
tenant Required The directory tenant that you want to request permission from. The
value can be in GUID or a friendly name format.
client_id Required The application ID that the Azure app registration portal assigned
when you registered your app.
scope Required The value passed for the scope parameter in this request should be
the identifier (app ID URI) of the resource you want, affixed with the
.default suffix. For example, the Microsoft Graph resource app ID
URI is https://graph.microsoft.com/ . For Microsoft Graph, the value
of scope is therefore https://graph.microsoft.com/.default . This
value informs the Microsoft identity platform endpoint to include in
the access token all the app-level permissions the admin has
consented to.
client_secret Required The client secret that you generated for your app in the app
registration portal. Ensure that it's URL encoded.
Token response
JSON
{
"token_type": "Bearer",
"expires_in": 3599,
"ext_expires_in":3599,
"access_token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBP..."
}
Parameter Description
access_token The requested access token. Your app can use this token in calls to Microsoft
Graph.
ext_expires_in Used to indicate an extended lifetime for the access token and to support
resiliency when the token issuance service isn't responding.
token_type Indicates the token type value. The only type that Azure AD supports is Bearer .
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users
Authorization: Bearer eyJ0eXAiO ... 0X2tnSQLEANnSPHY0gKcgw
Host: graph.microsoft.com
A successful response looks like this (some response headers have been removed):
JSON
HTTP/1.1 200 OK
Content-Type:
application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatib
le=false;charset=utf-8
request-id: f45d08c0-6901-473a-90f5-7867287de97f
client-request-id: f45d08c0-6901-473a-90f5-7867287de97f
OData-Version: 4.0
Date: Wed, 26 Apr 2017 19:53:49 GMT
Content-Length: 407
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users",
"value": [
{
"businessPhones": [],
"displayName": "Conf Room Adams",
"givenName": null,
"jobTitle": null,
"mail": "[email protected]",
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "[email protected]",
"id": "8afc02cb-4d62-4dba-b536-9f6d73e9be26"
},
{
"businessPhones": [
"+1 425 555 0109"
],
"displayName": "Adele Vance",
"givenName": "Adele",
"jobTitle": "Retail Manager",
"mail": "[email protected]",
"mobilePhone": null,
"officeLocation": "18/2111",
"preferredLanguage": null,
"surname": "Vance",
"userPrincipalName": "[email protected]",
"id": "59bb3898-0621-4414-ac61-74f9d7201355"
}
]
}
In this article, the app used a client secret as the credential. You can optionally configure
a certificate or a federated identity credential.
For more information about apps that call Microsoft Graph under their own identity and
use the client credentials flow, see Authentication flows and application scenarios:
Daemon app that calls a web API in the daemon's name.
Use the Microsoft Authentication Library
(MSAL)
In this article, you walked through the low-level protocol details usually required only
when manually crafting and issuing raw HTTP requests to execute the client credentials
flow. In production apps, use a Microsoft-built or supported authentication library, such
as the Microsoft Authentication Library (MSAL), to get security tokens and call protected
web APIs such as Microsoft Graph.
MSAL and other supported authentication libraries simplify the process for you by
handling details such as validation, cookie handling, token caching, and secure
connections, allowing you to focus on the functionality of your application.
Microsoft has built and maintains a wide selection of code samples that demonstrate
usage of supported authentication libraries with the Microsoft identity platform. To
access these code samples, see the Next steps.
Next steps
This article is part of the following series of articles on authentication and authorization
for Microsoft Graph through the Microsoft identity platform.
Next, choose from code samples that are built and maintained by Microsoft to run
custom apps that use supported authentication libraries and call Microsoft Graph with
their own identities.
Before the Microsoft identity platform can authorize your app to access data in the
Microsoft cloud, the app must be granted the privileges that it needs. Similarly, before
the Microsoft identity platform can authorize your app to access data through Microsoft
Graph, the app must be granted the privileges that it needs.
One way to grant an app the privileges it needs to access and work with your data
through Microsoft Graph is by assigning it Microsoft Graph permissions.
This article introduces Microsoft Graph permissions and provides guidance for using
them. To see the full list of permissions that Microsoft Graph exposes, see the Microsoft
Graph permissions reference.
To learn more about how permissions work, watch the following video.
https://www.youtube-nocookie.com/embed/yXYzgWWVdSM
Permission types
Microsoft Graph supports two access scenarios, delegated access and app-only access. In
delegated access, the app calls Microsoft Graph on behalf of a signed-in user. In app-
only access, the app calls Microsoft Graph with its own identity, without a signed in user.
To support these access scenarios, Microsoft Graph exposes delegated permissions and
application permissions.
Delegated permissions
Delegated permissions, also called scopes, are used in the delegated access scenario.
They're permissions that allow the application to act on behalf of a signed-in user.
However, the application will never be able to access anything the signed-in user
couldn't access.
For example, an application has been granted the Files.Read.All delegated permission on
behalf of Tom, a user. The application will only be able to read all files in the
organization that Tom can already access. Tom may be able to access the files because
he has permissions through one of the following ways:
Therefore, in a delegated scenario, the privileges that an app has to act on behalf of a
user is determined by the Microsoft Graph permissions that the app has been granted
and the user's own permissions.
https://learn-video.azurefd.net/vod/player?show=one-dev-minute&ep=how-do-
delegated-permissions-work&locale=en-us&embedUrl=%2Fgraph%2Fpermissions-
overview
In a delegated access scenario, an app may allow users to sign in with their personal
Microsoft accounts, like Outlook.com, work or school accounts, or allow both account
types. All delegated permissions are valid for work or school accounts, but not all are
valid for personal Microsoft accounts. Use the Microsoft Graph permissions reference to
identify delegated permissions that are valid for personal Microsoft accounts.
When a user signs in to an app they, or, in some cases, an administrator, are given a
chance to consent to the delegated permissions. If they grant consent, the app can
access resources and APIs within the boundaries of the user's permissions.
7 Note
Permissions granted through Azure AD built-in roles don't limit the app to calling
Microsoft Graph APIs only.
Application permissions
Application permissions, also called app roles, are used in the app-only access scenario,
without a signed-in user present. The application will be able to access any data that the
permission is associated with. For example, an application granted the Files.Read.All
application permission will be able to read any file in the organization.
For apps that access resources and APIs without a signed-in user, the application
permissions can be consented to by an administrator when the app is installed in the
tenant or in the Azure portal. Only an administrator can consent to application
permissions.
Apart from being assigned Microsoft Graph application permissions, an app may also be
granted the privileges it needs through one of the following conditions:
When the app is assigned ownership of the resource that it intends to manage.
When the app is assigned an Azure AD built-in or custom administrative roles.
7 Note
Permissions granted through Azure AD built-in roles don't limit the app to calling
Microsoft Graph APIs only.
Access context Get access on behalf of a user Get access without a user
Who can Users can consent for their data Only admin can consent
consent Admins can consent for all users
{resource}.{operation}.{constraint}
{operation} Refers to the Microsoft Graph API operations that are allowed Read ,
on the data that's exposed by the resource. For example, Read ReadBasic ,
for read operations only, or ReadWrite for read, create, update, ReadWrite ,
and delete operations. Create ,
Manage , or
Migrate
{constraint} Determines the potential extent of access an app will have All ,
within the directory. This value may not be explicitly declared. AppFolder ,
When undeclared, the default constraint is limited to data that's OwnedBy ,
owned by the signed-in user. Selected ,
Shared , Hidden
Examples:
User.Read - Allows the app to read information about the signed-in user.
Application.ReadWrite.All - Allows the app to manage all applications in the tenant.
Application.ReadWrite.OwnedBy - Allows the app to manage only the applications
that it creates or owns.
Group.Create - Allows the application create new groups, but not modify or delete
them.
Member.Read.Hidden - Allows the app to read hidden memberships
For the full list of permissions exposed by Microsoft Graph, see the Microsoft Graph
permissions reference.
This principle is applied to all relationships that are of directoryObject type. Examples
include /groups/{id}/members , /users/{id}/memberOf or me/ownedObjects .
Example scenario
A group's members are users, groups, and devices. An app has been granted the
Microsoft Graph User.Read.All and Group.Read.All permissions. The app calls the list
group members API to retrieve the members of the group.
To read the basic properties of a group's members that are users, the app needs at least
the User.Read.All permission. To read the basic properties of a group's members that are
groups, the app needs at least the Group.Read.All permission. To read the basic
properties of a group's members that are devices, the app needs at least the
Device.Read.All permission.
Because the app has permissions to access only user and group objects in the group,
but not device objects, in the response:
All the basic properties of the user and group member objects are returned.
For the device member objects, only the object type and object ID are returned,
but all other properties have the value null.
Example
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/groups/{id}/members
Response
JSON
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#directoryObject
s",
"value":[
{
"@odata.type":"#microsoft.graph.user",
"id":"69d035a3-29c9-469f-809d-d21a4ae69e65",
"displayName":"Adele Vance",
"createdDateTime":"2019-09-18T09:06:51Z",
},
{
"@odata.type":"#microsoft.graph.group",
"id":"c43a7cc9-2d95-44b6-bf6a-6392e41949b4",
"displayName":"All Company",
"description":null,
"createdDateTime":"2019-10-24T01:34:35Z"
},
{
"@odata.type":"#microsoft.graph.device",
"id": "d282309e-f91d-43b6-badb-9e68aa4b4fc8",
"accountEnabled":null,
"deviceId":null,
"displayName":null,
"operatingSystem":null,
"operatingSystemVersion":null
}
]
}
An app needs to only read the profile information of the signed-in user. The app
requires only the User.Read permission, which is the least privileged permission to
access the signed-in user's information. Granting the app the User.ReadWrite
permission makes it over-privileged because the app doesn't need to update the
user's profile.
An app needs to read the groups in the tenant without a signed-in user. The app
requires only the Group.Read.All application permission, which is the least
privileged permission to read groups in the tenant without a signed-in user.
An app needs to read or write to a calendar of the signed-in user. The app
manages dynamic jobs, and syncs from the user’s Outlook calendar to keep the
app up-to-date so to schedule jobs for the user. Even though getting the user's
calendar data requires Calendars.Read, updating the calendar with scheduled jobs
requires a higher privileged permission, Calendars.ReadWrite. In this case, the app
should request Calendars.ReadWrite.
Granting an application more privileges than it needs is a poor security practice that
exposes an app to unauthorized and unintended access to data or operations. Also,
requesting more permissions than necessary may cause users to refrain from consenting
to an app, affecting an app's adoption and usage.
Apply the principle of least privilege when assigning and granting Microsoft Graph
permissions to an app. For more information, see Enhance security with the principle of
least privilege and Building apps that secure identity through permissions and consent.
PersonalMicrosoftAccount Consumer 30 30 30
users (such
as
Outlook.com
or Live.com
accounts)
AzureADandPersonalMicrosoftAccount Consumer 30 30 30
users and
users from
any Azure
AD
organization
See also
Microsoft Graph permissions reference.
Overview of role-based access control in Azure Active Directory.
Understanding delegated access
Microsoft Graph permissions reference
Article • 05/05/2023
For an app to access data in Microsoft Graph, the user or administrator must grant it the permissions it
needs. This topic lists the delegated and application permissions exposed by Microsoft Graph. For
guidance about how to use the permissions, see the Overview of Microsoft Graph permissions.
To find the unique identifiers for all permissions, see All permissions and IDs.
7 Note
As a best practice, request the least privileged permissions that your app needs in order to access
data and function correctly. Requesting permissions with more than the necessary privileges is poor
security practice, which may cause users to refrain from consenting and affect your app's usage.
Delegated permissions
AccessReview.Read.All Read all access Allows the app to read access Yes No
reviews reviews on behalf of the signed-
in user.
AccessReview.ReadWrite.All Manage all access Allows the app to read and write Yes No
reviews access reviews on behalf of the
signed-in user.
AccessReview.ReadWrite.Membership Manage access Allows the app to read and write Yes No
reviews for group access reviews of groups and
and app apps on behalf of the signed-in
memberships user.
Application permissions
AccessReview.Read.All Read all access Allows the app to read access reviews without a Yes
reviews signed-in user.
AccessReview.ReadWrite.All Manage all Allows the app to read, update, delete and Yes
access reviews perform actions on access reviews, reviewers,
decisions and settings in the organization,
without a signed-in user.
Permission Display String Description Admin
Consent
Required
AccessReview.ReadWrite.Membership Manage access Allows the app to manage access reviews of Yes
reviews for groups and apps without a signed-in user.
group and app
memberships
Remarks
AccessReview.Read.All, AccessReview.ReadWrite.All, AccessReview.ReadWrite.Membership are valid only for
work or school accounts.
For an app with delegated permissions to read access reviews of a group or app, the signed-in user must
be a member of one of the following administrator roles: Global Administrator, Security Administrator,
Security Reader or User Administrator. For an app with delegated permissions to write access reviews of a
group or app, the signed-in user must be a member of one of the following administrator roles: Global
Administrator or User Administrator.
For an app with delegated permissions to read access reviews of an Azure AD role, the signed-in user
must be a member of one of the following administrator roles: Global Administrator, Security
Administrator, Security Reader or Privileged Role Administrator. For an app with delegated permissions to
write access reviews of an Azure AD role, the signed-in user must be a member of one of the following
administrator roles: Global Administrator or Privileged Role Administrator.
For more information about administrator roles, see Assigning administrator roles in Azure Active
Directory.
Delegated permissions
AdministrativeUnit.ReadWrite.All Read and Allows the app to create, read, update, Yes No
write and delete administrative units and
administrative manage administrative unit membership
units on behalf of the signed-in user.
Application permissions
Permission Display Description Admin
String Consent
Required
AdministrativeUnit.Read.All Read all Allows the app to read administrative units and Yes
administrative administrative unit membership without a signed-in
units user.
AdministrativeUnit.ReadWrite.All Read and Allows the app to create, read, update, and delete Yes
write all administrative units and manage administrative unit
administrative membership without a signed-in user.
units
Remarks
With the AdministrativeUnit.Read.All permission an application can read administrative unit information
including members.
With the AdministrativeUnit.ReadWrite.All permission an application can create, read, update, and delete
administrative unit information including members.
Example usage
7 Note
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
Analytics.Read Read user Allows the app to read the signed-in user's activity statistics, such as No
activity how much time the user has spent on emails, in meetings, or in chat
statistics. sessions.
Application permissions
None.
Example usage
Delegated
Application
None.
Delegated permissions
AppCatalog.Read.All Read all Allows the app to read the apps in the app catalogs. No No
app
catalogs
AppCatalog.ReadWrite.All Read and Allows the app to create, read, update, and delete Yes No
write to apps in the app catalogs.
all app
catalogs
AppCatalog.Submit Submit Allows the user to submit and app for admin review Yes No
an app for publication in an organization's app catalog and
for allows user to cancel past submissions that have not
admin been published.
review 𝐍𝐎𝐓𝐄: Non-admin users submit apps for review by
including the requiresReview=true query parameter.
Application permissions
Permission Display String Description Admin
Consent
Required
AppCatalog.Read.All Read all app Allows the app to read apps in the app catalogs Yes
catalogs without a signed-in user.
AppCatalog.ReadWrite.All Read and write Allows the app to create, read, update, and delete Yes
to all app apps in the app catalogs without a signed-in user.
catalogs
Remarks
Currently the only catalog is the list of applications in Microsoft Teams.
Example usage
Delegated
AppCatalog.ReadWrite.All: List all applications in catalog ( GET /beta/appCatalogs/teamsApps )
AppCatalog.ReadWrite.All: Publish an app ( POST /beta/appCatalogs/teamsApps )
AppCatalog.ReadWrite.All: Update a published app ( PATCH /beta/appCatalogs/teamsApps/{id} )
AppCatalog.ReadWrite.All: Remove a published app ( DELETE /beta/appCatalogs/teamsApps/{id} )
Application
None.
Delegated permissions
Application.ReadWrite.All Read and Allows the app to create, read, update and Yes
write all apps delete applications and service principals on
behalf of the signed-in user.
AppRoleAssignment.ReadWrite.All Manage app Allows the app to manage permission grants Yes
permission for application permissions to any API
grants and (including Microsoft Graph) and application
app role assignments for any app, on behalf of the
assignments signed-in user.
Permission Display Description Admin
String Consent
Required
Application permissions
Application.Read.All Read Allows the app to read applications and service Yes
applications principals without a signed-in user.
Application.ReadWrite.All Read and Allows the calling app to create, and manage Yes
write all (read, update, update application secrets and
apps delete) applications and service principals
without a signed-in user. Does not allow
management of consent grants or application
assignments to users or groups.
AppRoleAssignment.ReadWrite.All Manage Allows the app to manage permission grants for Yes
app application permissions to any API (including
permission Microsoft Graph) and application assignments
grants and for any app, without a signed-in user.
app role
assignments
DelegatedPermissionGrant.ReadWrite.All Manage all Allows the app to grant or revoke any Yes
delegated delegated permission for any API (including
permission Microsoft Graph), without a signed-in user.
grants
Remarks
U Caution
7 Note
The Application.ReadWrite.OwnedBy permission allows an app to call GET /applications and GET
/servicePrincipals to list all applications and service principals in the tenant. This scope of access
has been allowed for the permission.
Example usage
Delegated
Application.Read.All: List all applications ( GET /v1.0/applications )
Application.ReadWrite.All: Update a service principal ( PATCH /v1.0/servicePrincipals/{id} )
Application
Delegated permissions
AuditLog.Read.All Read Allows the app to read and query your audit log Yes No
audit log activities, on behalf of the signed-in user.
data
Application permissions
AuditLog.Read.All Read all audit Allows the app to read and query your audit log activities, Yes
log data without a signed-in user.
Delegated permissions
EventListener.ReadWrite.All Read and write your Allows the app to read or write your Yes No
organization's organization's authentication event
authentication event listeners on behalf of the signed-in
listeners user.
Application permissions
EventListener.Read.All Read all Allows the app to read your organization's Yes
authentication event authentication event listeners without a signed-in
listeners user.
EventListener.ReadWrite.All Read and write all Allows the app to read or write your Yes
authentication event organization's authentication event listeners
listeners without a signed-in user.
BitlockerKey.ReadBasic.All Read basic Allows an app to read the BitLocker key's Yes No
BitLocker key properties for all devices in the tenant. The
information recovery key is not returned.
BitlockerKey.Read.All Read the Allows an app to read the BitLocker keys for Yes No
BitLocker key all devices in the tenant. The recovery key is
returned.
Application permissions
None.
Example usage
Delegated
BitlockerKey.ReadBasic.All: List the BitLocker recovery keys for all devices in the tenant without
returning the 'key' property ( GET /bitlocker/recoveryKeys ).
BitlockerKey.Read.All: Get a BitLocker recovery key with the recovery key ( GET
/bitlocker/recoveryKeys/{bitlockerRecoveryKeyId}?$select=key )
Bookings permissions
Delegated permissions
Application permissions
Bookings.Manage.All Allows an app to read, Allows the app to have full Yes No
write, and manage access.
Bookings Intended for a full
appointments, management experience.
businesses, customers, Typical target user is the
services, and staff on administrator of an
behalf of the signed-in organization.
user.
Example usage
Delegated
Bookings.Read.All: Get the ID and names of the collection of Bookings businesses that has been
created for a tenant ( GET /bookingBusinesses ).
BookingsAppointment.ReadWrite.All: Create an appointment for a service at a Bookings business
( POST /bookingBusinesses/{id}/appointments ).
Bookings.ReadWrite.All: Create a new service for the specified Bookings business ( POST
/bookingBusinesses/{id}/services ).
Bookings.Manage.All: Make the scheduling page of this business available to external customers
( POST /bookingBusinesses/{id}/publish ).
BrowserSiteLists.ReadWrite.All Read and write Allows an app to read and write the No No
browser site lists browser site lists configured for your
for your organization, on behalf of the signed-in
organization user.
Application permissions
BrowserSiteLists.Read.All Read all browser Allows an app to read all browser site Yes No
site lists for your lists configured for your organization,
organization without a signed-in user.
BrowserSiteLists.ReadWrite.All Read and write all Allows an app to read and write all Yes No
browser site lists browser site lists configured for your
for your organization, without a signed-in user.
organization
Example usage
Delegated
BrowserSiteLists.Read.All: List all browser site lists, on behalf of a signed-in user ( GET
/beta/admin/edge/internetExplorerMode/siteLists )
BrowserSiteLists.ReadWrite.All: Update a browser site list, on behalf of a signed-in user ( PATCH
/beta/admin/edge/internetExplorerMode/siteLists/{browserSiteListId} )
Application
BrowserSiteLists.Read.All: List all browser site lists, without a signed-in user ( GET
/beta/admin/edge/internetExplorerMode/siteLists )
BrowserSiteLists.ReadWrite.All: Delete a browser site list, without a signed-in user ( DELETE
/beta/admin/edge/internetExplorerMode/siteLists/{browserSiteListId} )
BusinessScenarioData.Read.OwnedBy Read all data Allows the app to read all Yes No
for business data associated with the
scenarios this business scenarios it owns.
app creates or Data access will be
owns attributed to the signed-in
user.
Application permissions
BusinessScenarioConfig.Read.OwnedBy Read all business Allows the app to read the Yes
scenario configurations of business
configurations this scenarios it owns, without a
app creates or owns signed-in user.
BusinessScenarioConfig.ReadWrite.OwnedBy Read and write all Allows the app to create new Yes
business scenario business scenarios and fully
configurations this manage the configurations of
app creates or owns scenarios it owns, without a
signed-in user.
BusinessScenarioData.Read.OwnedBy Read data for all Allows the app to read the data Yes
business scenarios associated with the business
this app creates or scenarios it owns, without a
owns signed-in user.
BusinessScenarioData.ReadWrite.OwnedBy Read and write data Allows the app to fully manage the Yes
for all business data associated with the business
scenarios this app scenarios it owns, without a
creates or owns signed-in user.
Example usage
Delegated
BusinessScenarioConfig.ReadWrite.OwnedBy: Create a new business scenario ( POST
/solutions/businessScenarios )
BusinessScenarioConfig.Read.All: Get a list of all business scenarios in an organization ( GET
/solutions/businessScenarios )
Application
BusinessScenarioConfig.ReadWrite.OwnedBy: Update the Planner plan configuration for a business
scenario ( PATCH
/solutions/businessScenarios/c5d514e6c6864911ac46c720affb6e4d/planner/planConfiguration )
ZocLUTDvBSpcAGRaa )
Calendars permissions
Delegated permissions
Permission Display Description Admin Microsoft
String Consent Account
Required supported
Calendars.Read Read user Allows the app to read events in user No Yes
calendars calendars.
Calendars.Read.Shared Read user Allows the app to read events in all calendars No No
and shared that the user can access, including delegate
calendars and shared calendars.
Calendars.ReadWrite Have full Allows the app to create, read, update, and No Yes
access to delete events in user calendars.
user
calendars
Calendars.ReadWrite.Shared Read and Allows the app to create, read, update and No No
write user delete events in all calendars the user has
and shared permissions to access. This includes delegate
calendars and shared calendars.
Calendars.ReadBasic Read basic Allows the app to read events in user Yes No
details of calendars, except for properties such as body,
user attachments, and extensions.
calendars
Application permissions
Calendars.Read Read calendars in Allows the app to read events of all calendars without a Yes
all mailboxes signed-in user.
Calendars.ReadWrite Read and write Allows the app to create, read, update, and delete events Yes
calendars in all of all calendars without a signed-in user.
mailboxes
Calendars.ReadBasic.All Read basic details Allows the app to read events of all calendars, except for Yes
of calendars in all properties such as body, attachments, and extensions,
mailboxes without a signed-in user.
Important Administrators can configure application access policy to limit app access to specific
mailboxes and not to all the mailboxes in the organization, even if the app has been granted the
application permissions of Calendars.Read or Calendars.ReadWrite.
Example usage
Delegated
Calendars.Read: Get events on the user's calendar between April 23, 2017 and April 29, 2017 ( GET
/me/calendarView?startDateTime=2017-04-23T00:00:00&endDateTime=2017-04-29T00:00:00 ).
Calendars.Read.Shared: Find meeting times where all attendees are available ( POST
/users/{id|userPrincipalName}/findMeetingTimes ).
Calendars.ReadWrite: Add an event to the user's calendar ( POST /me/events ).
Application
Calendars.Read: Find events in a conference room's calendar organized by [email protected] ( GET
/users/{id | userPrincipalName}/events?$filter=organizer/emailAddress/address eq
'[email protected]' ).
Calendars.Read: List all events on a user's calendar for the month of May ( GET /users/{id |
userPrincipalName}/calendarView?startDateTime=2017-05-01T00:00:00&endDateTime=2017-06-
01T00:00:00 )
Calendars.ReadWrite: Add an event to a user's calendar for approved time off ( POST /users/{id |
userPrincipalName}/events ).
For more complex scenarios involving multiple permissions, see Permission scenarios.
Calls permissions
Delegated permissions
None.
Application permissions
Calls.Initiate.All Initiate Allows the app to place outbound calls to a single user Yes
outgoing and transfer calls to users in your organization's directory,
1:1 calls without a signed-in user.
from the
app
Calls.InitiateGroupCall.All Initiate Allows the app to place outbound calls to multiple users Yes
outgoing and add participants to meetings in your organization,
group calls without a signed-in user.
from the
app
Calls.JoinGroupCall.All Join group Allows the app to join group calls and scheduled meetings Yes
calls and in your organization, without a signed-in user. The app will
meetings be joined with the privileges of a directory user to
as an app meetings in your tenant.
Calls.JoinGroupCallasGuest.All Join group Allows the app to anonymously join group calls and Yes
calls and scheduled meetings in your organization, without a
meetings signed-in user. The app will be joined as a guest to
as a guest meetings in your tenant.
Permission Display Description Admin
String Consent
Required
Calls.AccessMedia.All* Access Allows the app to get direct access to media streams in a Yes
media call, without a signed-in user.
streams in
a call as an
app
*Important: You may NOT use the Cloud Communications APIs to record or otherwise persist media
content from calls or meetings that your application accesses, or data derived from that media
content. Make sure that you are compliant with the laws and regulations in your area regarding data
protection and confidentiality of communications. Please see the Terms of Use and consult with your
legal counsel for more information.
Example usage
Application
Calls.Initiate.All: Make a peer-to-peer call from the application to a user in the organization ( POST
/beta/communications/calls ).
Calls.InitiateGroupCall.All: Make a group call from the application to a group of users in the
organization ( POST /beta/communications/calls ).
Calls.JoinGroupCall.All: Join a group call or online meeting from the application ( POST
/beta/communications/calls ).
Calls.JoinGroupCallasGuest.All: Join a group call or online meeting from the application, but the
application only has guest privileges in the meeting ( POST /beta/communications/calls ).
Calls.AccessMedia.All: Create or join a call and the app gets direct access to participant media
streams in the call ( POST /beta/communications/calls ).
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
None.
Application permissions
Permission Display String Description Admin
Consent
Required
CallRecords.Read.All Read all call records Allows the app to read call records for all calls and Yes
online meetings without a signed-in user.
CallRecord- Read PSTN and direct Allows the app to read all PSTN and direct routing Yes
PstnCalls.Read.All routing call log data call log data without a signed-in user.
Remarks
The CallRecords.Read.All permission grants an application privileged access to callRecords for every call
and online meeting within your organization, including calls to and from external phone numbers. This
includes potentially sensitive details about who participated in the call, as well as technical information
pertaining to these calls and meetings that can be used for network troubleshooting, such as IP
addresses, device details, and other network information.
The CallRecord-PstnCalls.Read.All permission grants an application access to PSTN (calling plans) and
direct routing call logs. This includes potentially sensitive information about users as well as calls to and
from external phone numbers.
Important: Discretion should be used when granting these permissions to applications. Call records
can provide insights into the operation of your business, and so can be a target for malicious actors.
Only grant these permissions to applications you trust to meet your data protection requirements.
Important: Make sure that you are compliant with the laws and regulations in your area regarding
data protection and confidentiality of communications. Please see the Terms of Use and consult with
your legal counsel for more information.
Example usage
Application
CallRecords.Read.All: Retrieve a call record ( GET /v1.0/communications/callRecords/{id} ).
CallRecords.Read.All: Subscribe to new call records ( POST /v1.0/subscriptions ).
CallRecords.Read.All: Retrieve direct routing call records within the specified time range ( GET
/v1.0/communications/callRecords/microsoft.graph.callRecords.getDirectRoutingCalls(fromDateTim
For more complex scenarios involving multiple permissions, see Permission scenarios.
Channel permissions
Delegated permissions
Channel.ReadBasic.All Read the names and Read channel names and channel No No
descriptions of descriptions, on behalf of the signed-
channels. in user.
Application permissions
Channel.ReadBasic.All Read the names and Read all channel names and channel Yes No
descriptions of all descriptions, without a signed-in
channels. user.
Delegated permissions
ChannelMember.ReadWrite.All Add and Add and remove members from channels, on Yes No
remove behalf of the signed-in user. Also allows
members changing a member's role, for example from
from owner to non-owner.
channels.
Application permissions
ChannelMember.Read.All Read the Read the members of all channels, without a Yes No
members of signed-in user.
all channels.
ChannelMember.ReadWrite.All Add and Add and remove members from all Yes No
remove channels, without a signed-in user. Also
members allows changing a member's role, for
from all example from owner to non-owner.
channels.
Delegated permissions
Application permissions
ChannelMessage.Read.All Read all Allows the app to read all channel Yes No
channel messages in Microsoft Teams,
messages without a signed-in user.
Delegated permissions
ChannelSettings.Read.All Read the names, Read all channel names, channel Yes No
descriptions, and descriptions, and channel settings,
settings of channels. on behalf of the signed-in user.
ChannelSettings.ReadWrite.All Read and write the Read and write the names, Yes No
names, descriptions, descriptions, and settings of all
and settings of channels, on behalf of the signed-
channels. in user.
Application permissions
ChannelSettings.Read.All Read the names, Read all channel names, channel Yes No
descriptions, and descriptions, and channel
settings of all channels. settings, without a signed-in
user.
ChannelSettings.ReadWrite.All Read and write the Read and write the names, Yes No
names, descriptions, descriptions, and settings of all
and settings of all channels, without a signed-in
channels. user.
Chat permissions
Delegated permissions
Chat.Read Read your chat Allows an app to read your 1:1 or group chat No No
messages. messages in Microsoft Teams, on your
behalf.
Chat.ReadBasic Read names and Allows an app to read the members and No No
members of user descriptions of 1:1 and group chats threads,
chat threads. on behalf of the signed-in user.
Chat.ReadWrite Read your chat Allows an app to read and send your 1:1 or No No
messages and group chat messages in Microsoft Teams, on
send new ones. your behalf.
Chat.ManageDeletion.All Delete and Allows the app to delete and recover deleted Yes No
recover deleted chats, on behalf of the signed-in user.
chats.
Application permissions
Chat.Read.WhereInstalled Read all chat Allows the app to read all one-to- Yes No
messages for chats one or group chat messages in
where the Microsoft Teams for chats where the
associated Teams associated Teams application is
application is installed, without a signed-in user.
installed.
Chat.Read.All Read all chat Allows the app to read all 1:1 or Yes No
messages. group chat messages in Microsoft
Teams, without a signed-in user.
Chat.ReadBasic.WhereInstalled Read names and Allows the app to read names and Yes No
members of all members of all one-to-one and
chat threads where group chats in Microsoft Teams
the associated where the associated Teams
Teams application application is installed, without a
is installed. signed-in user.
Chat.ReadBasic.All Read names and Read names and members of all chat Yes No
members of user threads.
chat threads.
Chat.UpdatePolicyViolation.All Flag chat messages Allows the app to update Microsoft Yes No
for violating policy. Teams 1:1 or group chat messages
by patching a set of Data Loss
Prevention (DLP) policy violation
properties to handle the output of
DLP processing.
Permission Display String Description Admin Microsoft
Consent Account
Required supported
Chat.ReadWrite.WhereInstalled Read and write all Allows the app to read and write all Yes No
chat messages for chat messages in Microsoft Teams
chats where the for chats where the associated
associated Teams Teams application is installed,
application is without a signed-in user.
installed.
Chat.ReadWrite.All Read and write all Allows an app to read and write all Yes No
chat messages. one-to-one and group chats in
Microsoft Teams, without a signed-in
user. Does not allow sending
messages.
Chat.ManageDeletion.All Delete and recover Allows the app to delete and recover Yes No
deleted chats. deleted chats, without a signed-in
user.
Delegated permissions
ChatMember.ReadWrite Add and remove Add and remove members from Yes No
members from chats on behalf of the signed-in
chats. user.
Application permissions
ChatMember.Read.WhereInstalled Read the members Allows the app to read the Yes No
of all chats where members of all chats where
the associated the associated Teams
Teams application application is installed,
is installed. without a signed-in user.
ChatMember.Read.All Read the members Allows the app to read all Yes No
of all chats. 1:1 or group chat messages
in Microsoft Teams, without
a signed-in user.
Permission Display String Description Admin Microsoft
Consent Account
Required supported
ChatMember.ReadWrite.WhereInstalled Add and remove Allows the app to add and Yes No
members from all remove members from all
chats where the chats where the associated
associated Teams Teams application is
application is installed, without a signed-
installed. in user.
Application permissions
ChatSettings.Read.Chat Read this chat's Allows the app to read this chat's No No
settings. settings, without a signed-in user.
ChatSettings.ReadWrite.Chat Read and write Allows the app to read and write this No No
this chat's chat's settings, without a signed-in
settings. user.
ChatMessage.Read.Chat Read this chat's Allows the app to read this chat's No No
messages. messages, without a signed-in user.
ChatMember.Read.Chat Read this chat's Allows the app to read this chat's No No
members. members, without a signed-in user.
TeamsTab.Read.Chat Read this chat's Allows the app to read this chat's tabs, No No
tabs. without a signed-in user.
TeamsAppInstallation.Read.Chat Read which apps Allows the app to read the Teams No No
are installed in apps that are installed in this chat
this chat. along with the permissions granted to
each app, without a signed-in user.
Permission Display String Description Admin Microsoft
Consent Account
Required supported
7 Note
Currently, these permissions are supported only in the beta version of Microsoft Graph.
ChatMessage permissions
Delegated permissions
ChatMessage.Send Send user Allows an app to send 1:1 and group chat No No
chat messages in Microsoft Teams, on behalf of the
messages signed-in user.
Cloud PC permissions
Delegated permissions
CloudPC.ReadWrite.All Read Allows the app to create, read, update, and delete Cloud Yes No
and PC objects such as Azure network connections,
write provisioning policies, and device images, on behalf of
Cloud the user.
PCs
Application permissions
CloudPC.Read.All Read Allows the app to read Cloud PC objects such as Yes No
Cloud provisioning policies, without a signed-in user.
PCs
CloudPC.ReadWrite.All Read Allows the app to create, read, update, and delete Cloud Yes No
and PC objects such as Azure network connections,
write provisioning policies, and device images, without a
Cloud signed-in user.
PCs
Example usage
Delegated
Application
ConsentRequest.Read.All Read Allows the app to read consent requests and Yes No
consent approvals on behalf of the signed-in user.
requests
ConsentRequest.ReadWrite.All Read and Allows the app to read app consent requests Yes No
write and approvals, and deny or approve those
consent requests on behalf of the signed-in user.
requests
Application permissions
ConsentRequest.Read.All Read consent Allows the app to read app consent requests and Yes
requests approvals without a signed-in user.
ConsentRequest.ReadWrite.All Read and Allows the app to read app consent requests and Yes
write consent approvals, and deny or approve those requests without
requests a signed-in user.
Delegated permissions
Application permissions
Contacts permissions
Delegated permissions
Permission Display Description Admin Microsoft
String Consent Account
Required supported
Contacts.Read Read user Allows the app to read user contacts. No Yes
contacts
Contacts.Read.Shared Read user Allows the app to read contacts that the user No No
and shared has permissions to access, including the user's
contacts own and shared contacts.
Contacts.ReadWrite Have full Allows the app to create, read, update, and No Yes
access to delete user contacts.
user
contacts
Contacts.ReadWrite.Shared Read and Allows the app to create, read, update and No No
write user delete contacts that the user has permissions
and shared to, including the user's own and shared
contacts contacts.
Application permissions
Contacts.Read Read contacts in all Allows the app to read all contacts in all mailboxes Yes
mailboxes without a signed-in user.
Contacts.ReadWrite Read and write Allows the app to create, read, update, and delete all Yes
contacts in all contacts in all mailboxes without a signed-in user.
mailboxes
Important Administrators can configure application access policy to limit app access to specific
mailboxes and not all the mailboxes in the organization, even if the app has been granted the
application permissions of Contacts.Read or Contacts.ReadWrite.
Example usage
Delegated
Contacts.Read: Read a contact from one of the top-level contact folders of the signed-in user ( GET
/me/contactfolders/{Id}/contacts/{id} ).
Contacts.ReadWrite: Update the contact photo of one of the signed-in user's contacts ( PUT
/me/contactfolders/{contactFolderId}/contacts/{id}/photo/$value ).
Contacts.ReadWrite: Add contacts to the root folder of the signed-in user ( POST /me/contacts ).
Application
Contacts.Read: Read contacts from one of the top-level contact folders of any user in the
organization ( GET /users/{id | userPrincipalName}/contactfolders/{Id}/contacts/{id} ).
Contacts.ReadWrite: Update the photo for any contact of any user in an organization ( PUT /users/{id
| userPrincipalName}/contactfolders/{contactFolderId}/contacts/{id}/photo/$value ).
Contacts.ReadWrite: Add contacts to the root folder of any user in the organization ( POST /users/{id
| userPrincipalName}/contacts ).
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
Application permissions
CustomAuthenticationExtension.Read.All Read all custom Allows the app to read your Yes
authentication organization's custom authentication
extensions extensions without a signed-in user.
CustomAuthenticationExtension.ReadWrite.All Read and write Allows the app to read or write your Yes
all custom organization's custom authentication
authentication extensions without a signed-in user.
extensions
Delegated permissions
Application permissions
CustomSecAttributeAssignment.Read.All Read custom Allows the app to read custom security Yes
security attribute assignments for all principals
attribute in the tenant without a signed in user.
assignments
CustomSecAttributeAssignment.ReadWrite.All Read and write Allows the app to read and write Yes
custom security custom security attribute assignments
attribute for all principals in the tenant without a
assignments signed in user.
CustomSecAttributeDefinition.Read.All Read custom Allows the app to read custom security Yes
security attribute definitions for the tenant
attribute without a signed in user.
definitions
CustomSecAttributeDefinition.ReadWrite.All Read and write Allows the app to read and write Yes
custom security custom security attribute definitions for
attribute the tenant without a signed in user.
definitions
DeviceLocalCredential.ReadBasic.All Read basic Allows the app to read device local Yes No
device local credential properties excluding
credential passwords, on behalf of the signed-
information in user.
DeviceLocalCredential.Read.All Read device Allows the app to read device local Yes No
local credential properties including
credential passwords, on behalf of the signed-
information in user.
Application permissions
DeviceLocalCredential.ReadBasic.All Read basic device Allows the app to read device Yes No
local credential local credential properties
information excluding passwords.
DeviceLocalCredential.Read.All Read device local Allows the app to read device Yes No
credential local credential properties
information including passwords.
Example usage
Delegated
DeviceLocalCredential.ReadBasic.All_: List the device local credential for all devices in the tenant
without returning the 'credentials' property ( GET /deviceLocalCredentials ).
DeviceLocalCredential.Read.All_: Get a device local credential with the local administrator account
password in Base64 encoded value ( GET /deviceLocalCredentials/{deviceId}?$select=credentials ).
Application
DeviceLocalCredential.ReadBasic.All_: List the device local credential for all devices in the tenant
without returning the 'credentials' property ( GET /deviceLocalCredentials ).
DeviceLocalCredential.Read.All_: Get a device local credential with the local administrator account
password in Base64 encoded value ( GET /deviceLocalCredentials/{deviceId}?$select=credentials ).
Delegated permissions
Permission Display Description Admin Microsoft
String Consent Account
Required supported
Application permissions
Device permissions
Delegated permissions
Device.Read Read user Allows the app to read a user's list of devices on No Yes
devices behalf of the signed-in user.
Device.Read.All Read all Allows the app to read your organization's devices' Yes Yes
devices configuration information on behalf of the signed-in
user.
Application permissions
Device.Read.All Read all Allows the app to read your organization's devices' configuration Yes
devices information without a signed-in user.
Device.ReadWrite.All Read Allows the app to read and write all device properties without a signed Yes
and in user. Does not allow device creation or update of device alternative
write security identifiers.
devices
7 Note
Before December 3rd, 2020, when the application permission Device.ReadWrite.All was granted, the
Device Managers directory role was also assigned to the app's service principal. This directory role
assignment is not removed automatically when the associated application permissions is revoked. To
ensure that an application's access to read or write to devices is removed, customers must also
remove any related directory roles that were granted to the application.
A service update disabling this behavior began rolling out on December 3rd, 2020. Deployment to all
customers completed on January 11th, 2021. Directory roles are no longer automatically assigned
when application permissions are granted.
Example usage
Application
For more complex scenarios involving multiple permissions, see Permission scenarios.
Directory permissions
Delegated permissions
Directory.Read.All Read Allows the app to read data in your organization's Yes No
directory directory, such as users, groups and apps. Note:
data Users may consent to applications that require this
permission if the application is registered in their
own organization's tenant.
Directory.ReadWrite.All Read Allows the app to read and write data in your Yes No
and organization's directory, such as users, and groups. It
write does not allow the app to delete users or groups, or
directory reset user passwords.
data
Directory.AccessAsUser.All Access Allows the app to have the same access to Yes No
directory information in the directory as the signed-in user.
as the
signed-
in user
Application permissions
Directory.Read.All Read Allows the app to read data in your organization's directory, such Yes
directory as users, groups and apps, without a signed-in user.
data
Directory.ReadWrite.All Read and Allows the app to read and write data in your organization's Yes
write directory, such as users, and groups, without a signed-in user.
directory Does not allow user or group deletion.
data
Remarks
Directory permissions provide the highest level of privilege for accessing directory resources such as user,
group, and device in an organization.
They also exclusively control access to other directory resources like: organizational contacts, schema
extension APIs, Privileged Identity Management (PIM) APIs, as well as many of the resources and APIs
listed under the Azure Active Directory node in the v1.0 and beta API reference documentation. These
include administrative units, directory roles, directory settings, policy, and many more.
7 Note
Before December 3rd, 2020, when the application permission Directory.Read.All was granted, the
Directory Readers directory role was also assigned to the app's service principal. When
Directory.ReadWrite.All was granted, the Directory Writers directory role was also assigned. These
directory roles are not removed automatically when the associated application permissions are
revoked. To remove an application's access to read or write to the directory, customers must also
remove any directory roles that were granted to the application.
A service update disabling this behavior began rolling out on December 3rd, 2020. Deployment to all
customers completed on January 11th, 2021. Directory roles are no longer automatically assigned
when application permissions are granted.
Full read of all directory resources (both declared properties and navigation properties)
Create and update users
Disable and enable users (but not Company Administrator)
Set user alternative security ID (but not administrators)
Create and update groups
Manage group memberships
Update group owner
Manage license assignments
Define schema extensions on applications
Manage directory settings
Manage admin consent workflow configuration (but not whether admin consent is required or who
is authorized to grant admin consent)
Note:
Example usage
Delegated
Application
Directory.Read.All: List all memberships of a user, including directory roles and administrative units
( GET /beta/users/{id}/memberOf )
Directory.Read.All: List all group members, including service principals ( GET
/beta/groups/{id}/members )
Directory.ReadWrite.All: Add an owner to a group ( POST /groups/{id}/owners/$ref )
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
Application permissions
DirectoryRecommendations.ReadWrite.All Manage all Allows the app to read and write Yes
recommendations recommendations without a signed-in
user.
Domain permissions
Delegated permissions
Domain.Read.All Read Allows the app to read all domain properties on behalf Yes No
domains of the signed-in user.
Permission Display Description Admin Microsoft
String Consent Account
Required supported
Domain.ReadWrite.All Read Allows the app to read and write all domain properties Yes No
and on behalf of the signed-in user. Also allows the app to
write add, verify, and remove domains.
domains
Application permissions
Domain.Read.All Read domains Allows the app to read all domain properties Yes
without a signed-in user.
Domain.ReadWrite.All Read and write Allows the app to read and write domains without a Yes
domains signed-in user.
eDiscovery permissions
Delegated permissions
eDiscovery.Read.All Read user Allows the app to read eDiscovery objects such as Yes No
eDiscovery cases, custodians, review sets and other related
case data objects on behalf of the signed-in user.
eDiscovery.ReadWrite.All Read and Allows the app to read and write eDiscovery Yes No
write objects such as cases, custodians, review sets and
eDiscovery other related objects on behalf of the signed-in
case data user.
Application permissions
None
Example usage
Delegated
eDiscovery.Read.All: Get the list of cases available to the user ( GET /compliance/ediscovery/cases )
eDiscovery.ReadWrite.All: Create a reviewset query in a review set ( POST
/compliance/ediscovery/cases/{caseId}/reviewSets/{reviewSetId}/queries )
For more complex scenarios involving multiple permissions, see Permission scenarios.
Education permissions
Delegated permissions
EduAssignments.ReadWriteBasic Read and Allows the app to read and write Yes No
write users' assignments without grades on behalf of
class the user
assignments
without
grades
EduAssignments.Read Read users' Allows the app to read assignments and Yes No
view of class their grades on behalf of the user
assignments
and their
grades
EduAssignments.ReadWrite Read and Allows the app to read and write Yes No
write users' assignments and their grades on behalf of
view of class the user
assignments
and their
grades
EduRoster.Read Read users' Allows the app to read the structure of Yes
view of the schools and classes in an organization's
roster roster and education-specific information
about users to be read on behalf of the
user.
Permission Display Description Admin Microsoft
String Consent Account
Required supported
EduRoster.ReadWrite Read and Allows the app to read and write the Yes
write users' structure of schools and classes in an
view of the organization's roster and education-
roster specific information about users to be
read and written on behalf of the user.
Application permissions
EduAdministration.Read.All Read Education Read the state and settings of all Microsoft Yes
app settings education apps on behalf of the user.
EduAdministration.ReadWrite.All Manage Manage the state and settings of all Microsoft yes
education app education apps on behalf of the user.
settings
EduAssignments.ReadBasic.All Read all class Allows the app to read all class assignments Yes
assignments without grades for all users without a signed-in
without grades user.
EduAssignments.ReadWriteBasic.All Create, read, Allows the app to create, read, update and Yes
update, and delete all class assignments without grades for
delete all class all users without a signed-in user.
assignments
without grades
EduAssignments.Read.All Read all class Allows the app to read all class assignments Yes
assignments with with grades for all users without a signed-in
grades user.
EduAssignments.ReadWrite.All Create, read, Allows the app to create, read, update and Yes
update, and delete all class assignments with grades for all
delete all class users without a signed-in user.
assignments with
grades
EduRoster.ReadBasic.All Read a limited Allows the app to read a limited subset of both Yes
subset of the the structure of schools and classes in an
organization's organization's roster and education-specific
roster. information about all users.
EduRoster.Read.All Read the Allows the app to read the structure of schools Yes
organization's and classes in the organization's roster and
roster. education-specific information about all users
to be read.
EduRoster.ReadWrite.All Read and write Allows the app to read and write the structure Yes
the organization's of schools and classes in the organization's
roster. roster and education-specific information
about all users to be read and written.
Example usage
Delegated
EduAssignments.Read: Get the signed-in student's assignment information ( GET
/education/classes/{id}/assignments/{id} )
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
LearningProvider.Read Read Allows the app to read data for the Yes No
learning learning provider in the organization's
provider directory, on behalf of the signed-in user.
LearningProvider.ReadWrite Manage Allows the app to create, update, read, and Yes No
learning delete data for the learning provider in the
provider organization's directory, on behalf of the
signed-in user.
LearningAssignedCourse.Read Read Allows the app to read data for assignment Yes No
assignment record in organization's directory on behalf
of the signed-in user.
LearningSelfInitiatedCourse.Read Read self- Allows the app to read data for self- Yes No
initiated initiated course record in organization's
course directory on behalf of the signed-in user.
Application permissions
Delegated permissions
EntitlementManagement.ReadWrite.All Read and write Allows the app to request access to read and Yes
entitlement manage access packages and related
management entitlement management resources on behalf
resources of the signed-in user.
EntitlementManagement.ReadWrite.All Read and write Allows the app to read and manage Yes
entitlement access packages and related entitlement
management management resources.
resources
EntitlementManagement.Read.All Read entitlement Allows the app to read access packages Yes
management and related entitlement management
resources resources.
Files permissions
Delegated permissions
Files.Read Read user files Allows the app to read the signed-in user's No Yes
files.
Files.Read.All Read all files Allows the app to read all files the signed-in No Yes
that user can user can access.
access
Files.ReadWrite Have full access Allows the app to read, create, update, and No Yes
to user files delete the signed-in user's files.
Files.ReadWrite.All Have full access Allows the app to read, create, update, and No Yes
to all files user delete all files the signed-in user can access.
can access
Files.ReadWrite.AppFolder Have full access (Preview) Allows the app to read, create, No Yes
to the update, and delete files in the application's
application's folder.
folder (preview)
Files.Read.All Read files in all site Allows the app to read all files in all site collections Yes
collections without a signed in user.
Files.ReadWrite.All Read and write files Allows the app to read, create, update, and delete all Yes
in all site collections files in all site collections without a signed in user.
Remarks
Note: For personal accounts, Files.Read and Files.ReadWrite also grant access to files shared with the
signed-in user.
The Files.Read.Selected and Files.ReadWrite.Selected delegated permissions are only valid on work or
school accounts and are only exposed for working with Office 365 file handlers (v1.0). They should not be
used for directly calling Microsoft Graph APIs.
The Files.ReadWrite.AppFolder delegated permission is only valid for personal accounts and is used for
accessing the App Root special folder with the OneDrive Get special folder Microsoft Graph API.
Example usage
Delegated
Files.Read: Read files stored in the signed-in user's OneDrive ( GET /me/drive/root/children )
Files.Read.All: Read files shared with the signed-in user ( GET /me/drive/root/sharedWithMe )
Files.ReadWrite: Write a file in the signed-in user's OneDrive ( PUT
/me/drive/root/children/filename.txt/content )
Files.ReadWrite.All: Write a file shared with the user ( PUT
/users/[email protected]/drive/root/children/file.txt/content )
For more complex scenarios involving multiple permissions, see Permission scenarios.
Financials permissions
Delegated permissions
Financials.ReadWrite.All Read and write Allows the app to read and write financials data on No
financials data behalf of the signed-in user
Group permissions
Delegated permissions
Group.Read.All Read all Allows the app to list groups, and to Yes No
groups read their properties and all group
memberships on behalf of the signed-
in user. Also allows the app to read
calendar, conversations, files, and
other group content for all groups the
signed-in user can access.
Group.ReadWrite.All Read and Allows the app to create groups and Yes No
write all read all group properties and
groups memberships on behalf of the signed-
in user. Also allows the app to read
and write calendar, conversations,
files, and other group content for all
groups the signed-in user can access.
Additionally allows group owners to
manage their groups and allows
group members to update group
content.
GroupMember.Read.All Read group Allows the app to list groups, read Yes No
memberships basic group properties and read
membership of all groups the signed-
in user has access to.
GroupMember.ReadWrite.All Read and Allows the app to list groups, read Yes No
write group basic properties, read and update the
memberships membership of the groups the
signed-in user has access to. Group
properties and owners cannot be
updated and groups cannot be
deleted.
UnifiedGroupMember.Read.AsGuest Read unified Allows the app to read basic unified Yes No
(Microsoft group properties, memberships, and
365) group owners of the group the signed-in
memberships guest is a member of.
as a guest
user
Application permissions
Group.Read.All Read all Allows the app to read group properties and memberships, Yes
groups and read conversations for all groups, without a signed-in
user.
Group.ReadWrite.All Read and Allows the app to create groups, read all group properties Yes
write all and memberships, update group properties and
groups memberships, and delete groups. Also allows the app to
read and write conversations. All of these operations can
be performed by the app without a signed-in user.
GroupMember.Read.All Read group Allows the app to read memberships and basic group Yes
memberships properties for all groups without a signed-in user.
GroupMember.ReadWrite.All Read and Allows the app to list groups, read basic properties, read Yes
write group and update the membership of the groups without a
memberships signed-in user. Group properties and owners cannot be
updated and groups cannot be deleted.
Group.Create Create Allows the calling app to create groups without a signed-in Yes
groups user. Does not allow read, update, or deletion of any
groups.
Remarks
Group functionality is not supported on personal Microsoft accounts.
For Microsoft 365 groups, Group permissions grant the app access to the contents of the group; for
example, conversations, files, notes, and so on.
For application permissions, there are some limitations for the APIs that are supported. For more
information, see known issues.
In some cases, an app may need Directory permissions to read some group properties like member and
memberOf . For example, if a group has a one or more servicePrincipals as members, the app will need
effective permissions to read service principals through being granted one of the Directory.* permissions,
otherwise Microsoft Graph will return an error. (In the case of delegated permissions, the signed-in user
will also need sufficient privileges in the organization to read service principals.) The same guidance
applies for the memberOf property, which can return administrativeUnits.
Group permissions are used to control access to Microsoft Teams resources and APIs. Personal Microsoft
accounts are not supported.
Group permissions are also used to control access to Microsoft Planner resources and APIs. Only
delegated permissions are supported for Microsoft Planner APIs; application permissions are not
supported. Personal Microsoft accounts are not supported.
Example usage
Delegated
Group.Read.All: Read all Microsoft 365 groups that the signed-in user is a member of ( GET
/me/memberOf/$/microsoft.graph.group?$filter=groupTypes/any(a:a%20eq%20'unified') ).
Group.Read.All: Read all Microsoft 365 group content like conversations ( GET
/groups/{id}/conversations ).
Note:: This also requires User.ReadBasic.All to read the user to add as a member.
Application
Group.Read.All: Find all groups with name that starts with 'Sales' ( GET /groups?
$filter=startswith(displayName,'Sales') ).
Group.ReadWrite.All: Daemon service creates new events on a Microsoft 365 group's calendar ( POST
/groups/{id}/events ).
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
IdentityProvider.Read.All Read identity Allows the app to read identity providers Yes No
provider configured in your Azure AD or Azure AD
information B2C tenant on behalf of the signed-in user.
IdentityProvider.ReadWrite.All Read and Allows the app to read or write identity Yes No
write identity providers configured in your Azure AD or
provider Azure AD B2C tenant on behalf of the
information signed-in user.
Remarks
IdentityProvider.Read.All and IdentityProvider.ReadWrite.All are valid only for work or school accounts. For
an app to read or write identity providers with delegated permissions, the signed-in user must be
assigned the Global Administrator role. For more information about administrator roles, see Assigning
administrator roles in Azure Active Directory.
Example usage
Delegated
The following usages are valid for both delegated permissions:
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
IdentityRiskyServicePrincipal.Read.All Read all Allows the app to read all risky Yes No
risky service principal information for
service your organization, on behalf of
principal the signed-in user.
information
Permission Display Description Admin Microsoft
String Consent Account
Required supported
Application permissions
IdentityRiskEvent.Read.All Read identity Allows the app to read identity risk event Yes
risk event information for all users in your
information organization without a signed-in user.
IdentityRiskyUser.Read.All Read identity Allows the app to read identity user risk Yes
user risk information for all users in your
information organization without a signed-in user.
IdentityRiskyUser.ReadWrite.All Read and Allows the app to read and update Yes
update identity identity user risk information for all users
user risk in your organization without a signed-in
information user.
IdentityRiskyServicePrincipal.Read.All Read all risky Allows the app to read all risky service Yes
service principal principal information for your
information organization, without a signed-in user.
IdentityRiskyServicePrincipal.ReadWrite.All Read and write Allows the app to read and update risky Yes
all risky service service principal for your organization,
principal without a signed-in user.
information
All identity risk permissions are valid only for work or school accounts. For an app with delegated
permissions to read identity risk information, the signed-in user must be a member of one of the
following Azure AD administrator roles: Global Administrator, Security Administrator, or Security Reader.
Example usage
The following usages are valid for both delegated and application permissions:
Read all risky service principals and properties in the tenant ( GET
/identityProtection/riskyServicePrincipals )
Read all risky service principals whose aggregate risk level is Medium ( GET
/identityProtection/riskyServicePrincipals?$filter=riskLevel eq 'medium' )
Read the risk information for a specific service principal ( GET
/identityProtection/riskyServicePrincipals?$filter=id eq '{riskyServicePrincipalsId}' )
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
IdentityUserFlow.Read.All Read all identity user Allows the app to read your Yes No
flows in a tenant organization's user flows.
IdentityUserFlow.ReadWrite.All Read and write all Allows the app to read or Yes No
identity user flows in a write your organization's
tenant. user flows.
Application permissions
IdentityUserFlow.Read.All Read all identity user Allows the app to read your Yes No
flows in a tenant organization's user flows.
IdentityUserFlow.ReadWrite.All Read and write all Allows the app to read or Yes No
identity user flows in a write your organization's
tenant. user flows.
Remarks
IdentityUserFlow.Read.All and IdentityUserFlow.ReadWrite.ALL is valid only for work or school accounts.
For an app with delegated permissions to read user flows, the signed-in user must be a member of one of
the following administrator roles: Global Administrator, External Identities User Flow Administrator, or
Global Reader. For an app with delegated permissions to write user flows, the signed-in user must be a
member of one of the following administrator roles: Global Administrator or External Identities User Flow
Administrator.
For more information about administrator roles, see Assigning administrator roles in Azure Active
Directory.
Example usage
IdentityUserFlow.Read.All: Read all user flows in an Azure Active Directory (Azure AD) tenant ( GET
beta/identity/b2xUserFlows )
IdentityUserFlow.Read.All: Read all user attribute assignments in an Azure AD B2C user flow ( GET
beta/identity/b2cUserFlows/{id}/userAttributeAssignments )
IdentityUserFlow.ReadWrite.All: Create a new user flow in an Azure AD B2C tenant ( POST
beta/identity/b2cUserFlows )
IdentityUserFlow.ReadWrite.All: Create a new user flow in an Azure Active Directory (Azure AD) tenant
( POST beta/identity/b2xUserflows )
IdentitytUserFlow.ReadWrite.All: Add an identity provider to an Azure AD B2C user flow ( PATCH
beta/identity/b2cUserFlows/{id}/identityProviders/$ref )
IdentityUserFlow.ReadWrite.All: Remove an identity provider from an Azure AD B2C user flow ( DELETE
beta/identity/b2cUserFlows/{id}/identityProviders/{id} )
For more complex scenarios involving multiple permissions, see Permission scenarios.
Incidents permissions
Delegated permissions
SecurityIncident.ReadWrite.All Read and Allows the app to read and write Yes No
write to incidents, on behalf of the signed-in
incidents user.
Application permissions
SecurityIncident.Read.All Read all incidents Allows the app to read all incidents, without a Yes
signed-in user.
SecurityIncident.ReadWrite.All Read and write to Allows the app to read and write to all Yes
all incidents incidents, without a signed-in user.
Remarks
Incidents permissions are valid only on work or school accounts.
Example usage
Delegated
SecurityIncident.Read.All: Read all incidents in an organization that the user is allowed to read ( GET
/security/incidents )
SecurityIncident.ReadWrite.All: Read and write to all incidents in an organization that the user is
allowed to read and write ( GET /security/incidents )
Application
Delegated permissions
IndustryData.ReadBasic.All Read basic industry Allows the app to read basic industry No No
data service and data service and resource information
resource on behalf of the signed-in user.
definitions
IndustryData- Manage data Allows the app to read and write data Yes No
DataConnector.ReadWrite.All connector connectors on behalf of the signed-in
definitions user.
IndustryData- Upload files to a Allows the app to upload data files to Yes No
DataConnector.Upload data connector a data connector on behalf of the
signed-in user.
IndustryData- View inbound flow Allows the app to read inbound data Yes No
InboundFlow.Read.All definitions flows on behalf of the signed-in user.
IndustryData- Manage inbound Allows the app to read and write Yes No
InboundFlow.ReadWrite.All flow definitions inbound data flows on behalf of the
signed-in user.
IndustryData-Run.Read.All View current and Allows the app to read current and Yes No
previous runs previous industry data runs on behalf
of the signed-in user.
IndustryData- View source system Allows the app to read source system Yes No
SourceSystem.Read.All definitions definitions on behalf of the signed-in
user.
IndustryData- Manage source Allows the app to read and write Yes No
SourceSystem.ReadWrite.All system definitions source system definitions on behalf of
the signed-in user.
IndustryData- Read time period Allows the app to read time period Yes No
TimePeriod.Read.All definitions definitions on behalf of the signed-in
user.
IndustryData- Manage time Allows the app to read and write time Yes No
TimePeriod.ReadWrite.All period definitions period definitions on behalf of the
signed-in user.
Application permissions
IndustryData.ReadBasic.All View basic service and Allows the app to read basic service and No
resource information resource information without a signed-in user.
IndustryData- View data connector Allows the app to read data connectors Yes
DataConnector.Read.All definitions without a signed-in user.
IndustryData- Manage data Allows the app to read and write data Yes
DataConnector.ReadWrite.All connector definitions connectors without a signed-in user.
IndustryData- Upload files to a data Allows the app to upload data files to a data Yes
DataConnector.Upload connector connector without a signed-in user.
IndustryData- View inbound flow Allows the app to read inbound data flows Yes
InboundFlow.Read.All definitions without a signed-in user.
IndustryData- Manage inbound flow Allows the app to read and write inbound Yes
InboundFlow.ReadWrite.All definitions data flows without a signed-in user.
IndustryData- View reference Allows the app to read reference definitions Yes
ReferenceDefinition.Read.All definitions without a signed-in user.
IndustryData-Run.Read.All View current and Allows the app to read current and previous Yes
previous runs industry data runs without a signed-in user.
IndustryData- View source system Allows the app to read source system Yes
SourceSystem.Read.All definitions definitions without a signed-in user.
IndustryData- Manage source Allows the app to read and write source Yes
SourceSystem.ReadWrite.All system definitions system definitions without a signed-in user.
IndustryData- Read time period Allows the app to read time period definitions Yes
TimePeriod.Read.All definitions without a signed-in user.
IndustryData- Manage time period Allows the app to read and write time period Yes
TimePeriod.ReadWrite.All definitions definitions without a signed-in user.
Delegated permissions
Application permissions
Permission Display String Description Admin
Consent
Required
InformationProtectionPolicy.Read.All Read all published Allows an app to read published sensitivity Yes
labels and label labels and label policy settings for the entire
policies for an organization or a specific user, without a
organization signed in user.
Delegated permissions
Application permissions
Remarks
Note: Using the Microsoft Graph APIs to configure Intune controls and policies still requires that the
Intune service is correctly licensed by the customer.
Example usage
Delegated
DeviceManagementApps.Read.All: Find all the Windows Store apps published to Intune ( GET
/deviceAppManagement/mobileApps?$filter=isOf('microsoft.graph.windowsStoreApp') ).
Application
DeviceManagementApps.Read.All: Find all the Windows Store apps published to Intune ( GET
/deviceAppManagement/mobileApps?$filter=isOf('microsoft.graph.windowsStoreApp') ).
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
LifecycleWorkflows.Read.All Read all Allows the app to list and read all Yes No
lifecycle workflows, tasks and related lifecycle
workflows workflows resources on behalf of the
resources signed-in user.
Permission Display Description Admin Microsoft
String Consent Account
Required supported
LifecycleWorkflows.ReadWrite.All Read and Allows the app to create, update, list, Yes No
write all read and delete all workflows, tasks and
lifecycle related lifecycle workflows resources on
workflows behalf of the signed-in user.
resources
Application permissions
LifecycleWorkflows.Read.All Read all lifecycle Allows the app to list and read all workflows, tasks Yes
workflows and related lifecycle workflows resources without a
resources signed-in user.
LifecycleWorkflows.ReadWrite.All Read and write Allows the app to create, update, list, read and Yes
all lifecycle delete all workflows, tasks and related lifecycle
workflows workflows resources without a signed-in user.
resources
Mail permissions
Delegated permissions
Mail.Read Read user Allows the app to read email in user mailboxes. No Yes
mail
Mail.ReadBasic Read user Allows the app to read email in the signed-in No No
basic mail user's mailbox, except for body, bodyPreview,
uniqueBody, attachments, extensions, and any
extended properties. Does not include permissions
to search messages.
Mail.ReadWrite Read and Allows the app to create, read, update, and delete No Yes
write email in user mailboxes. Does not include
access to permission to send mail.
user mail
Mail.Read.Shared Read user Allows the app to read mail that the user can No No
and access, including the user's own and shared mail.
shared
mail
Permission Display Description Admin Microsoft
String Consent Account
Required supported
Mail.ReadWrite.Shared Read and Allows the app to create, read, update, and delete No No
write user mail that the user has permission to access,
and including the user's own and shared mail. Does
shared not include permission to send mail.
mail
Mail.Send Send mail Allows the app to send mail as users in the No Yes
as a user organization.
Mail.Send.Shared Send mail Allows the app to send mail as the signed-in user, No No
on behalf including sending on-behalf of others.
of others
MailboxSettings.Read Read user Allows the app to the read user's mailbox settings. No Yes
mailbox Does not include permission to send mail.
settings
MailboxSettings.ReadWrite Read and Allows the app to create, read, update, and delete No Yes
write user user's mailbox settings. Does not include
mailbox permission to directly send mail, but allows the
settings app to create rules that can forward or redirect
messages.
IMAP.AccessAsUser.All Read and Allows the app to read, update, create and delete No Yes
write email in user mailboxes. Does not include
access to permission to send mail.
user mail
via IMAP
POP.AccessAsUser.All Read and Allows the app to read, update, create and delete No Yes
write email in user mailboxes. Does not include
access to permission to send mail.
user mail
via POP
SMTP.Send Send mail Allows the app to send mail as users in the No Yes
as a user organization.
using
SMTP
AUTH
Application permissions
Mail.Read Read mail in Allows the app to read mail in all mailboxes without a signed- Yes
all in user.
mailboxes
Permission Display Description Admin
String Consent
Required
Mail.ReadBasic.All Read all Allows the app to read all users mailboxes except Body, Yes
users basic BodyPreview, UniqueBody, Attachments, ExtendedProperties,
mail and Extensions. Does not include permissions to search
messages.
Mail.ReadWrite Read and Allows the app to create, read, update, and delete mail in all Yes
write mail in mailboxes without a signed-in user. Does not include
all permission to send mail.
mailboxes
Mail.Send Send mail Allows the app to send mail as any user without a signed-in Yes
as any user user.
MailboxSettings.Read Read all Allows the app to read user's mailbox settings without a Yes
user signed-in user. Does not include permission to send mail.
mailbox
settings
MailboxSettings.ReadWrite Read and Allows the app to create, read, update, and delete user's Yes
write all mailbox settings without a signed-in user. Does not include
user permission to send mail.
mailbox
settings
Important Administrators can configure application access policy to limit app access to specific
mailboxes and not to all the mailboxes in the organization, even if the app has been granted the
application permissions of Mail.Read, Mail.ReadWrite, Mail.Send, MailboxSettings.Read, or
MailboxSettings.ReadWrite.
Remarks
Mail.Read.Shared, Mail.ReadWrite.Shared, and Mail.Send.Shared are only valid for work or school accounts.
All other permissions are valid for both Microsoft accounts and work or school accounts.
With the Mail.Send or Mail.Send.Shared permission, an app can send mail and save a copy to the user's
Sent Items folder, even if the app does not use a corresponding Mail.ReadWrite or Mail.ReadWrite.Shared
permission.
Example usage
Delegated
Mail.Read: List messages in the user's inbox, sorted by receivedDateTime ( GET
/me/mailfolders/inbox/messages?$orderby=receivedDateTime DESC ).
Mail.Read.Shared: Find all messages with attachments in a user's inbox that has shared their inbox
with the signed-in user ( GET /users{id | userPrincipalName}/mailfolders/inbox/messages?
$filter=hasAttachments eq true ).
Application
Mail.ReadWrite: Create a new folder in the Inbox named Expense Reports ( POST /users/{id |
userPrincipalName}/mailfolders ).
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
ManagedTenants.Read.All Read all managed Allows the app to read all managed Yes No
tenant specific tenant information on behalf of the
information signed-in user.
ManagedTenants.ReadWrite.All Read and write all Allows the app to read and write all Yes No
managed tenant managed tenant information on
specific information behalf of the signed-in user.
Application permissions
None.
Member permissions
Delegated permissions
Member.Read.Hidden Read hidden Allows the app to read the memberships of hidden Yes No
memberships groups and administrative units on behalf of the
signed-in user, for those hidden groups and
administrative units that the signed-in user has
access to.
Application permissions
Member.Read.Hidden Read all hidden Allows the app to read the memberships of hidden groups Yes
memberships and administrative units without a signed-in user.
Remarks
Member.Read.Hidden is valid only on work or school accounts.
Membership in some Microsoft 365 groups can be hidden. This means that only the members of the
group can view its members. This feature can be used to help comply with regulations that require an
organization to hide group membership from outsiders (for example, a Microsoft 365 group that
represents students enrolled in a class).
Example usage
Delegated
Application
Member.Read.Hidden: Read the members of an administrative unit with hidden membership ( GET
/administrativeUnits/{id}/members ).
For more complex scenarios involving multiple permissions, see Permission scenarios.
Notes permissions
Delegated permissions
Notes.Read Read user Allows the app to read the titles of No Yes
OneNote OneNote notebooks and sections and
notebooks to create new pages, notebooks, and
sections on behalf of the signed-in user.
Permission Display String Description Admin Microsoft
Consent Account
Required supported
Notes.Create Create user Allows the app to read the titles of No Yes
OneNote OneNote notebooks and sections and
notebooks to create new pages, notebooks, and
sections on behalf of the signed-in user.
Notes.ReadWrite Read and write Allows the app to read, share, and No Yes
user OneNote modify OneNote notebooks on behalf
notebooks of the signed-in user.
Notes.ReadWrite.All Read and write Allows the app to read, share, and No No
all OneNote modify OneNote notebooks that the
notebooks that signed-in user has access to in the
user can access organization.
Application permissions
Notes.Read.All Read all OneNote Allows the app to read all the OneNote notebooks in your Yes
notebooks organization, without a signed-in user.
Notes.ReadWrite.All Read and write all Allows the app to read, share, and modify all the OneNote Yes
OneNote notebooks in your organization, without a signed-in user.
notebooks
Remarks
Notes.Read.All and Notes.ReadWrite.All are only valid for work or school accounts. All other permissions
are valid for both Microsoft accounts and work or school accounts.
With the Notes.Create permission, an app can view the OneNote notebook hierarchy of the signed-in user
and create OneNote content (notebooks, section groups, sections, pages, and so on).
Notes.ReadWrite and Notes.ReadWrite.All also allow the app to modify the permissions on the OneNote
content that can be accessed by the signed-in user.
For work or school accounts, Notes.Read.All and Notes.ReadWrite.All allow the app to access other users'
OneNote content that the signed-in user has permission to within the organization.
Example usage
Delegated
Notes.Create: Create a new notebooks for the signed-in user ( POST /me/onenote/notebooks ).
Notes.Read: Read the notebooks for the signed-in user ( GET /me/onenote/notebooks ).
Notes.Read.All: Get all notebooks that the signed-in user has access to within the organization ( GET
/me/onenote/notebooks?includesharednotebooks=true ).
Application
For more complex scenarios involving multiple permissions, see Permission scenarios.
Notifications permissions
Delegated permissions
Notifications.ReadWrite.CreatedByApp Deliver and Allow the app to deliver its notifications on behalf No
manage of signed-in users. Also allows the app to read,
notifications update, and delete the user's notification items
for this app. for this app.
Remarks
Notifications.ReadWrite.CreatedByApp is valid for both Microsoft accounts and work or school accounts.
The CreatedByApp constraint associated with this permission indicates that the service will apply implicit
filtering to results based on the identity of the calling app, either the Microsoft account app ID or a set of
app IDs configured for a cross-platform application identity.
Example usage
Delegated
Delegated permissions
OnlineMeetingTranscript.Read.All Read all Allows the app to read all transcripts Yes No
transcripts of of online meetings on behalf of the
online signed-in user.
meetings.
Application permissions
OnlineMeetings.Read.All Read Online Allows the app to read Online Meeting Yes
Meeting details details in your organization without a signed-
from the app in user.
OnlineMeetingArtifact.Read.All Read Online Allows the app to read Online Meeting Yes
Meeting artifacts artifacts in your organization, without a
from the app signed-in user.
OnlineMeetingTranscript.Read.All Read all transcripts Allows the app to read all transcripts of all Yes
of online meetings. online meetings, without a signed-in user.
Important Administrators can configure application access policy to allow apps to access online
meetings on behalf of a user.
Example usage
Delegated
OnlineMeetings.Read: Retrieve the properties and relationships of an online meeting ( GET
/beta/communications/onlinemeetings/{default id} ).
Application
OnlineMeetings.Read.All
Retrieve the properties and relationships of an online meeting ( GET
/beta/communications/onlinemeetings/?$filter=VideoTeleconferenceId%20eq%20'{id}' ).
Retrieve an online meeting on behalf of a user (`GET /beta/users/{userId}/onlineMeetings/{id})
OnlineMeetings.ReadWrite.All
Create an online meeting on behalf of a user (`POST /beta/users/{userId}/onlineMeetings/)
Update an online meeting on behalf of a user (`PATCH /beta/users/{userId}/onlineMeetings/{id})
Delete an online meeting on behalf of a user (`DELETE /beta/users/{userId}/onlineMeetings/{id})
Note: Creating an online meeting creates a meeting on behalf of a user, but does not show it on the
user's Calendar.
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
Application permissions
None.
On-premises publishing profiles permissions
Delegated permissions
Application permissions
email View Allows the app to read your users' primary email address. No Yes
users'
email
address
offline_access Access Allows the app to read and update user data, even when they are No Yes
user's not currently using the app.
data
anytime
openid Sign By using this permission, an app can receive a unique identifier No Yes
users in for the user in the form of the sub claim. The permission also
gives the app access to the UserInfo endpoint. The openid scope
can be used at the Microsoft identity platform token endpoint to
acquire ID tokens. The app can use these tokens for
authentication.
Permission Display Description Admin Microsoft
String Consent Account
Required supported
profile View Allows the app to see your users' basic profile (name, picture, No Yes
users' user name).
basic
profile
Remarks
You can use these scopes to specify artifacts that you want returned in Azure AD authorization and token
requests. They are supported differently by the Azure AD v1.0 and v2.0 endpoints.
With the Azure AD v1.0 endpoint, only the openid scope is used. You specify it in the scope parameter in
an authorization request to return an ID token when you use the OpenID Connect protocol to sign in a
user to your app. For more information, see Authorize access to web applications using OpenID Connect
and Azure Active Directory. To successfully return an ID token, you must also make sure that the User.Read
permission is configured when you register your app.
With the Azure AD v2.0 endpoint, you specify the offline_access scope in the scope parameter to explicitly
request a refresh token when using the OAuth 2.0 or OpenID Connect protocols. With OpenID Connect,
you specify the openid scope to request an ID token. You can also specify the email scope, profile scope,
or both to return additional claims in the ID token. You do not need to specify the User.Read permission to
return an ID token with the v2.0 endpoint. For more information, see OpenID Connect scopes.
) Important
The Microsoft Authentication Library (MSAL) currently specifies offline_access, openid, profile, and
email by default in authorization and token requests. This means that, for the default case, if you
specify these scopes explicitly, Azure AD may return an error.
Organization permissions
Delegated permissions
Organization.Read.All Read Allows the app to read the organization and Yes No
organization related resources, on behalf of the signed-in
information user. Related resources include things like
subscribed SKUs and tenant branding
information.
Permission Display Description Admin Microsoft
String Consent Account
Required supported
Organization.ReadWrite.All Read and Allows the app to read and write the Yes No
write organization and related resources, on behalf
organization of the signed-in user. Related resources include
information things like subscribed SKUs and tenant
branding information.
Application permissions
Organization.Read.All Read Allows the app to read the organization and related Yes
organization resources, without a signed-in user. Related resources
information include things like subscribed SKUs and tenant branding
information.
Organization.ReadWrite.All Read and Allows the app to read and write the organization and Yes
write related resources, without a signed-in user. Related resources
organization include things like subscribed SKUs and tenant branding
information information.
Example usage
Delegated
Application
Organization.ReadWrite.All: Update organization information (such as technicalNotificationMails)
( PATCH /organization/{id} ).
Delegated permissions
OrgContact.Read.All Read Allows the app to read all organizational contacts on Yes No
organizational behalf of the signed-in user. These contacts are
contacts managed by the organization and are different from
a user's personal contacts.
Application permissions
OrgContact.Read.All Read Allows the app to read all organizational contacts without a Yes
organizational signed-in user. These contacts are managed by the organization
contacts and are different from a user's personal contacts.
Example usage
Delegated
People permissions
Delegated permissions
People.Read Read Allows the app to read a scored list of people relevant to the No Yes
users' signed-in user. The list can include local contacts, contacts from
relevant social networking or your organization's directory, and people
people from recent communications (such as email and Skype).
lists
People.Read.All Read all Allows the app to read a scored list of people relevant to the Yes No
users' signed-in user or other users in the signed-in user's
relevant organization. The list can include local contacts, contacts from
people social networking or your organization's directory, and people
lists from recent communications (such as email and Skype). Also
allows the app to search the entire directory of the signed-in
user's organization.
Application permissions
Permission Display Description Admin
String Consent
Required
People.Read.All Read all Allows the app to read a scored list of people relevant to the signed-in user Yes
users' or other users in the signed-in user's organization.
relevant
people The list can include local contacts, contacts from social networking or your
lists organization's directory, and people from recent communications (such as
email and Skype). Also allows the app to search the entire directory of the
signed-in user's organization.
Remarks
The People.Read.All permission is only valid for work and school accounts.
Example usage
Delegated
People.Read: Read a list of relevant people ( GET /me/people )
People.Read.All: Read a list of relevant people to another user in the same organization ( GET
/users('{id})/people )
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
Application permissions
Places permissions
Delegated permissions
Place.Read.All Read all Allows the app to read company places (conference Yes No
company rooms and room lists) set up in Exchange Online for
places the tenant.
Place.ReadWrite.All Read and Allows the app to read and write company places Yes No
write all (conference rooms and room lists) set up in
company Exchange Online for the tenant.
places
Application permissions
Place.Read.All Read all Allows the app to read company places (conference rooms and Yes
company room lists) for calendar events and other applications.
places
Policy permissions
Delegated permissions
Application permissions
Policy.Read.All Read your Allows the app to read all your Yes
organization's organization's policies without a signed in
policies user.
Permission Display Description Admin
String Consent
Required
Policy.Read.PermissionGrant Read consent Allows the app to read policies related to Yes
and consent and permission grants for
permission applications, without a signed-in user.
grant policies
Policy.Read.ApplicationConfiguration Read your Allows the app to read all your Yes
organization's organization's application configuration
application policies without a signed in user.
configuration
policies
Policy.ReadWrite.AccessReview Read and Allows the app to read and write your Yes
write your organization's access review policy, without
organization's a signed-in user.
access review
policy
Policy.ReadWrite.ApplicationConfiguration Read and Allows the app to read and write your Yes
write your organization's application configuration
organization's policies, without a signed-in user.
application
configuration
policies
Policy.ReadWrite.AuthenticationFlows Read and Allows the app to read and write the Yes
write your authentication flow policies for the tenant,
organization's without a signed in user.
authentication
flow policies
Policy.ReadWrite.Authorization Read and Allows the app to read and write your Yes
write your organization's authorization policy on behalf
organization's of the signed-in user. For example,
authorization authorization policies can control some of
policy the permissions that the out-of-the-box user
role has by default.
Policy.ReadWrite.ConsentRequest Read and Allows the app to read and write your Yes
write your organization's consent requests policy
organization's without a signed-in user.
consent
requests
policy
Policy.ReadWrite.CrossTenantAccess Read and Allows the app to read and write your Yes
write your organization's cross-tenant access policy
organization's without a signed-in user.
cross-tenant
access policy
Policy.ReadWrite.AuthenticationMethod Read and Allows the app to read and write all Yes
write all authentication method policies for the
authentication tenant, without a signed-in user.
method
policies
Permission Display Description Admin
String Consent
Required
Policy.ReadWrite.FeatureRollout Read and Allows the app to read and write feature Yes
write feature rollout policies without a signed-in user.
rollout Includes abilities to assign and remove users
policies and groups to rollout of a specific feature.
Policy.ReadWrite.TrustFramework Read and Allows the app to read and write your Yes
write your organization's trust framework policies
organization's without a signed in user.
trust
framework
policies
Example usage
The following usages are valid for both delegated and application permissions:
Policy.ReadWrite.TrustFramework: Read and write your organization's trust framework policies ( POST
/beta/trustFramework/policies )
For more complex scenarios involving multiple permissions, see Permission scenarios.
Presence permissions
Delegated permissions
Presence.Read Read user's Allows the app to read presence information on behalf of the No
presence signed-in user. Presence information includes activity, availability,
information status note, calendar out-of-office message, timezone and
location.
Presence.Read.All Read presence Allows the app to read presence information of all users in the No
information of directory on behalf of the signed-in user. Presence information
all users in your includes activity, availability, status note, calendar out-of-office
organization message, timezone and location.
Presence.ReadWrite Read and write Allows the app to read the presence information and write Yes
a user's activity and availability on behalf of the signed-in user. Presence
presence information includes activity, availability, status note, calendar
information out-of-office message, timezone and location.
Application permissions
Presence.ReadWrite.All Read and Allows the app to read all presence information and write activity Yes
write and availability of all users in the directory without a signed-in
presence user. Presence information includes activity, availability, status
information note, calendar out-of-office message, timezone and location.
for all users
Example usage
Presence.Read: If you're signed in, retrieve your own presence information ( GET /me/presence )
Presence.Read.All: Retrieve the presence information of another user ( GET /users/{id}/presence )
Presence.Read.All: Retrieve the presence information of multiple users ( POST
/communications/getPresencesByUserId )
Presence.ReadWrite:
If you're signed in, set the state of your presence session ( POST /me/presence/setPresence )
If you're signed in, set your own preferred presence ( POST
/me/presence/setUserPreferredPresence )
Presence.ReadWrite.All:
Set the state of a user's presence session as an application ( POST
/users/{id}/presence/setPresence )
Delegated permissions
Application permissions
ProgramControl.Read.All Read all Allows the app to read programs without a Yes
programs signed-in user.
ProgramControl.ReadWrite.All Manage all Allows the app to read and write programs Yes
programs without a signed-in user.
Remarks
ProgramControl.Read.All and ProgramControl.ReadWrite.All are valid only for work or school accounts.
For an app with delegated permissions to read programs and program controls, the signed-in user must
be a member of one of the following administrator roles: Global Administrator, Security Administrator,
Security Reader or User Administrator. For an app with delegated permissions to write programs and
program controls, the signed-in user must be a member of one of the following administrator roles:
Global Administrator or User Administrator. For more information about administrator roles, see
Assigning administrator roles in Azure Active Directory.
Delegated permissions
RecordsManagement.Read.All Read Records Allows the application to read any data from Yes
Management Records Management, such as configuration,
configuration, labels, and policies on behalf of the signed-in
labels, and policies user.
Permission Display String Description Admin
Consent
Required
RecordsManagement.ReadWrite.All Read and write Allow the application to create, update and Yes
Records delete any data from Records Management,
Management such as configuration, labels, and policies on
configuration, behalf of the signed-in user.
labels, and policies
Application permissions
RecordsManagement.Read.All Read Records Allows the application to read any data from Yes
Management Records Management, such as configuration,
configuration, labels labels, and policies without the signed in user.
and policies
RecordsManagement.ReadWrite.All Read and write Allow the application to create, update and Yes
Records delete any data from Records Management,
Management such as configuration, labels, and policies
configuration, labels without the signed in user.
and policies
Example usage
Delegated
RecordsManagement.Read.All: Get the list of labels available to the user from Microsoft Purview
Records maangement ( GET /security/labels/retentionLabels )
RecordsManagement.ReadWrite.All: Create a label in Microsoft Purview Records managment ( POST
/security/labels/retentionLabels/ )
For more complex scenarios involving multiple permissions, see Permission scenarios.
Reports permissions
Delegated permissions
Reports.Read.All Read all Allows an app to read all service usage reports on behalf of the Yes No
usage signed-in user. Services that provide usage reports include
reports Microsoft 365 and Azure Active Directory.
Application permissions
Reports.Read.All Read all Allows an app to read all service usage reports without a signed-in user. Yes
usage Services that provide usage reports include Microsoft 365 and Azure
reports Active Directory.
Remarks
Reports permissions are only valid for work or school accounts.
For delegated permissions to allow apps to read service usage reports on behalf of a user, the tenant
administrator must have assigned the user an Azure AD limited administrator role. For more details,
see Authorization for APIs to read Microsoft 365 usage reports.
Example usage
Application
Reports.Read.All: Read usage detail report of email apps with period of 7 days ( GET
/reports/EmailAppUsage(view='Detail',period='D7')/content ).
Reports.Read.All: Read activity detail report of email with date of '2017-01-01' ( GET
/reports/EmailActivity(view='Detail',data='2017-01-01')/content ).
Reports.Read.All: Read Microsoft 365 activations detail report ( GET
/reports/Office365Activations(view='Detail')/content ).
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
Application permissions
RoleManagement.Read.All Read role Allows the app to read the role-based access Yes
management control (RBAC) settings for all supported RBAC
data for all providers, without a signed-in user. This includes
RBAC reading role definitions and role assignments.
providers.
RoleManagement.Read.Directory Read role Allows the app to read the role-based access Yes
management control (RBAC) settings for your company's
data for directory, without a signed-in user. This includes
Azure AD. reading directory role templates, directory roles
and memberships.
RoleManagement.ReadWrite.Directory Read and Allows the app to read and manage the role- Yes
write role based access control (RBAC) settings for your
management company's directory, without a signed-in user.
data for This includes instantiating directory roles and
Azure AD. managing directory role membership, and
reading directory role templates, directory roles
and memberships.
Remarks
U Caution
Role management permissions are only valid for work or school accounts.
Example usage
RoleManagement.Read.Directory: Read the list of available role templates ( GET
/directoryRoleTemplates )
RoleManagement.Read.Directory: Read the list of administrative unit-scoped members for a role ( GET
/directoryRoles/<id>/scopedMembers )
RoleManagement.ReadWrite.Directory: Activate a directory role from a role template ( POST
/directoryRoles )
RoleManagement.ReadWrite.Directory: Add a member to a directory role ( POST
/directoryRoles/<id>/members )
For more complex scenarios involving multiple permissions, see Permission scenarios.
Application permissions
Schedule.ReadWrite.All Read and Allows an app to read and write schedule, Yes No
(private preview) Write Shifts schedule groups, shifts, and associated entities in
service shifts applications without a signed-in user.
(Teams) data
Schedule.Read.All Read Shifts Allows the app to read schedule, schedule Yes No
(private preview) service groups, shifts, and associated entities in shifts
(Teams) data applications without a signed-in user.
Delegated permissions
Permission Display Description Admin Microsoft
String Consent Account
Required supported
Search permissions
Application permissions
ExternalConnection.Read.All Read all Allows the app to read all external Yes No
external connections without a signed-in
connections user.
ExternalConnection.ReadWrite.All Read and Allows the app to read and write Yes No
write all all external connections without a
external signed-in user.
connections
ExternalConnection.ReadWrite.OwnedBy Read and Allows the app to read and write Yes No
write external connections and their
external settings without a signed-in user.
connections The app can only read and write
and external connections that it is
connection authorized to, or it can create new
settings external connections.
ExternalItem.Read.All Read all Allows the app to read all external Yes No
external items without a signed-in user.
items
Permission Display Description Admin Microsoft
String Consent Account
Required supported
ExternalItem.ReadWrite.All Read and Allows the app to read and write Yes No
write all all external items without a signed-
external in user.
items
ExternalItem.ReadWrite.OwnedBy Read and Allows the app to read and write Yes No
write external items without a signed-in
external user. The app can only read
items external items of the connection
that it is authorized to.
Delegated permissions
ExternalConnection.Read.All Read all Allows the app to read all external Yes No
external connections on behalf of a signed-
connections in user.
ExternalConnection.ReadWrite.All Read and Allows the app to read and write Yes No
write all all external connections on behalf
external of a signed-in user.
connections
ExternalConnection.ReadWrite.OwnedBy Read and Allows the app to read and write Yes No
write external connections on behalf of a
external signed-in user. The app can only
connections read and write external
connections that it is authorized to,
or it can create new external
connections.
ExternalItem.ReadWrite.All Read and Allows the app to read and write Yes No
write all all external items on behalf of a
external signed-in user.
items
Permission Display Description Admin Microsoft
String Consent Account
Required supported
ExternalItem.ReadWrite.OwnedBy Read and Allows the app to read and write Yes No
write external items on behalf of a
external signed-in user. The app can only
items read external items of the
connection that it is authorized to.
Remarks
Search permissions are only valid for work or school accounts.
This search permission is only applicable to ingested data from the indexing API.
Access to data via search requires the read permission to the item. Ex : Files.Read.All to access files via
search.
Example usage
Delegated
ExternalItem.Read.All : Access external data from the search API ( POST /search/query ).
Delegated permissions
SearchConfiguration.ReadWrite.All Read and write your Allows the app to read and write Yes No
organization's search configurations, on behalf
search of the signed-in user.
configuration.
Application permissions
SearchConfiguration.Read.All Read your organization's Allows the app to read search Yes
search configuration. configurations without a signed-in
user.
SearchConfiguration.ReadWrite.All Read and write your Allows the app to read and write Yes
organization's search search configurations without a
configuration. signed-in user.
Remarks
Search configuration permissions are only valid for work or school accounts.
Example usage
SearchConfiguration.ReadWrite.All: Update or read all bookmarks created for your tenant ( PATCH
/beta/search/bookmarks/{id} )
Security permissions
Delegated permissions
AttackSimulation.ReadWrite.All Read, create, Allows the app to read, create, and Yes No
and update update attack simulation and
attack training data for an organization for
simulation the signed-in user.
data of an
organization
SecurityAlert.ReadWrite.All Read and Allows the app to read and write Yes No
write to alerts alerts, on behalf of the signed-in
user.
SecurityIncident.ReadWrite.All Read and Allows the app to read and write Yes No
write to incidents, on behalf of the signed-in
incidents user.
ThreatIndicators.Read.All Read your Allows the app to read all the threat Yes No
organization's indicators for your organization, on
threat behalf of the signed-in user.
indicators
Application permissions
AttackSimulation.Read.All Read attack Allows the app to read attack simulation and Yes
simulation data training data for an organization without a
of an signed-in user.
organization
AttackSimulation.ReadWrite.All Read, create, Allows the app to read, create, and update Yes
and update all attack simulation and training data for an
attack organization without a signed-in user.
simulation data
of an
organization
SecurityActions.Read.All Read and write Allows the app to create other applications, Yes
your and fully manage those applications (read,
organization's update, update application secrets and delete),
security events without a signed-in user.
SecurityActions.ReadWrite.All Create and read Allows the app to read or create security Yes
your actions, without a signed-in user.
organization's
security actions
SecurityAlert.Read.All Read all alerts Allows the app to read all alerts, without a Yes
signed-in user.
SecurityAlert.ReadWrite.All Read and write Allows the app to read and write to all alerts, Yes
to all alerts without a signed-in user.
SecurityEvents.Read.All Read your Allows the app to read your organization's Yes
organization's security events.
security events
SecurityEvents.ReadWrite.All Read and Allows the app to read your organization's Yes
update your security events. Also allows the app to update
organization's editable properties in security events.
security events
SecurityIncident.Read.All Read all Allows the app to read all incidents, without a Yes
incidents signed-in user.
SecurityIncident.ReadWrite.All Read and write Allows the app to read and write to all Yes
to all incidents incidents, without a signed-in user.
ThreatIndicators.ReadWrite.OwnedBy Manage threat Allows the app to create threat indicators, and Yes
indicators this fully manage those threat indicators (read,
app creates or update and delete), without a signed-in user. It
owns cannot update any threat indicators it does not
own.
ThreatIndicators.Read.All Manage threat Allows the app to read all the threat indicators Yes
indicators this for your organization, without a signed-in user.
app creates or
owns
Permission Display String Description Admin
Consent
Required
ThreatIndicators.ReadWrite.OwnedBy Manage threat Allows the app to create threat indicators, and Yes
indicators this fully manage those threat indicators (read,
app creates or update and delete), without a signed-in user. It
owns cannot update any threat indicators it does not
own.
Remarks
Security permissions are valid only on work or school accounts.
Example usage
Delegated
SecurityAlert.Read.All: Read all alerts in an organization that the user is allowed to read ( GET
/security/alerts_v2 ).
SecurityAlert.ReadWrite.All: Read and write to all alerts in an organization that the user is allowed to
read and write ( GET /security/alerts_v2 ).
SecurityEvents.Read.All: Read the list of all security alerts from all licensed security providers available
in an organization ( GET /beta/security/alerts ).
SecurityEvents.ReadWrite.All: Update or read security alerts from all licensed security providers
available in an organization ( PATCH /beta/security/alerts/{id} ).
Application
SecurityAlert.Read.All: Read all alerts in an organization ( GET /security/alerts_v2 ).
SecurityAlert.ReadWrite.All: Read and write to all alerts in an organization ( GET /security/alerts ).
SecurityEvents.Read.All: Read the list of all security alerts from all licensed security providers available
in an organization ( GET /beta/security/alerts ).
SecurityEvents.ReadWrite.All: Update or read security alerts from all licensed security providers
available in an organization ( PATCH /beta/security/alerts/{id} ).
Delegated permissions
ServiceHealth.Read.All Read service Allows the app to read your tenant's Yes Yes
health service health information on behalf of
the signed-in user. Health information
may include service issues or service
health overviews.
ServiceMessage.Read.All Read service Allows the app to read your tenant's Yes Yes
messages service announcement messages on
behalf of the signed-in user. Messages
may include information about new or
changed features.
ServiceMessageViewpoint.Write Update your Allows the app to update service Yes Yes
user status on announcement messages' user status on
service behalf of the signed-in user. The
announcement message status can be marked as read,
messages archive, or favorite.
Application permissions
ServiceHealth.Read.All Read Allows the app to read your tenant's service health information, Yes
service without a signed-in user. Health information may include service
health issues or service health overviews.
ServiceMessage.Read.All Read Allows the app to read your tenant's service announcement Yes
service messages, without a signed-in user. Messages may include
messages information about new or changed features.
Delegated permissions
ShortNotes.Read Read short notes of the Allows the app to read all the No Yes
signed-in user short notes a sign-in user has
access to.
ShortNotes.ReadWrite Read, create, edit, and Allows the app to read, create, No Yes
delete short notes of the edit, and delete short notes of a
signed-in user signed-in user.
Application permissions
Permission Display String Description Admin
Consent
Required
ShortNotes.Read.All Read all users' short Allows the app to read all the short notes Yes
notes without a signed-in user.
ShortNotes.ReadWrite.All Read, create, edit, and Allows the app to read, create, edit, and delete Yes
delete all users' short all the short notes without a signed-in user.
notes
Sites permissions
Delegated permissions
Sites.Read.All Read items in all site Allows the app to read documents and list No No
collections items in all site collections on behalf of the
signed-in user.
Sites.ReadWrite.All Read and write items Allows the app to edit or delete documents No No
in all site collections and list items in all site collections on behalf
of the signed-in user.
Sites.Manage.All Create, edit, and Allows the app to manage and create lists, No No
delete items and lists documents, and list items in all site collections
in all site collections on behalf of the signed-in user.
Sites.FullControl.All Have full control of Allows the app to have full control to Yes No
all site collections SharePoint sites in all site collections on
behalf of the signed-in user.
Application permissions
Sites.Read.All Read items in all Allows the app to read documents and list items in all site Yes
site collections collections without a signed in user.
Sites.ReadWrite.All Read and write Allows the app to create, read, update, and delete documents Yes
items in all site and list items in all site collections without a signed in user.
collections
Sites.Manage.All Create, edit, and Allows the app to manage and create lists, documents, and list Yes
delete items and items in all site collections without a signed-in user.
lists in all site
collections
Sites.FullControl.All Have full control of Allows the app to have full control to SharePoint sites in all Yes
all site collections site collections without a signed-in user.
Permission Display String Description Admin
Consent
Required
Sites.Selected Access selected Allow the application to access a subset of site collections Yes
site collections without a signed in user. The specific site collections and the
permissions granted will be configured in SharePoint Online.
Remarks
Sites permissions are valid only on work or school accounts. The Sites.Selected application permission is
available only in the Microsoft Graph API.
Example usage
Delegated
Sites.Read.All: Read the lists on the SharePoint root site ( GET /v1.0/sites/root/lists )
Sites.ReadWrite.All: Create new list items in a SharePoint list ( POST
/v1.0/sites/root/lists/123/items )
Synchronization permissions
Delegated permissions
Synchronization.Read.All Read all Azure Allows the app to read synchronization Yes No
AD data on behalf of the signed-in user.
synchronization
data
Synchronization.ReadWrite.All Read and write Allows the app to read and write synchronization Yes No
all Azure AD data on behalf of the signed-in user.
synchronization
data
Application permissions
Synchronization.Read.All Read all Azure AD Allows the app to read synchronization Yes
synchronization data data on behalf of the signed-in user.
Synchronization.ReadWrite.All Read and write all Allows the app to read and write synchronization Yes
Azure AD data on behalf of the signed-in user.
synchronization data
Example usage
Delegated
Synchronization.Read.All: Get the list of subject rights request available to the user ( GET
/servicePrincipals/{id}/synchronization/jobs/{jobId}/schema ).
Application
Synchronization.Read.All: Get the list of subject rights request available to the user ( GET
/servicePrincipals/{id}/synchronization/jobs/{jobId}/ ).
Synchronization.ReadWrite.All: Create a subject rights request ( POST
/servicePrincipals/{id}/synchronization/jobs/{jobId}/starta ).
Delegated permissions
SubjectRightsRequest.ReadWrite.All Read Allows the app to read and write subject rights Yes No
and requests on behalf of the signed-in user.
write
subject
rights
requests
Application permissions
None.
Example usage
Delegated
SubjectRightsRequest.Read.All_: Get the list of subject rights request available to the user ( GET
/privacy/subjectrightsrequests ).
SubjectRightsRequest.ReadWrite.All: Create a subject rights request ( POST
/privacy/subjectrightsrequests ).
For more complex scenarios involving multiple permissions, see Permission scenarios.
Tasks permissions
Delegated permissions
Tasks.Read Read user's Allows the app to read the signed-in user's No Yes
tasks and task tasks and task lists, including any shared with
lists the user. Doesn't include permission to create,
delete, or update anything.
Tasks.Read.Shared Read user and Allows the app to read tasks a user has No No
shared tasks permissions to access, including their own and
(preview) shared tasks.
Tasks.ReadWrite Create, read, Allows the app to create, read, update, and No Yes
update, and delete the signed-in user's tasks and task lists,
delete user's including any shared with the user.
tasks and task
lists
Tasks.ReadWrite.Shared Read and write Allows the app to create, read, update, and No No
user and shared delete tasks a user has permissions to,
tasks (preview) including their own and shared tasks.
Application permissions
Tasks.Read.All Read all users' tasks Allows the app to read all users' tasks and task lists in your Yes
and tasklist organization, without a signed-in user.
Tasks.ReadWrite.All Read and write all Allows the app to create, read, update and delete all users' Yes
users' tasks and tasks and task lists in your organization, without a signed-in
tasklists user
Remarks
Tasks permissions are used to control access for To Do tasks, Planner tasks, and Outlook
tasks(deprecated).
Shared permissions are currently only supported for work or school accounts. Even with Shared
permissions, reads and writes may fail if the user who owns the shared content has not granted the
accessing user permissions to modify content within the folder.
Example usage
Delegated
Tasks.Read: Get all Planner tasks assigned to the current user ( GET /me/planner/tasks ).
Tasks.Read.Shared: Access tasks in a folder shared to you by another user in your organization ( Get
/users{id|userPrincipalName}/outlook/taskfolders/{id}/tasks ).
For more complex scenarios involving multiple permissions, see Permission scenarios.
Application
Taxonomy permissions
Delegated permissions
TermStore.Read.All Read term store Allows app to read various terms, Yes No
data sets, and groups in the term store
TermStore.ReadWrite.All Read and write Allows the app to edit or delete Yes No
all term store terms, sets, and groups in the term
data store
Remarks
Taxonomy permissions are valid only on work or school accounts.
Example usage
Delegated
TermStore.Read.All: Read the termstore for the tenant ( GET /termStore )
TermStore.ReadWrite.All: Create new terms in the termStore ( POST /termStore/sets/123/children )
Teams permissions
Delegated permissions
Team.ReadBasic.All Read the names and Read the names and descriptions of No No
descriptions of teams, on behalf of the signed-in user.
teams
Application permissions
Team.ReadBasic.All Get a list of all Get a list of all teams, without a Yes No
teams signed-in user.
Delegated permissions
Application permissions
Permission Display String Description Admin Microsoft
Consent Account
Required supported
Delegated permissions
Application permissions
TeamSettings.ReadWrite.All Read and change Read and change all teams' Yes No
all teams' settings. settings, without a signed-in
user.
Delegated permissions
TeamsActivity.Read Read Allows the app to read the signed-in user's teamwork No No
user's activity feed.
teamwork
activity
feed
Permission Display Description Admin Microsoft
String Consent Account
Required supported
Application permissions
TeamsActivity.Read.All Read all Allows the app to read all users' teamwork activity Yes No
users' feed, without a signed-in user.
teamwork
activity
feed
TeamsActivity.Send Send a Allows the app to create new notifications in users' Yes No
teamwork teamwork activity feeds without a signed in user.
activity to These notifications may not be discoverable or be held
any user or governed by compliance policies.
7 Note
These permissions are deprecated. Use the equivalent TeamsAppInstallation.*.All permissions instead.
Delegated permissions
TeamsApp.Read.All Read all Allows the app to read the Teams apps that are Yes No
(Deprecated) installed installed for the signed-in user, and in all teams the
Teams user is a member of. Does not give the ability to read
apps application-specific settings.
TeamsApp.ReadWrite.All Manage Allows the app to read, install, upgrade, and uninstall Yes No
(Deprecated) all Teams apps, on behalf of the signed-in user and also
Teams for teams the user is a member of. Does not give the
apps ability to read or write application-specific settings.
Application permissions
Permission Display Description Admin Microsoft
String Consent Account
Required supported
TeamsApp.Read.All Read all Allows the app to read the Teams apps that are Yes No
(Deprecated) users' installed for any user, without a signed-in user. Does
installed not give the ability to read application-specific
Teams settings.
apps
TeamsApp.ReadWrite.All Manage Allows the app to read, install, upgrade, and uninstall Yes No
(Deprecated) all users' Teams apps for any user, without a signed-in user.
Teams Does not give the ability to read or write application-
apps specific settings.
Delegated permissions
Application permissions
Delegated permissions
TeamworkAppSettings.ReadWrite.All Read and Allows the app to read and write the Yes No
write Teams Teams app settings on behalf of the
app settings signed-in user.
Application permissions
TeamworkAppSettings.Read.All Read Teams app Allows the app to read the Teams app Yes
settings settings without a signed-in user.
TeamworkAppSettings.ReadWrite.All Read and write Allows the app to read and write the Teams Yes
Teams app app settings without a signed-in user.
settings
Delegated permissions
TeamworkDevice.ReadWrite.All Read and Allows the app to read and write the Yes No
write management data for Teams devices on
Teams behalf of the signed-in user.
devices.
Application permissions
TeamworkDevice.Read.All Read Teams Allows the app to read the management Yes No
devices. data for Teams devices, without a signed-
in user.
TeamworkDevice.ReadWrite.All Read and Allows the app to read and write the Yes No
write Teams management data for Teams devices,
devices. without a signed-in user.
Team member permissions
Delegated permissions
TeamMember.Read.All Read the Read the members of teams, on behalf of the Yes No
members signed-in user.
of teams.
TeamMember.ReadWrite.All Add and Add and remove members from teams, on Yes No
remove behalf of the signed-in user. Also allows
members changing a member's role, for example from
from owner to non-owner.
teams.
Application permissions
TeamMember.Read.All Read the Read the members of all teams, without a Yes No
members of signed-in user.
all teams.
TeamMember.ReadWrite.All Add and Add and remove members from all teams, Yes No
remove without a signed-in user. Also allows changing
members a team member's role, for example from owner
from all to non-owner.
teams.
Application permissions
TeamsAppInstallation.Read.Group See which apps are See which apps are installed in No No
installed in this this team, without a signed-in
team. user.
Delegated permissions
Permission Display String Description Admin Microsoft
Consent Account
Required supported
TeamSettings.ReadWrite.All Read and change Read and change all teams' Yes No
teams' settings. settings, on behalf of the signed-in
user.
Application permissions
Team.ReadBasic.All Get a list of all Get a list of all teams, without a Yes No
teams. signed-in user.
TeamSettings.ReadWrite.All Read and change Read and change all teams' Yes No
all teams' settings settings, without a signed-in
user.
Delegated permissions
TeamsTab.Read.All Read tabs Allows the app to read the Teams apps Yes No
in Microsoft that are installed for the signed-in user,
Teams. and in all teams the user is a member of.
Does not give the ability to read
application-specific settings.
TeamsTab.ReadWrite.All Read and Allows the app to read, install, upgrade, Yes No
write tabs and uninstall Teams apps, on behalf of the
in Microsoft signed-in user and also for teams the user
Teams. is a member of. Does not give the ability
to read or write application-specific
settings.
Permission Display Description Admin Microsoft
String Consent Account
Required supported
TeamsTab.Create Create tabs Allows the app to create tabs in any team Yes No
in Microsoft in Microsoft Teams, on behalf of the
Teams. signed-in user. This does not grant the
ability to read, modify or delete tabs after
they are created, or give access to the
content inside the tabs.
Application permissions
TeamsTab.Read.All Read tabs Read the names and settings of tabs Yes No
in Microsoft inside any team in Microsoft Teams,
Teams. without a signed-in user. This does not
give access to the content inside the
tabs.
TeamsTab.ReadWrite.All Read and Read and write tabs in any team in Yes No
write tabs Microsoft Teams, without a signed-in
in Microsoft user. This does not give access to the
Teams. content inside the tabs.
TeamsTab.Create Create tabs Allows the app to create tabs in any Yes No
in Microsoft team in Microsoft Teams, without a
Teams. signed-in user. This does not grant the
ability to read, modify or delete tabs
after they are created, or give access to
the content inside the tabs.
Permission Display Description Admin Microsoft
String Consent Account
Required supported
Delegated permissions
TeamworkTag.ReadWrite Read and write Allows the app to read and write tags Yes No
tags in Microsoft in Teams, on behalf of the signed-in
Teams. user.
TeamworkTag.Read Read tags in Allows the app to read tags in Teams, Yes No
Microsoft Teams. on behalf of the signed-in user.
Application permissions
TeamworkTag.ReadWrite.All Read and write Allows the app to read and write Yes No
tags in Microsoft tags in Teams without a signed-in
Teams. user.
Delegated permissions
Application permissions
Delegated permissions
Agreement.Read.All Read all terms of use Allows the app to read terms of Yes No
agreements use agreements on behalf of the
signed-in user.
Agreement.ReadWrite.All Read and write all Allows the app to read and write Yes No
terms of use terms of use agreements on
agreements behalf of the signed-in user.
AgreementAcceptance.Read Read user terms of Allows the app to read terms of Yes No
use acceptance use acceptance statuses on behalf
statuses of the signed-in user.
AgreementAcceptance.Read.All Read terms of use Allows the app to read terms of Yes No
acceptance statuses use acceptance statuses on behalf
that user can access of the signed-in user.
Remarks
All the permissions above are valid only for work or school accounts.
For an app to read or write all agreements or agreement acceptances with delegated permissions, the
signed-in user must be assigned the Global Administrator, Conditional Access Administrator or Security
Administrator role. For more information about administrator roles, see Assigning administrator roles in
Azure Active Directory.
Example usage
Delegated
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
Application permissions
ThreatAssessment.Read.All Read threat Allows an app to read your organization's threat Yes
assessment assessment requests, without a signed-in user.
requests
Remarks
Threat assessment permissions are valid only on work or school accounts.
Example usage
Delegated
ThreatAssessment.ReadWrite.All: Read and write threat assessment requests ( POST
/informationProtection/threatAssessmentRequests )
Application
ThreatAssessment.Read.All: Read threat assessment requests ( GET
/informationProtection/threatAssessmentRequests )
Delegated permissions
Application permissions
ThreatHunting.Read.All Run hunting Allows the app to run hunting queries, without a Yes
queries signed-in user.
Remarks
Threat hunting permissions are valid only on work or school accounts.
Example usage
Delegated
ThreatHunting.Read.All: Run hunting query on behalf of the signed in user ( POST
/security/runHuntingQuery )
Application
ThreatHunting.Read.All: Run hunting query ( POST /security/runHuntingQuery )
Threat intelligence permissions
Delegated permissions
ThreatIntelligence.Read.All Read all Allows the app to read threat intelligence Yes No
threat information, such as indicators, observations,
intelligence and articles, on behalf of the signed-in user.
information
Application permissions
ThreatIntelligence.Read.All Read all threat Allows the app to read threat intellgence information, Yes
intelligence such as indicators, observations, and articles, without a
information signed-in user.
Remarks
Threat intelligence permissions are valid only on work or school accounts.
Example usage
Delegated
ThreatIntelligence.Read.All: List threat intelligence articles on behalf of the signed-in user ( GET
/security/threatIntelligence/articles )
Application
Delegated permissions
Printer.ReadWrite.All Read and Allows the application to read and update Yes No
update printers on behalf of the signed-in
printers user. Does not allow creating (registering)
or deleting (unregistering) printers.
PrinterShare.ReadWrite.All Read and Allows the application to read and update Yes No
write printer printer shares on behalf of the signed-in
shares user.
PrintJob.Read.All Read print Allows the application to read the metadata Yes No
jobs and document content of print jobs on
behalf of the signed-in user.
PrintJob.ReadBasic.All Read basic Allows the application to read the metadata Yes No
information of of print jobs on behalf of the signed-in
print jobs user. Does not allow access to print job
document content.
PrintJob.ReadWrite.All Read and Allows the application to read and update Yes No
write print the metadata and document content of
jobs print jobs on behalf of the signed-in user.
PrintJob.ReadWriteBasic.All Read and Allows the application to read and update Yes No
write basic the metadata of print jobs on behalf of the
information of signed-in user. Does not allow access to
print jobs print job document content.
PrintConnector.ReadWrite.All Read and Allows the application to read and write Yes No
write print print connectors on behalf of the signed-in
connectors user.
PrintSettings.Read.All Read tenant- Allows the application to read print settings Yes No
wide print on behalf of the signed-in user.
settings
PrintSettings.ReadWrite.All Read and Allows the application to read and update Yes No
write tenant- print settings on behalf of the signed-in
wide print user.
settings
Application permissions
Printer.ReadWrite.All Read and Allows the application to read and update printers Yes
update without a signed-in user. Does not allow creating
printers (registering) or deleting (unregistering) printers.
PrintJob.Read.All Read print Allows the application to read the metadata and Yes
jobs document content of print jobs without a signed-in
user.
Permission Display Description Admin
String Consent
Required
PrintJob.ReadBasic.All Read basic Allows the application to read the metadata of print Yes
information jobs without a signed-in user. Does not allow access to
for print print job document content.
jobs
PrintJob.ReadWrite.All Read and Allows the application to read and update the metadata Yes
write print and document content of print jobs without a signed-in
jobs user.
PrintJob.ReadWriteBasic.All Read and Allows the application to read and update the metadata Yes
write basic of print jobs without a signed-in user. Does not allow
information access to print job document content.
for print
jobs
PrintTaskDefinition.ReadWrite.All Read, write Allows the application to read and update print task Yes
and update definitions without a signed-in user.
print task
definitions
Remarks
To use the Universal Print service, the user or app's tenant must have an active Universal Print
subscription in addition to the permissions listed earlier.
Some permissions distinguish between print job metadata and payload. Metadata describes the
configuration of a print job (its name and document configuration, such as whether it should be
stapled or printed in color). Payload is the document data itself (the PDF or XPS file to be printed.)
All PrintJob.* permissions also require at least Printer.Read.All (or a more prviliged permission)
because print jobs are stored within printers.
Example usage
Delegated
PrintJob.ReadWrite.All: Create print jobs and upload document data to them ( POST
/print/printers/{id}/jobs )
Application
Printer.Read.All: Get a list of all printers in the tenant ( GET /print/printers )
User permissions
Delegated permissions
User.Read Sign-in and Allows users to sign-in to the app, and No Yes
read user allows the app to read the profile of signed-
profile in users. It also allows the app to read basic
company information of signed-in users.
User.ReadWrite Read and Allows the app to read the signed-in user's No Yes
write access full profile. It also allows the app to update
to user the signed-in user's profile information on
profile their behalf.
User.ReadBasic.All Read all Allows the app to read a basic set of profile No No
users' basic properties of other users in your
profiles organization on behalf of the signed-in user.
This includes display name, first and last
name, email address, open extensions and
photo. Also allows the app to read the full
profile of the signed-in user.
User.Read.All Read all Allows the app to read the full set of profile Yes No
users' full properties, reports, and managers of other
profiles users in your organization, on behalf of the
signed-in user.
User.ReadWrite.All Read and Allows the app to read and write the full set Yes No
write all of profile properties, reports, and managers
users' full of other users in your organization, on
profiles behalf of the signed-in user. Also allows the
app to create and delete users as well as
reset user passwords on behalf of the
signed-in user.
User.Invite.All Invite guest Allows the app to invite guest users to your Yes No
users to the organization, on behalf of the signed-in
organization user.
User.EnableDisableAccount.All Enable and Allows the app to enable and disable users' Yes No
disable user accounts, on behalf of the signed-in user.
accounts
User-LifeCycleInfo.Read.All Read all Allows the app to read the lifecycle Yes No
users' information like employeeLeaveDateTime of
lifecycle users in your organization, on behalf of the
information signed-in user.
User- Read and Allows the app to read and write the Yes No
LifeCycleInfo.ReadWrite.All write all lifecycle information like
users' employeeLeaveDateTime of users in your
lifecycle organization, on behalf of the signed-in
information user.
Application permissions
User.Read.All Read all Allows the app to read the full set of profile properties, Yes
users' full group membership, reports and managers of other users
profiles in your organization, without a signed-in user.
User.ReadWrite.All Read and Allows the app to read and write the full set of profile Yes
write all properties, group membership, reports and managers of
users' full other users in your organization, without a signed-in user.
profiles Also allows the app to create and delete non-
administrative users. Does not allow reset of user
passwords.
User.Invite.All Invite guest Allows the app to invite guest users to your organization, Yes
users to the without a signed-in user.
organization
User.EnableDisableAccount.All Enable and Allows the app to enable and disable users' accounts, Yes
disable user without a signed-in user.
accounts
User.Export.All Export Allows the app to export organizational users' data, Yes
users' data without a signed-in user.
User.ManageIdentities.All Manage all Allows an application to read, update and delete identities Yes
user that are associated with a user's account, without a signed
identities in user. This controls which identities users can sign-in
with.
User-LifeCycleInfo.Read.All Read all Allows the app to read the lifecycle information like Yes
users' employeeLeaveDateTime of users in your organization,
lifecycle without a signed-in user.
information
User- Read and Allows the app to read and write the lifecycle information Yes
LifeCycleInfo.ReadWrite.All write all like employeeLeaveDateTime of users in your
users' organization, without a signed-in user.
lifecycle
information
Remarks
With the User.Read permission, an app can also read the basic company information of the signed-in user
for a work or school account through the organization resource. The following properties are available: id,
displayName, and verifiedDomains.
For work or school accounts, the full profile includes all of the declared properties of the User resource.
On reads, only a limited number of properties are returned by default. To read properties that are not in
the default set, use $select . The default properties are:
displayName
givenName
jobTitle
mail
mobilePhone
officeLocation
preferredLanguage
surname
userPrincipalName
User.ReadWrite and User.Readwrite.All delegated permissions allow the app to update the following profile
properties for work or school accounts:
aboutMe
birthday
hireDate
interests
mobilePhone
mySite
pastProjects
photo
preferredName
responsibilities
schools
skills
With the User.ReadWrite.All application permission, the app can update all of the declared properties of
work or school accounts except for password.
With the User.ReadWrite.All delegated or application permission, updating another user's businessPhones,
mobilePhone or otherMails is only allowed on users who are non-administrators or assigned one of the
following roles: Directory Readers, Guest Inviter, Message Center Reader and Reports Reader. For more
details, see Helpdesk (Password) Administrator in Azure AD available roles.
To read or write direct reports ( directReports ) or the manager ( manager ) of a work or school account, the
app must have either User.Read.All (read only) or User.ReadWrite.All.
The User.ReadBasic.All permission constrains app access to a limited set of properties known as the basic
profile. This is because the full profile might contain sensitive directory information. The basic profile
includes only the following properties:
displayName
givenName
id
mail
photo
securityIdentifier
surname
userPrincipalName
To read the group memberships of a user ( memberOf ), the app must have either Group.Read.All or
Group.ReadWrite.All. However, if the user also has membership in a directoryRole or an administrativeUnit,
the app will need effective permissions to read those resources too, or Microsoft Graph will return an
error. This means the app will also need Directory permissions, and, for delegated permissions, the
signed-in user will also need sufficient privileges in the organization to access directory roles and
administrative units.
Example usage
Delegated
User.Read: Read the full profile for the signed-in user ( GET /me ).
User.ReadWrite: Update the photo of the signed-in user ( PUT /me/photo/$value ).
User.ReadBasic.All: Find all users whose name starts with "David" ( GET /users?
$filter=startswith(displayName,'David') ).
User.Read.All: Read a user's manager ( GET /users/{id | userPrincipalName}/manager ).
Application
User.Read.All: Read all users and relationships through delta query ( GET /beta/users/delta?
$select=displayName,givenName,surname ).
User.ReadWrite.All: Update the photo for any user in the organization ( PUT /users/{id |
userPrincipalName}/photo/$value ).
For more complex scenarios involving multiple permissions, see Permission scenarios.
Delegated permissions
Permission Display String Description Admin Microsoft
Consent Account
Required supported
UserActivity.ReadWrite.CreatedByApp Read and write app Allows the app to read and No Yes
activity to users' report the signed-in user's
activity feed activity in the app.
Application permissions
None.
Remarks
UserActivity.ReadWrite.CreatedByApp is valid for both Microsoft accounts and work or school accounts.
The CreatedByApp constraint associated with this permission indicates the service will apply implicit
filtering to results based on the identity of the calling app, either the MSA app id or a set of app ids
configured for a cross-platform application identity.
Example usage
Delegated
UserActivity.ReadWrite.CreatedByApp: Get a list of recent unique user activities based on associated
history items published in the last day. (GET /me/activities/recent).
UserActivity.ReadWrite.CreatedByApp: Publish or update a user activity which may be resumed by the
user of the application. (PUT /me/activities/%2Farticle%3F12345).
UserActivity.ReadWrite.CreatedByApp: Publish or update a history item for a specified user activity in
order to represent the period of user engagement. (PUT /me/activities/{id}/historyItems/{id}).
UserActivity.ReadWrite.CreatedByApp: Delete a user activity in response to user initiated request or to
remove invalid data. (DELETE /me/activities/{id}).
UserActivity.ReadWrite.CreatedByApp: Delete a history item in response to user initiated request or to
remove invalid data. (DELETE /me/activities/{id}/historyItems/{id}).
Delegated permissions
UserAuthenticationMethod.ReadWrite Manage own Allows the app to read and write Yes No
authentication the signed-in user's
methods authentication methods,
including phone numbers and
Authenticator app settings. This
does not allow the app to see
secret information like the
signed-in user's passwords, or
to sign-in or otherwise use the
signed-in user's authentication
methods.
Application permissions
Permission Display Description Admin
String Consent
Required
Remarks
User authentication method permissions are used to manage authentication methods on users. With
these permissions, a delegated user or application can register new authentication methods on a user,
read the authentication methods the user already has registered, update those authentication methods,
and remove them from the user.
With these permissions, all authentication methods can be read and managed on a user. This includes
methods used for:
Delegated permissions
WindowsUpdates.ReadWrite.All Read and write Allows the app to read and write all Yes No
all Windows Windows update deployment settings
update for the organization on behalf of the
deployment signed-in user.
settings
Application permissions
WindowsUpdates.ReadWrite.All Read and write all Allows the app to read and write all Windows Yes
Windows update update deployment settings for the
deployment settings organization without a signed-in user.
Remarks
All the permissions above are valid only for work or school accounts.
For an app to read or write all Windows update deployment settings with delegated permissions, the
signed-in user must be assigned the Global Administrator, Intune Administrator, or Windows Update
Deployment Administrator role. For more information about administrator roles, see Assigning
administrator roles in Azure Active Directory.
Example usage
Delegated
Application
WindowsUpdates.ReadWrite.All: Create a deployment ( POST
/beta/admin/windows/updates/deployments ).
Permission scenarios
This section shows some common scenarios that target user and group resources in an organization. The
tables show the permissions that an app needs to be able to perform specific operations required by the
scenario. Note that in some cases the ability of the app to perform specific operations will depend on
whether a permission is an application or delegated permission. In the case of delegated permissions, the
app's effective permissions will also depend on the privileges of the signed-in user within the
organization. For more information, see Delegated permissions, Application permissions, and effective
permissions.
App wants to read other users' basic User.ReadBasic.All Read all user's basic profiles
information (only display name and
picture), for example to show in a people
picking experience
App wants to read complete user profile for User.Read Enable sign-in and read user profile
signed in user (see direct reports, and
manager, and so on)
App wants to read complete user profile all User.Read.All Read all user's full profiles
users
App wants to read files, mail and calendar User.Read, Files.Read, Enable sign-in and read user profile, Read
information for the signed in user Mail.Read, users' files, Read user mail, Read user calendars
Calendars.Read
App wants to read the signed-in user's (my) User.Read, Files.Read, Enable sign-in and read user profile, Read
files and files that other users have shared Sites.Read.All users' files, Read items in all site collections
with the signed-in user (me).
App wants to read and write complete user User.ReadWrite Read and write access to user profile
profile for signed in user
App wants to read and write complete user User.ReadWrite.All Read and write all user's full profiles
profile all users
App wants to read and write files, mail and User.ReadWrite, Read and write access to user profile, Read and
calendar information for the signed in user Files.ReadWrite, write access to user profile, Read and write
Mail.ReadWrite, access to user mail, Have full access to user
Calendars.ReadWrite calendars
App wants to submit a data policy User.Export.All Export a user'a personal data.
operation request to export a user's
personal data
App wants to read basic group info (only display name and picture), for Group.Read.All Read all groups
example to show in a group picking experience
App wants to read all content in all Microsoft 365 groups, including files, Group.Read.All Read items in all
conversations. It also needs to show group memberships, be able to site collections,
update group memberships, (if owner). Read all groups
App wants to read and write all content in all Microsoft 365 groups, Group.ReadWrite.All, Read and write all
including files, conversations. It also needs to show group memberships, Sites.ReadWrite.All groups, Edit or
be able to update group memberships, (if owner). delete items in all
site collections
App wants to discover (find) a Microsoft 365 group. It allows the user to Group.ReadWrite.All Read and write all
search for a particular group and choose one from the enumerated list to groups
allow the user to join the group.
App tasks involving Group Required Permission
permissions strings
App wants to create a group through AAD Graph Group.ReadWrite.All Read and write all
groups
This article lists the Azure AD built-in roles you can assign to allow management of
Azure AD resources. For information about how to assign roles, see Assign Azure AD
roles to users. If you are looking for roles to manage Azure resources, see Azure built-in
roles.
All roles
Role Description Template ID
Azure AD Joined Device Local Users assigned to this role are 9f06204d-73c1-4d4c-880a-
Administrator added to the local 6edb90606fd8
administrators group on Azure
AD-joined devices.
B2C IEF Policy Administrator Can create and manage trust 3edaf663-341e-4475-9f94-
framework policies in the 5c398ef6c070
Identity Experience Framework
(IEF).
External ID User Flow Attribute Can create and manage the 0f971eea-41eb-4569-a71e-
Administrator attribute schema available to 57bb8a3eff1e
all user flows.
Application Administrator
Users in this role can create and manage all aspects of enterprise applications,
application registrations, and application proxy settings. Note that users assigned to this
role are not added as owners when creating new application registrations or enterprise
applications.
This role also grants the ability to consent for delegated permissions and application
permissions, with the exception of application permissions for Microsoft Graph.
) Important
This exception means that you can still consent to application permissions for other
apps (for example, non-Microsoft apps or apps that you have registered). You can
still request these permissions as part of the app registration, but granting (that is,
consenting to) these permissions requires a more privileged administrator, such as
Global Administrator.
This role grants the ability to manage application credentials. Users assigned this
role can add credentials to an application, and use those credentials to
impersonate the application’s identity. If the application’s identity has been granted
access to a resource, such as the ability to create or update User or other objects,
then a user assigned to this role could perform those actions while impersonating
the application. This ability to impersonate the application’s identity may be an
elevation of privilege over what the user can do via their role assignments. It is
important to understand that assigning a user to the Application Administrator role
gives them the ability to impersonate an application’s identity.
Actions Description
Application Developer
Users in this role can create application registrations when the "Users can register
applications" setting is set to No. This role also grants permission to consent on one's
own behalf when the "Users can consent to apps accessing company data on their
behalf" setting is set to No. Users assigned to this role are added as owners when
creating new application registrations.
Actions Description
For more information, see Microsoft Defender for Office 365 permissions in the
Microsoft 365 Defender portal and Permissions in the Microsoft Purview compliance
portal.
Actions Description
For more information, see Microsoft Defender for Office 365 permissions in the
Microsoft 365 Defender portal and Permissions in the Microsoft Purview compliance
portal.
Actions Description
By default, Global Administrator and other administrator roles do not have permissions
to read, define, or assign custom security attributes. To work with custom security
attributes, you must be assigned one of the custom security attribute roles.
For more information, see Manage access to custom security attributes in Azure AD.
Actions Description
By default, Global Administrator and other administrator roles do not have permissions
to read, define, or assign custom security attributes. To work with custom security
attributes, you must be assigned one of the custom security attribute roles.
For more information, see Manage access to custom security attributes in Azure AD.
Actions Description
By default, Global Administrator and other administrator roles do not have permissions
to read, define, or assign custom security attributes. To work with custom security
attributes, you must be assigned one of the custom security attribute roles.
For more information, see Manage access to custom security attributes in Azure AD.
Actions Description
By default, Global Administrator and other administrator roles do not have permissions
to read, define, or assign custom security attributes. To work with custom security
attributes, you must be assigned one of the custom security attribute roles.
For more information, see Manage access to custom security attributes in Azure AD.
Actions Description
Authentication Administrator
Assign the Authentication Administrator role to users who need to do the following:
Cannot change the credentials or reset MFA for members and owners of a role-
assignable group.
Cannot manage MFA settings in the legacy MFA management portal or Hardware
OATH tokens. The same functions can be accomplished using the Set-MsolUser
commandlet Azure AD PowerShell module.
The following table compares the capabilities of this role with related roles.
Privileged Yes for Yes for No No No Yes for all Yes for
Authentication all users all users users all
Administrator users
) Important
Users with this role can change credentials for people who may have access to
sensitive or private information or critical configuration inside and outside of Azure
Active Directory. Changing the credentials of a user may mean the ability to assume
that user's identity and permissions. For example:
Actions Description
Cannot update sensitive properties. For more information, see Who can perform
sensitive actions.
Cannot delete or restore users. For more information, see Who can perform
sensitive actions.
Cannot manage MFA settings in the legacy MFA management portal or Hardware
OATH tokens.
The following table compares the capabilities of this role with related roles.
Privileged Yes for Yes for No No No Yes for all Yes for
Authentication all users all users users all
Administrator users
Actions Description
Actions Description
Actions Description
Actions Description
) Important
This is a sensitive role. The keyset administrator role should be carefully audited
and assigned with care during pre-production and production.
Actions Description
) Important
The B2 IEF Policy Administrator is a highly sensitive role which should be assigned
on a very limited basis for organizations in production. Activities by these users
should be closely audited, especially for organizations in production.
Actions Description
Actions Description
Actions Description
This role also grants the ability to consent for delegated permissions and application
permissions, with the exception of application permissions for Microsoft Graph.
) Important
This exception means that you can still consent to application permissions for other
apps (for example, non-Microsoft apps or apps that you have registered). You can
still request these permissions as part of the app registration, but granting (that is,
consenting to) these permissions requires a more privileged administrator, such as
Global Administrator.
This role grants the ability to manage application credentials. Users assigned this
role can add credentials to an application, and use those credentials to
impersonate the application’s identity. If the application’s identity has been granted
access to a resource, such as the ability to create or update User or other objects,
then a user assigned to this role could perform those actions while impersonating
the application. This ability to impersonate the application’s identity may be an
elevation of privilege over what the user can do via their role assignments. It is
important to understand that assigning a user to the Application Administrator role
gives them the ability to impersonate an application’s identity.
Actions Description
Actions Description
In Can do
Microsoft Purview Protect and manage your organization's data across Microsoft 365 services
compliance portal Manage compliance alerts
Microsoft Purview Track, assign, and verify your organization's regulatory compliance
Compliance activities
Manager
This role has the same permissions as the Compliance Administrator role
group in Microsoft 365 Defender portal role-based access control.
Actions Description
In Can do
Microsoft Purview Track, assign, and verify your organization's regulatory compliance activities
Compliance
Manager
This role has the same permissions as the Compliance Data Administrator
role group in Microsoft 365 Defender portal role-based access control.
Actions Description
Actions Description
Actions Description
Directory Readers
Users in this role can read basic directory information. This role should be used for:
Granting a specific set of guest users read access instead of granting it to all guest
users.
Granting a specific set of non-admin users access to Azure portal when "Restrict
access to Azure portal to admins only" is set to "Yes".
Granting service principals access to directory where Directory.Read.All is not an
option.
Actions Description
Actions Description
Directory Writers
Users in this role can read and update basic information of users, groups, and service
principals.
Actions Description
Actions Description
In the Microsoft Graph API and Azure AD PowerShell, this role is named Dynamics
365 Service Administrator. In the Azure portal, it is named Dynamics 365
Administrator.
Actions Description
Edge Administrator
Users in this role can create and manage the enterprise site list required for Internet
Explorer mode on Microsoft Edge. This role grants permissions to create, edit, and
publish the site list and additionally allows access to manage support tickets. Learn
more
Actions Description
Exchange Administrator
Users with this role have global permissions within Microsoft Exchange Online, when the
service is present. Also has the ability to create and manage all Microsoft 365 groups,
manage support tickets, and monitor service health. For more information, see About
admin roles in the Microsoft 365 admin center.
7 Note
In the Microsoft Graph API and Azure AD PowerShell, this role is named Exchange
Service Administrator. In the Azure portal, it is named Exchange Administrator. In
the Exchange admin center, it is named Exchange Online administrator.
Actions Description
Actions Description
Actions Description
Actions Description
Actions Description
Global Administrator
Users with this role have access to all administrative features in Azure Active Directory,
as well as services that use Azure Active Directory identities like the Microsoft 365
Defender portal, the Microsoft Purview compliance portal, Exchange Online, SharePoint
Online, and Skype for Business Online. Global Administrators can view Directory Activity
logs. Furthermore, Global Administrators can elevate their access to manage all Azure
subscriptions and management groups. This allows Global Administrators to get full
access to all Azure resources using the respective Azure AD Tenant. The person who
signs up for the Azure AD organization becomes a Global Administrator. There can be
more than one Global Administrator at your company. Global Administrators can reset
the password for any user and all other administrators. A Global Administrator cannot
remove their own Global Administrator assignment. This is to prevent a situation where
an organization has zero Global Administrators.
7 Note
As a best practice, Microsoft recommends that you assign the Global Administrator
role to fewer than five people in your organization. For more information, see Best
practices for Azure AD roles.
Actions Description
Global Reader
Users in this role can read settings and administrative information across Microsoft 365
services but can't take management actions. Global Reader is the read-only counterpart
to Global Administrator. Assign Global Reader instead of Global Administrator for
planning, audits, or investigations. Use Global Reader in combination with other limited
admin roles like Exchange Administrator to make it easier to get work done without the
assigning the Global Administrator role. Global Reader works with Microsoft 365 admin
center, Exchange admin center, SharePoint admin center, Teams admin center, Microsoft
365 Defender portal, Microsoft Purview compliance portal, Azure portal, and Device
Management admin center.
Cannot access the Purchase Services area in the Microsoft 365 admin center.
7 Note
OneDrive admin center - OneDrive admin center does not support the Global
Reader role
Microsoft 365 admin center - Global Reader can't read integrated apps. You
won't find the Integrated apps tab under Settings in the left pane of
Microsoft 365 admin center.
Microsoft 365 Defender portal - Global Reader can't read SCC audit logs, do
content search, or see Secure Score.
Teams admin center - Global Reader cannot read Teams lifecycle, Analytics &
reports, IP phone device management, and App catalog. For more
information, see Use Microsoft Teams administrator roles to manage Teams.
Privileged Access Management doesn't support the Global Reader role.
Azure Information Protection - Global Reader is supported for central
reporting only, and when your Azure AD organization isn't on the unified
labeling platform.
SharePoint - Global Reader currently can't access SharePoint using
PowerShell.
Power Platform admin center - Global Reader is not yet supported in the
Power Platform admin center.
Microsoft Purview doesn't support the Global Reader role.
Actions Description
Actions Description
Groups Administrator
Users in this role can create/manage groups and its settings like naming and expiration
policies. It is important to understand that assigning a user to this role gives them the
ability to manage all groups in the organization across various workloads like Teams,
SharePoint, Yammer in addition to Outlook. Also the user will be able to manage the
various groups settings across various admin portals like Microsoft admin center, Azure
portal, as well as workload specific ones like Teams and SharePoint admin centers.
Actions Description
Guest Inviter
Users in this role can manage Azure Active Directory B2B guest user invitations when the
Members can invite user setting is set to No. More information about B2B collaboration
at About Azure AD B2B collaboration. It does not include any other permissions.
Actions Description
Helpdesk Administrator
Users with this role can change passwords, invalidate refresh tokens, create and manage
support requests with Microsoft for Azure and Microsoft 365 services, and monitor
service health. Invalidating a refresh token forces the user to sign in again. Whether a
Helpdesk Administrator can reset a user's password and invalidate refresh tokens
depends on the role the user is assigned. For a list of the roles that a Helpdesk
Administrator can reset passwords for and invalidate refresh tokens, see Who can reset
passwords.
Cannot change the credentials or reset MFA for members and owners of a role-
assignable group.
) Important
Users with this role can change passwords for people who may have access to
sensitive or private information or critical configuration inside and outside of Azure
Active Directory. Changing the password of a user may mean the ability to assume
that user's identity and permissions. For example:
This role was previously named Password Administrator in the Azure portal. It was
renamed to Helpdesk Administrator to align with the existing name in the Microsoft
Graph API and Azure AD PowerShell.
Actions Description
Actions Description
Actions Description
Insights Administrator
Users in this role can access the full set of administrative capabilities in the Microsoft
Viva Insights app. This role has the ability to read directory information, monitor service
health, file support tickets, and access the Insights Administrator settings aspects.
Learn more
Actions Description
Insights Analyst
Assign the Insights Analyst role to users who need to do the following:
Analyze data in the Microsoft Viva Insights app, but can't manage any
configuration settings
Create, manage, and run queries
View basic settings and reports in the Microsoft 365 admin center
Create and manage service requests in the Microsoft 365 admin center
Learn more
Actions Description
Learn more
Actions Description
Intune Administrator
Users with this role have global permissions within Microsoft Intune Online, when the
service is present. Additionally, this role contains the ability to manage users and devices
in order to associate policy, as well as create and manage groups. For more information,
see Role-based administration control (RBAC) with Microsoft Intune.
This role can create and manage all security groups. However, Intune Administrator does
not have admin rights over Office groups. That means the admin cannot update owners
or memberships of all Office groups in the organization. However, he/she can manage
the Office group that he creates which comes as a part of his/her end-user privileges.
So, any Office group (not security group) that he/she creates should be counted against
his/her quota of 250.
7 Note
In the Microsoft Graph API and Azure AD PowerShell, this role is named Intune
Service Administrator. In the Azure portal, it is named Intune Administrator.
Actions Description
Kaizala Administrator
Users with this role have global permissions to manage settings within Microsoft Kaizala,
when the service is present, as well as the ability to manage support tickets and monitor
service health. Additionally, the user can access reports related to adoption & usage of
Kaizala by Organization members and business reports generated using the Kaizala
actions.
Actions Description
Knowledge Administrator
Users in this role have full access to all knowledge, learning and intelligent features
settings in the Microsoft 365 admin center. They have a general understanding of the
suite of products, licensing details and have responsibility to control access. Knowledge
Administrator can create and manage content, like topics, acronyms and learning
resources. Additionally, these users can create content centers, monitor service health,
and create service requests.
Actions Description
Knowledge Manager
Users in this role can create and manage content, like topics, acronyms and learning
content. These users are primarily responsible for the quality and structure of
knowledge. This user has full rights to topic management actions to confirm a topic,
approve edits, or delete a topic. This role can also manage taxonomies as part of the
term store management tool and create content centers.
Actions Description
License Administrator
Users in this role can read, add, remove, and update license assignments on users,
groups (using group-based licensing), and manage the usage location on users. The role
does not grant the ability to purchase or manage subscriptions, create or manage
groups, or create or manage users beyond the usage location. This role has no access to
view, create, or manage support tickets.
Actions Description
Create and manage all aspects of workflows and tasks associated with Lifecycle
Workflows in Azure AD
Check the execution of scheduled workflows
Launch on-demand workflow runs
Inspect workflow execution logs
Actions Description
Actions Description
Actions Description
Actions Description
Create new warranty claims for Microsoft manufactured hardware, like Surface and
HoloLens
Search and read opened or closed warranty claims
Search and read warranty claims by serial number
Create, read, update, and delete shipping addresses
Read shipping status for open warranty claims
Create and manage service requests in the Microsoft 365 admin center
Read Message center announcements in the Microsoft 365 admin center
A warranty claim is a request to have the hardware repaired or replaced in accordance
with the terms of the warranty. For more information, see Self-serve your Surface
warranty & service requests.
Actions Description
Create new warranty claims for Microsoft manufactured hardware, like Surface and
HoloLens
Read warranty claims that they created
Read and update existing shipping addresses
Read shipping status for open warranty claims they created
Create and manage service requests in the Microsoft 365 admin center
Actions Description
Actions Description
The Modern Commerce User role gives certain users permission to access Microsoft 365
admin center and see the left navigation entries for Home, Billing, and Support. The
content available in these areas is controlled by commerce-specific roles assigned to
users to manage products that they bought for themselves or your organization. This
might include tasks like paying bills, or for access to billing accounts and billing profiles.
Users with the Modern Commerce User role typically have administrative permissions in
other Microsoft purchasing systems, but do not have Global Administrator or Billing
Administrator roles used to access the admin center.
If the Modern Commerce User role is unassigned from a user, they lose access to
Microsoft 365 admin center. If they were managing any products, either for themselves
or for your organization, they won’t be able to manage them. This might include
assigning licenses, changing payment methods, paying bills, or other tasks for managing
subscriptions.
Actions Description
microsoft.commerce.billing/partners/read
Network Administrator
Users in this role can review network perimeter architecture recommendations from
Microsoft that are based on network telemetry from their user locations. Network
performance for Microsoft 365 relies on careful enterprise customer network perimeter
architecture which is generally user location specific. This role allows for editing of
discovered user locations and configuration of network parameters for those locations
to facilitate improved telemetry measurements and design recommendations
Actions Description
Actions Description
Write, publish, and delete organizational messages using Microsoft 365 admin
center or Microsoft Intune
Manage organizational message delivery options using Microsoft 365 admin
center or Microsoft Intune
Read organizational message delivery results using Microsoft 365 admin center or
Microsoft Intune
View usage reports and most settings in the Microsoft 365 admin center, but can't
make changes
Actions Description
) Important
This role can reset passwords and invalidate refresh tokens for only non-
administrators. This role should not be used because it is deprecated.
Actions Description
) Important
This role can reset passwords and invalidate refresh tokens for all non-
administrators and administrators (including Global Administrators). This role
should not be used because it is deprecated.
Actions Description
Password Administrator
Users with this role have limited ability to manage passwords. This role does not grant
the ability to manage service requests or monitor service health. Whether a Password
Administrator can reset a user's password depends on the role the user is assigned. For
a list of the roles that a Password Administrator can reset passwords for, see Who can
reset passwords.
Cannot change the credentials or reset MFA for members and owners of a role-
assignable group.
Actions Description
Manage all aspects of Entra Permissions Management, when the service is present
Learn more about Permissions Management roles and polices at View information about
roles/policies.
Actions Description
Power BI Administrator
Users with this role have global permissions within Microsoft Power BI, when the service
is present, as well as the ability to manage support tickets and monitor service health.
For more information, see Understanding Power BI administrator roles.
7 Note
In the Microsoft Graph API and Azure AD PowerShell, this role is named Power BI
Service Administrator. In the Azure portal, it is named Power BI Administrator.
Actions Description
Actions Description
Printer Administrator
Users in this role can register printers and manage all aspects of all printer
configurations in the Microsoft Universal Print solution, including the Universal Print
Connector settings. They can consent to all delegated print permission requests. Printer
Administrators also have access to print reports.
Actions Description
Printer Technician
Users with this role can register printers and manage printer status in the Microsoft
Universal Print solution. They can also read all connector information. Key task a Printer
Technician cannot do is set user permissions on printers and sharing printers.
Actions Description
Set or reset any authentication method (including passwords) for any user,
including Global Administrators.
Delete or restore any users, including Global Administrators. For more information,
see Who can perform sensitive actions.
Force users to re-register against existing non-password credential (such as MFA or
FIDO) and revoke remember MFA on the device, prompting for MFA on the next
sign-in of all users.
Update sensitive properties for all users. For more information, see Who can
perform sensitive actions.
Create and manage support tickets in Azure and the Microsoft 365 admin center.
Cannot manage per-user MFA in the legacy MFA management portal. The same
functions can be accomplished using the Set-MsolUser commandlet Azure AD
PowerShell module.
The following table compares the capabilities of this role with related roles.
Role Manage Manage Manage Manage Manage Update Delete
user's per- MFA auth password sensitive and
auth user settings method protection properties restore
methods MFA policy policy users
Privileged Yes for Yes for No No No Yes for all Yes for
Authentication all users all users users all
Administrator users
) Important
Users with this role can change credentials for people who may have access to
sensitive or private information or critical configuration inside and outside of Azure
Active Directory. Changing the credentials of a user may mean the ability to assume
that user's identity and permissions. For example:
Actions Description
) Important
This role grants the ability to manage assignments for all Azure AD roles including
the Global Administrator role. This role does not include any other privileged
abilities in Azure AD like creating or updating users. However, users assigned to this
role can grant themselves or others additional privilege by assigning additional
roles.
Actions Description
Actions Description
Search Administrator
Users in this role have full access to all Microsoft Search management features in the
Microsoft 365 admin center. Additionally, these users can view the message center,
monitor service health, and create service requests.
Actions Description
Search Editor
Users in this role can create, manage, and delete content for Microsoft Search in the
Microsoft 365 admin center, including bookmarks, Q&As, and locations.
Actions Description
Security Administrator
Users with this role have permissions to manage security-related features in the
Microsoft 365 Defender portal, Azure Active Directory Identity Protection, Azure Active
Directory Authentication, Azure Information Protection, and Microsoft Purview
compliance portal. For more information about Office 365 permissions, see Roles and
role groups in Microsoft Defender for Office 365 and Microsoft Purview compliance.
In Can do
Microsoft Add admins, add policies and settings, upload logs and perform governance
Defender for actions
Cloud Apps
Smart lockout Define the threshold and duration for lockouts when failed sign-in events
happen.
Cross-tenant Configure cross-tenant access settings for users in another tenant. Security
synchronization Administrators can't directly create and delete users, but can indirectly create
and delete synchronized users from another tenant when both tenants are
configured for cross-tenant synchronization, which is a privileged permission.
Actions Description
Security Operator
Users with this role can manage alerts and have global read-only access on security-
related features, including all information in Microsoft 365 Defender portal, Azure Active
Directory, Identity Protection, Privileged Identity Management and Microsoft Purview
compliance portal. For more information about Office 365 permissions, see Roles and
role groups in Microsoft Defender for Office 365 and Microsoft Purview compliance.
In Can do
Actions Description
Security Reader
Users with this role have global read-only access on security-related feature, including
all information in Microsoft 365 Defender portal, Azure Active Directory, Identity
Protection, Privileged Identity Management, as well as the ability to read Azure Active
Directory sign-in reports and audit logs, and in Microsoft Purview compliance portal. For
more information about Office 365 permissions, see Roles and role groups in Microsoft
Defender for Office 365 and Microsoft Purview compliance.
In Can do
Privileged Has read-only access to all information surfaced in Azure AD Privileged Identity
Identity Management: Policies and reports for Azure AD role assignments and security
Management reviews.
Cannot sign up for Azure AD Privileged Identity Management or make any
changes to it. In the Privileged Identity Management portal or via PowerShell,
someone in this role can activate additional roles (for example, Global
Administrator or Privileged Role Administrator), if the user is eligible for them.
In Can do
Intune Views user, device, enrollment, configuration, and application information. Cannot
make changes to Intune.
Actions Description
7 Note
This role was previously named Service Administrator in the Azure portal and
Microsoft 365 admin center. It was renamed to Service Support Administrator to
align with the existing name in the Microsoft Graph API and Azure AD PowerShell.
Actions Description
SharePoint Administrator
Users with this role have global permissions within Microsoft SharePoint Online, when
the service is present, as well as the ability to create and manage all Microsoft 365
groups, manage support tickets, and monitor service health. For more information, see
About admin roles in the Microsoft 365 admin center.
7 Note
In the Microsoft Graph API and Azure AD PowerShell, this role is named SharePoint
Service Administrator. In the Azure portal, it is named SharePoint Administrator.
7 Note
This role also grants scoped permissions to the Microsoft Graph API for Microsoft
Intune, allowing the management and configuration of policies related to
SharePoint and OneDrive resources.
Actions Description
7 Note
In the Microsoft Graph API and Azure AD PowerShell, this role is named Lync
Service Administrator. In the Azure portal, it is named Skype for Business
Administrator.
Actions Description
Teams Administrator
Users in this role can manage all aspects of the Microsoft Teams workload via the
Microsoft Teams & Skype for Business admin center and the respective PowerShell
modules. This includes, among other areas, all management tools related to telephony,
messaging, meetings, and the teams themselves. This role additionally grants the ability
to create and manage all Microsoft 365 groups, manage support tickets, and monitor
service health.
Actions Description
Actions Description
Actions Description
Actions Description
Tenant Creator
Assign the Tenant Creator role to users who need to do the following tasks:
Create both Azure Active Directory and Azure Active Directory B2C tenants even if
the tenant creation toggle is turned off in the user settings
7 Note
The tenant creators will be assigned the Global administrator role on the new
tenants they create.
Actions Description
User Administrator
Assign the User Administrator role to users who need to do the following:
Create users
Update most user properties for all users, including all Who can perform sensitive
administrators actions
Update sensitive properties (including user principal name) for Who can perform sensitive
some users actions
Assign and read licenses for all users, including all administrators
Create and manage support tickets in Azure and the Microsoft 365
admin center
) Important
Users with this role can change passwords for people who may have access to
sensitive or private information or critical configuration inside and outside of Azure
Active Directory. Changing the password of a user may mean the ability to assume
that user's identity and permissions. For example:
Actions Description
Manage and configure all aspects of Virtual Visits in Bookings in the Microsoft 365
admin center, and in the Teams EHR connector
View usage reports for Virtual Visits in the Teams admin center, Microsoft 365
admin center, and Power BI
View features and settings in the Microsoft 365 admin center, but can't edit any
settings
Virtual Visits are a simple way to schedule and manage online and video appointments
for staff and attendees. For example, usage reporting can show how sending SMS text
messages before appointments can reduce the number of people who don't show up
for appointments.
Actions Description
Manage and configure all aspects of the Microsoft Viva Goals application
Configure Microsoft Viva Goals admin settings
Read Azure AD tenant information
Monitor Microsoft 365 service health
Create and manage Microsoft 365 service requests
For more information, see Roles and permissions in Viva Goals and Introduction to
Microsoft Viva Goals.
Actions Description
Assign the Windows 365 Administrator role to users who need to do the following tasks:
Actions Description
Actions Description
Yammer Administrator
Assign the Yammer Administrator role to users who need to do the following tasks:
Learn more
Actions Description
<namespace>/<entity>/<propertySet>/<action>
For example:
microsoft.directory/applications/credentials/update
Permission Description
element
namespace Product or service that exposes the task and is prepended with microsoft . For
example, all tasks in Azure AD use the microsoft.directory namespace.
entity Logical feature or component exposed by the service in Microsoft Graph. For
example, Azure AD exposes User and Groups, OneNote exposes Notes, and
Exchange exposes Mailboxes and Calendars. There is a special allEntities
keyword for specifying all entities in a namespace. This is often used in roles that
grant access to an entire product.
Permission Description
element
propertySet Specific properties or aspects of the entity for which access is being granted. For
example, microsoft.directory/applications/authentication/read grants the ability
to read the reply URL, logout URL, and implicit flow property on the application
object in Azure AD.
action Operation being granted, most typically create, read, update, or delete (CRUD).
There is a special allTasks keyword for specifying all of the above abilities (create,
read, update, and delete).
Deprecated roles
The following roles should not be used. They have been deprecated and will be
removed from Azure AD in the future.
Partner Tier 1 Support Not shown because it Partner Tier1 Support documentation
shouldn't be used
Partner Tier 2 Support Not shown because it Partner Tier2 Support documentation
shouldn't be used
The following table is for roles assigned at the scope of a tenant. For roles assigned at
the scope of an administrative unit, further restrictions apply.
Role that password can be Password Helpdesk Auth User Privileged Global
reset Admin Admin Admin Admin Auth Admin
Admin
Auth Admin ✔️ ✔️ ✔️
Directory Readers ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Groups Admin ✔️ ✔️ ✔️
Guest Inviter ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Role that password can be Password Helpdesk Auth User Privileged Global
reset Admin Admin Admin Admin Auth Admin
Admin
Helpdesk Admin ✔️ ✔️ ✔️ ✔️
Password Admin ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Reports Reader ✔️ ✔️ ✔️ ✔️ ✔️
User ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
(no admin role)
User ✔️ ✔️
(no admin role, but member
or owner of a role-assignable
group)
User Admin ✔️ ✔️ ✔️
) Important
The Partner Tier2 Support role can reset passwords and invalidate refresh tokens
for all non-administrators and administrators (including Global Administrators). The
Partner Tier1 Support role can reset passwords and invalidate refresh tokens for
only non-administrators. These roles should not be used because they are
deprecated.
The ability to reset a password includes the ability to update the following sensitive
properties required for self-service password reset:
businessPhones
mobilePhone
otherMails
Who can perform sensitive actions
Some administrators can perform the following sensitive actions for some users. All
users can read the sensitive properties.
In the following table, the columns list the roles that can perform sensitive actions. The
rows list the roles for which the sensitive action can be performed upon.
The following table is for roles assigned at the scope of a tenant. For roles assigned at
the scope of an administrative unit, further restrictions apply.
Auth Admin ✔️ ✔️ ✔️
Directory Readers ✔️ ✔️ ✔️ ✔️
Global Admin ✔️ ✔️
Groups Admin ✔️ ✔️ ✔️
Guest Inviter ✔️ ✔️ ✔️ ✔️
Helpdesk Admin ✔️ ✔️ ✔️
Password Admin ✔️ ✔️ ✔️ ✔️
Reports Reader ✔️ ✔️ ✔️ ✔️
User ✔️ ✔️ ✔️ ✔️
(no admin role)
User ✔️ ✔️
(no admin role, but member or owner of a
role-assignable group)
User Admin ✔️ ✔️ ✔️
Next steps
Assign Azure AD roles to groups
Understand the different roles
Assign a user as an administrator of an Azure subscription
Call Microsoft Graph from a Cloud
Solution Provider application
Article • 01/04/2023
Note: This topic applies only to Microsoft Cloud Solution Provider (CSP) application
developers. The Microsoft Cloud Solution Provider (CSP) program enables
Microsoft’s partners to resell and manage Microsoft Online services to customers.
) Important
Calling Microsoft Graph from a CSP application is only supported for directory
resources (such as user, group,device, organization) and Intune resources.
1. Register your application in your Partner tenant using the Azure Portal . To
function as a partner-managed app, an application must be configured as a multi-
tenant app. Additionally, if your app is deployed and sold in multiple geographic
regions you will need to register your app in each of those regions as described
here.
2. Configure your multi-tenant app, again through the Azure Portal, with the required
permissions it needs using a least privileged approach.
Azure AD PowerShell
PowerShell
Connect-AzureAd
PowerShell
3. Find the service principal that has the same appId as your app.
PowerShell
PowerShell
Apart from pre-consented access to all your customer tenants, partner-managed apps
have one additional capability. It allows for your agents to use your app to access your
customers' tenant data (using delegated admin privileges). Conceptually it works like
this:
1. Your agent signs in to your app with their user credentials issued from your partner
tenant.
2. Your app requests an access token for the intended partner-managed customer
tenant.
3. Your app uses the access token to call Microsoft Graph.
This is a standard authorization code grant flow, except that your agents must sign-in
using their partner accounts. To see how this would look, imagine your partner tenant is
partner.com (which is the home tenant for your agents) and one of your customers is
customer.com:
HTTP
GET https://login.microsoftonline.com/customer.com/oauth2/authorize
2. Acquire an access token using the authorization code: Your app must use a
customer tenant as the target tenant, in our example customer.com , when making
the request to the token endpoint:
HTTP
POST https://login.microsoftonline.com/customer.com/oauth2/token
3. Now you have an access token, call Microsoft Graph, putting the access token in
the HTTP authorization header:
HTTP
GET https://graph.microsoft.com/beta/users
Authorization: Bearer <token>
Note: On the retry, you must acquire a new access token from Azure AD, before
calling Microsoft Graph. Calling Microsoft Graph with the access token you already
have will not work, because the access token is good for an hour and won’t contain
the pre-consented permission claims.
Limiting application permissions to
specific Exchange Online mailboxes
Article • 03/03/2022
Administrators who want to limit app access to specific mailboxes can create an
application access policy by using the New-ApplicationAccessPolicy PowerShell cmdlet.
This article covers the basic steps to configure access control. These steps are specific to
Exchange Online resources and do not apply to other Microsoft Graph workloads.
Background
Some apps call Microsoft Graph using their own identity and not on behalf of a user.
These are usually background services or daemon apps that run on a server without the
presence of a signed-in user. These apps make use of OAuth 2.0 client credentials grant
flow to authenticate and are configured with application permissions, which by default
enable such apps to access all mailboxes in a organization on Exchange Online. For
example, the Mail.Read application permission allows apps to read mail in all mailboxes
without a signed-in user.
) Important
By default, apps that have been granted application permissions to the following
data sets can access all the mailboxes in the organization:
Calendars
Contacts
Mail
Mailbox settings
There are scenarios where administrators may want to limit an app to only specific
mailboxes and not all Exchange Online mailboxes in the organization. Administrators
can identify the set of mailboxes to permit access by putting them in a mail-enabled
security group. Administrators can then limit third-party app access to only that set of
mailboxes by creating an application access policy for access to that group.
As further described in the Supported permissions and additional resources section
below, application access policy restricts mailbox access for apps that have been
granted any of the Microsoft Graph or Exchange Web Services permission scopes that
the policy supports.
Configure ApplicationAccessPolicy
To configure an application access policy and limit the scope of application permissions:
2. Identify the app’s client ID and a mail-enabled security group to restrict the app’s
access to.
PowerShell
Run the following command, replacing the arguments for Identity and AppId.
PowerShell
The output of this command will indicate whether the app has access to User1’s
mailbox.
7 Note
Changes to application access policies can take longer than 1 hour to take effect in
Microsoft Graph REST API calls, even when Test-ApplicationAccessPolicy shows
positive results.
Mail.Read
Mail.ReadBasic
Mail.ReadBasic.All
Mail.ReadWrite
Mail.Send
MailboxSettings.Read
MailboxSettings.ReadWrite
Calendars.Read
Calendars.ReadWrite
Contacts.Read
Contacts.ReadWrite
For more information about configuring application access policy, see the PowerShell
cmdlet reference for New-ApplicationAccessPolicy.
JSON
{
"error": {
"code": "ErrorAccessDenied",
"message": "Access to OData is disabled.",
"innerError": {
"request-id": "2f038156-cf40-403d-8e46-831fe42a8229",
"date": "2019-05-24T10:16:21"
}
}
}
If the Microsoft Graph API calls from your app return this error, work with the Exchange
Online administrator for the organization to ensure that your app has permission to
access the mailbox resource.
See also
Permissions reference
New-ApplicationAccessPolicy
Get-ApplicationAccessPolicy
Remove-ApplicationAccessPolicy
Set-ApplicationAccessPolicy
Test-ApplicationAccessPolicy
Application Access Policy Support in EWS
Resolve Microsoft Graph authorization
errors
Article • 05/23/2023
Authorization errors can occur as a result of several different issues, most of which
generate a 403 error (with a few exceptions). For example, the following can all lead to
authorization errors:
403 Forbidden: Does the user have access and are they
licensed?
For delegated code flows, Microsoft Graph evaluates whether the request is allowed
based on the permissions granted to the app and the permissions that the signed-in
user has. Generally, this error indicates that the user is not privileged enough to perform
the request or the user is not licensed for the data being accessed. Only users with the
required permissions or licenses can make the request successfully.
acquired for Azure AD Graph APIs, Outlook APIs, or SharePoint/OneDrive APIs to call
Microsoft Graph (or vice versa). Ensure that the resource (or scope) your app is acquiring
a token for matches the API that the app is calling.
JSON
{
"error": {
"code": "ErrorAccessDenied",
"message": "Access to OData is disabled."
}
}
PowerShell
Get-OrganizationConfig | fl EwsApplicationAccessPolicy,EWS*List
PowerShell
Get-CASMailbox <user-principal-name> | fl
EwsApplicationAccessPolicy,EWS*List
7 Note
Changes to EWS application policies take time to take effect. Your application
might continue to receive 403 Forbidden errors for some time after you make a
change.
Use the Microsoft Graph API
Article • 01/27/2023
Microsoft Graph is a RESTful web API that enables you to access Microsoft Cloud service
resources. After you register your app and get authentication tokens for a user or
service, you can make requests to the Microsoft Graph API.
) Important
OData namespace
The Microsoft Graph API defines most of its resources, methods, and enumerations in
the OData namespace, microsoft.graph , in the Microsoft Graph metadata. A small
number of API sets are defined in their sub-namespaces, such as the call records API
which defines resources like callRecord in microsoft.graph.callRecords .
Unless explicitly specified in the corresponding topic, assume types, methods, and
enumerations are part of the microsoft.graph namespace.
HTTP
{HTTP method} - The HTTP method used on the request to Microsoft Graph.
{version} - The version of the Microsoft Graph API your application is using.
{resource} - The resource in Microsoft Graph that you're referencing.
{query-parameters} - Optional OData query options or REST method parameters
that customize the response.
Status code - An HTTP status code that indicates success or failure. For details
about HTTP error codes, see Errors.
Response message - The data that you requested or the result of the operation.
The response message can be empty for some operations.
@odata.nextLink - If your request returns a lot of data, you need to page through
HTTP methods
Microsoft Graph uses the HTTP method on your request to determine what your request
is doing. Depending on the resource, the API may support operations including actions,
functions, or CRUD operations described below.
Method Description
For the CRUD methods GET and DELETE , no request body is required.
The POST , PATCH , and PUT methods require a request body, usually specified in
JSON format, that contains additional information, such as the values for
properties of the resource.
) Important
Write requests in the Microsoft Graph API have a size limit of 4 MB.
In some cases, the actual write request size limit is lower than 4 MB. For example,
attaching a file to a user event by POST /me/events/{id}/attachments has a request
size limit of 3 MB, because a file around 3.5 MB can become larger than 4 MB when
encoded in base64.
Requests exceeding the size limit fail with the status code HTTP 413, and the error
message "Request entity too large" or "Payload too large".
Version
Microsoft Graph currently supports two versions: v1.0 and beta .
v1.0 includes generally available APIs. Use the v1.0 version for all production apps.
beta includes APIs that are currently in preview. Because we might introduce
breaking changes to our beta APIs, we recommend that you use the beta version
only to test apps that are in development; do not use beta APIs in your production
apps.
We are always looking for feedback on our beta APIs. To provide feedback or request
features, see our Microsoft 365 Developer Platform ideas forum .
For more information about API versions, see Versioning and support.
Resource
A resource can be an entity or complex type, commonly defined with properties. Entities
differ from complex types by always including an id property.
Your URL will include the resource you are interacting with in the request, such as me ,
user, group, drive, and site. Often, top-level resources also include relationships, which
you can use to access additional resources, like me/messages or me/drive . You can also
interact with resources using methods; for example, to send an email, use me/sendMail .
For more information, see Access data and methods by navigating Microsoft Graph.
Each resource might require different permissions to access it. You will often need a
higher level of permissions to create or update a resource than to read it. For details
about required permissions, see the method reference topic.
Query parameters
Query parameters can be OData system query options, or other strings that a method
accepts to customize its response.
You can use optional OData system query options to include more or fewer properties
than the default response, filter the response for items that match a custom query, or
provide additional parameters for a method.
For example, adding the following filter parameter restricts the messages returned to
only those with the emailAddress property of [email protected] .
HTTP
GET https://graph.microsoft.com/v1.0/me/messages?filter=emailAddress eq
'[email protected]'
For more information about OData query options, see Use query parameters to
customize responses.
Aside from OData query options, some methods require parameter values specified as
part of the query URL. For example, you can get a collection of events that occurred
during a time period in a user's calendar, by querying the calendarView relationship of a
user, and specifying the period startDateTime and endDateTime values as query
parameters:
HTTP
GET https://graph.microsoft.com/me/calendarView?startDateTime=2019-09-
01T09:00:00.0000000&endDateTime=2019-09-01T17:00:00.0000000
Graph Explorer
Graph Explorer is a web-based tool that you can use to build and test requests using
Microsoft Graph APIs. You can access Graph Explorer at:
https://developer.microsoft.com/graph/graph-explorer.
You can either access demo data without signing in, or you can sign in to a tenant of
your own. Use the following steps to build the request:
Sample queries are provided in Graph Explorer to enable you to more quickly run
common requests. To see the samples that are available, select show more samples.
Select On for the set of samples that you want to see, and then after closing the
selection window, you should see a list of predefined requests.
A status code and message are displayed after a request is sent and the response is
shown in the Response Preview tab.
Postman
Postman is a tool that you can use to build and test requests using the Microsoft Graph
APIs. You can download Postman at: https://www.getpostman.com/ . To interact with
Microsoft Graph in Postman, you use the Microsoft Graph collection.
For more information, see Use Postman with the Microsoft Graph API.
Next steps
You're ready to get up and running with Microsoft Graph. Try the Quick Start, or get
started using one of our SDKs and code samples.
Access data and methods by navigating
Microsoft Graph
Article • 08/17/2022
In addition to using the Microsoft Graph API to read and write data, you can use a
number of request patterns to traverse through the resources in Microsoft Graph. The
metadata document also helps you to understand the data model of the resources and
relationships in Microsoft Graph.
HTTP
https://graph.microsoft.com/v1.0/$metadata
HTTP
https://graph.microsoft.com/beta/$metadata
The metadata allows you to see and understand the Microsoft Graph data model,
including the entity types, complex types, and enumerations that make up the resources
represented in the request and response packets.
You can use the metadata to learn the relationships between entities in Microsoft Graph
and establish URLs that navigate between those entities.
7 Note
Use resource IDs in the same case as they are returned from Microsoft Graph
APIs.
Assume resource IDs, values you assign, and other base-64-encoded values
are case-sensitive.
Assume path URL resource names, query parameters, action and function
names, their request body parameters, including any API property names and
values, are not case-sensitive.
For example, you can get the collection of user resources defined in a tenant:
If successful, you'll get a 200 OK response that contains the collection of user resources
in the payload. Each user is identified by the id property and accompanied by its default
properties. The payload shown below is truncated for brevity.
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users",
"value":[
{
"id":"f71f1f74-bf1f-4e6b-b266-c777ea76e2c7",
"businessPhones":[
],
"displayName":"CIE Administrator",
"givenName":"CIE",
"jobTitle":null,
"mail":"[email protected]",
"mobilePhone":"+1 3528700812",
"officeLocation":null,
"preferredLanguage":"en-US",
"surname":"Administrator",
"userPrincipalName":"[email protected]"
},
{
"id":"d66f2902-9d12-4ff8-ab01-21ec6706079f",
"businessPhones":[
],
"displayName":"Alan Steiner",
"givenName":"Alan",
"jobTitle":"VP Corporate Marketing",
"mail":"[email protected]",
"mobilePhone":null,
"officeLocation":null,
"preferredLanguage":"en-US",
"surname":"Steiner",
"userPrincipalName":"[email protected]"
}
]
}
Microsoft Graph also lets you view collections by navigating the relationships of one
resource with another. For example, through a user's mailFolders navigation property,
you can query for the collection of mailFolder resources in the user's mailbox:
If successful, you'll get a 200 OK response that contains the collection of mailFolder
resources in the payload. Each mailFolder is identified by the id property and
accompanied by its properties. The payload shown below is truncated for brevity.
HTTP/1.1 200 OK
Content-type: application/json
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users('16f5a7b6
-5a15-4568-aa5a-31bb117e9967')/mailFolders",
"value":[
{
"id":"AAMkADRm9AABDGisXAAA=",
"displayName":"Archive",
"parentFolderId":"AQMkADRmZWj0AAAIBCAAAAA==",
"childFolderCount":0,
"unreadItemCount":0,
"totalItemCount":0
},
{
"id":"AQMkADRm0AAAIBXAAAAA==",
"displayName":"Sales reports",
"parentFolderId":"AQMkADRmZWj0AAAIBCAAAAA==",
"childFolderCount":0,
"unreadItemCount":0,
"totalItemCount":0
},
{
"id":"AAMkADRCxI9AAAT6CAIAAA=",
"displayName":"Conversation History",
"parentFolderId":"AQMkADRmZWj0AAAIBCAAAAA==",
"childFolderCount":1,
"unreadItemCount":0,
"totalItemCount":0
}
]
}
The following request example uses the userPrincipalName value as the user's ID.
GET https://graph.microsoft.com/v1.0/users/[email protected]
HTTP/1.1
Authorization : Bearer {access_token}
If successful, you'll get a 200 OK response that contains the user resource representation
in the payload, as shown.
HTTP/1.1 200 OK
content-type: application/json;odata.metadata=minimal
content-length: 982
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"id": "c95e3b3a-c33b-48da-a6e9-eb101e8a4205",
"city": "Redmond",
"country": "USA",
"department": "Help Center",
"displayName": "John Doe",
"givenName": "John",
"userPrincipalName": "[email protected]",
...
}
GET https://graph.microsoft.com/v1.0/users/[email protected]?
$select=displayName,aboutMe,skills HTTP/1.1
Authorization : Bearer {access_token}
The successful response returns the 200 OK status and a payload, as shown.
HTTP/1.1 200 OK
content-type: application/json;odata.metadata=minimal
content-length: 169
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"aboutMe": "A cool and nice guy.",
"displayName": "John Doe",
"skills": [
"n-Lingual",
"public speaking",
"doodling"
]
}
Here, instead of the entire property sets on the user entity, only the aboutMe,
displayName, and skills basic properties are returned.
Read specific properties of the resources in a
collection
In addition to reading specific properties of a single resource, you can also apply the
similar $select query parameter to a collection to get back all resources in the collection
with just the specific properties returned on each.
For example, to query the name of the signed-in user's drive items, you can submit the
following HTTPS GET request.
GET https://graph.microsoft.com/v1.0/me/drive/root/children?$select=name
HTTP/1.1
Authorization : Bearer {access_token}
The successful response returns a 200 OK status code and a payload that contains only
the names of the shared files, as shown in the following example.
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('john.doe%40contoso.onmicr
osoft.com')/drive/root/children(name,type)",
"value": [
{
"@odata.etag": "\"{896A8E4D-27BF-424B-A0DA-F073AE6570E2},2\"",
"name": "Shared with Everyone"
},
{
"@odata.etag": "\"{B39D5D2E-E968-491A-B0EB-D5D0431CB423},1\"",
"name": "Documents"
},
{
"@odata.etag": "\"{9B51EA38-3EE6-4DC1-96A6-230E325EF054},2\"",
"name": "newFile.txt"
}
]
}
GET
https://graph.microsoft.com/v1.0/users/[email protected]/dire
ctReports HTTP/1.1
Authorization : Bearer {access_token}
The successful response returns the 200 OK status and a payload, as shown.
HTTP/1.1 200 OK
content-type: application/json;odata.metadata=minimal
content-length: 152
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#directoryObjects/$entity",
"@odata.type": "#microsoft.graph.user",
"id": "c37b074d-fe9d-4e68-83ad-b4401d3be174",
"department": "Sales & Marketing",
"displayName": "Bonnie Kearney",
...
}
Similarly, you can follow a relationship to navigate to related resources. For example, the
user-messages relationship enables traversal from an Azure Active Directory (Azure AD)
User to a set of Outlook mail messages. The following example shows how to do this in
a REST API call.
The successful response returns the 200 OK status and a payload, as shown.
HTTP/1.1 200 OK
content-type: application/json;odata.metadata=minimal
odata-version: 4.0
content-length: 147
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('john.doe%40contoso.onmicr
osoft.com')/Messages",
"@odata.nextLink": "https://graph.microsoft.com/v1.0/me/messages?
$top=1&$skip=1",
"value": [
{
"@odata.etag": "W/\"FwAAABYAAABMR67yw0CmT4x0kVgQUH/3AAJL+Kej\"",
"id": "<id-value>",
"createdDateTime": "2015-11-14T00:24:42Z",
"lastModifiedDateTime": "2015-11-14T00:24:42Z",
"changeKey": "FwAAABYAAABMR67yw0CmT4x0kVgQUH/3AAJL+Kej",
"categories": [],
"receivedDateTime": "2015-11-14T00:24:42Z",
"sentDateTime": "2015-11-14T00:24:28Z",
"hasAttachments": false,
"subject": "Did you see last night's game?",
"body": {
"ContentType": "HTML",
"Content": "<content>"
},
"BodyPreview": "it was great!",
"Importance": "Normal",
...
}
]
}
You can see all the relationships on a given resource by going to the metadata, finding
the EntityType , and looking at each NavigationProperty for that EntityType .
You can see all the functions that are available in the metadata. They appear as
Functions or Actions.
See also
Use the Microsoft Graph API
Get auth tokens
Paging Microsoft Graph data in your
app
Article • 01/27/2023
Some queries against Microsoft Graph return multiple pages of data either due to
server-side paging or due to the use of the $top query parameter to specifically limit
the page size in a request. When more than one query request is required to retrieve all
the results, Microsoft Graph returns an @odata.nextLink property in the response that
contains a URL to the next page of results.
For example, the following URL requests all the users in an organization with a page size
of 5, specified with the $top query parameter:
HTML
https://graph.microsoft.com/v1.0/users?$top=5
If the result contains more results, Microsoft Graph will return an @odata.nextLink
property similar to the following along with the first page of results:
JSON
"@odata.nextLink": "https://graph.microsoft.com/v1.0/users?
$top=5&$skiptoken=X%274453707 ... 6633B900000000000000000000%27"
You can retrieve the next page of results by sending the URL value of the
@odata.nextLink property to Microsoft Graph.
HTML
https://graph.microsoft.com/v1.0/users?$top=5&$skiptoken=X%274453707 ...
6633B900000000000000000000%27
Microsoft Graph will continue to return a reference to the next page of results in the
@odata.nextLink property with each response until all pages of the results have been
read. To read all results, you must continue to call Microsoft Graph with the
@odata.nextLink property returned in each response until the @odata.nextLink property
is no longer returned.
Important: You should include the entire URL in the @odata.nextLink property in
your request for the next page of results. Depending on the API that the query is
being performed against, the @odata.nextLink URL value will contain either a
$skiptoken or a $skip query parameter. The URL also contains all the other query
parameters present in the original request. Do not try to extract the $skiptoken or
$skip value and use it in a different request.
Paging behavior varies across different Microsoft Graph APIs. Consider the following
when working with paged data:
Microsoft Graph supports optional query parameters that you can use to specify and
control the amount of data returned in a response. The support for the exact query
parameters varies from one API operation to another, and depending on the API, can
differ between the v1.0 and beta endpoints.
Tip
On the beta endpoint, the $ prefix is optional. For example, instead of $filter ,
you can use filter . On the v1 endpoint, the $ prefix is optional for only a subset
of APIs. For simplicity, always include $ if using the v1 endpoint.
Query parameters can be OData system query options or other query parameters.
https://www.youtube-nocookie.com/embed/7BuFv3yETi4
$skip Indexes into a result set. Also used by some APIs to /me/messages?$skip=11
implement paging and can be used together with
$top to manually page results.
To know the OData system query options that an API and its properties support, see the
Properties table in the resource page, and the Optional query parameters section of
the LIST and GET operations for the API.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?$filter=startswith(givenName,
'J')
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?
$filter=startswith(givenName%2C+'J')
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?
$filter=startswith%28givenName%2C%20%27J%27%29
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/messages?$filter=subject eq
'let''s meet for lunch?'
count parameter
Use the $count query parameter to retrieve the count of the total number of items in a
collection or matching an expression. $count can be used in the following ways:
1. As a query string parameter with the syntax $count=true to include a count of the
total number of items in a collection alongside the page of data values returned
from Microsoft Graph. For example, users?$count=true .
2. As a URL segment to retrieve only the integer total of the collection. For example,
users/$count .
3. In a $filter expression with equality operators to retrieve a collection of data
where the filtered property is an empty collection. See Use the $filter query
parameter to filter a collection of objects.
7 Note
For example, the following request returns both the contact collection of the current
user, and the number of items in the contact collection in the @odata.count property.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/contacts?$count=true
The $count query parameter is supported for collections of the following frequently
used resources and their relationships that derive from directoryObject and only in
advanced queries:
administrativeUnit
application
orgContact
device
group
servicePrincipal
user
expand parameter
Many Microsoft Graph resources expose both declared properties of the resource as
well as its relationships with other resources. These relationships are also called
reference properties or navigation properties, and they can reference either a single
resource or a collection of resources. For example, the mail folders, manager, and direct
reports of a user are all exposed as relationships.
Normally, you can query either the properties of a resource or one of its relationships in
a single request, but not both. You can use the $expand query string parameter to
include the expanded resource or collection referenced by a single relationship
(navigation property) in your results. Only one relationship can be expanded in a single
request.
The following example gets root drive information along with the top-level child items
in a drive:
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/drive/root?$expand=children
With some resource collections, you can also specify the properties to be returned in the
expanded resources by adding a $select parameter. The following example performs
the same query as the previous example but uses a $select statement to limit the
properties returned for the expanded child items to the id and name properties.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/drive/root?
$expand=children($select=id,name)
7 Note
Not all relationships and resources support the $expand query parameter. For
example, you can expand the directReports, manager, and memberOf
relationships on a user, but you cannot expand its events, messages, or photo
relationships. Not all resources or relationships support using $select on
expanded items.
With Azure AD resources that derive from directoryObject, like user and
group, $expand typically returns a maximum of 100 items for the expanded
relationship and has no @odata.nextLink. See more known issues.
filter parameter
Use the $filter query parameter to retrieve just a subset of a collection. For guidance
on using $filter , see Use the $filter query parameter to filter a collection of objects.
format parameter
Use the $format query parameter to specify the media format of the items returned
from Microsoft Graph.
For example, the following request returns the users in the organization in the json
format:
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?$format=json
7 Note
The $format query parameter supports a number of formats (for example, atom,
xml, and json) but results may not be returned in all formats.
orderby parameter
Use the $orderby query parameter to specify the sort order of the items returned from
Microsoft Graph. The default order is ascending order.
For example, the following request returns the users in the organization ordered by their
display name:
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?$orderby=displayName
You can also sort by complex type entities. The following request gets messages and
sorts them by the address field of the from property, which is of the complex type
emailAddress:
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/messages?
$orderby=from/emailAddress/address
To sort the results in ascending or descending order, append either asc or desc to the
field name, separated by a space; for example, ?$orderby=name%20desc . If the sort order
is not specified, the default (ascending order) is inferred.
With some APIs, you can order results on multiple properties. For example, the following
request orders the messages in the user's Inbox, first by the name of the person who
sent it in descending order (Z to A), and then by subject in ascending order (default).
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/mailFolders/Inbox/messages?
$orderby=from/emailAddress/name desc,subject
7 Note
When you specify $filter the server will infer a sort order for the results. If you use
both $orderby and $filter to get messages, because the server always infers a
sort order for the results of a $filter , you must specify properties in certain ways.
The following example shows a query filtered by the subject and importance properties,
and then sorted by the subject, importance, and receivedDateTime properties in
descending order.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/messages?$filter=Subject eq
'welcome' and importance eq
'normal'&$orderby=subject,importance,receivedDateTime desc
7 Note
search parameter
Use the $search query parameter to restrict the results of a request to match a search
criterion. It's syntax and behavior varies from one API operation to another. To see the
syntax for $search across different resources, see Use the $search query parameter to
match a search criterion.
select parameter
Use the $select query parameter to return a set of properties that are different than the
default set for an individual resource or a collection of resources. With $select , you can
specify a subset or a superset of the default properties.
For example, when retrieving the messages of the signed-in user, you can specify that
only the from and subject properties be returned:
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/messages?$select=from,subject
) Important
In general, we recommend that you use $select to limit the properties returned by
a query to those needed by your app. This is especially true of queries that might
potentially return a large result set. Limiting the properties returned in each row will
reduce network load and help improve your app's performance.
In v1.0 , some Azure AD resources that derive from directoryObject, like user and
group, return a limited, default subset of properties on reads. For these resources,
you must use $select to return properties outside of the default set.
skip parameter
Use the $skip query parameter to set the number of items to skip at the start of a
collection. For example, the following request returns events for the user sorted by date
created, starting with the 21st event in the collection:
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/events?
$orderby=createdDateTime&$skip=20
Some Microsoft Graph APIs, like Outlook Mail and Calendars (message, event, and
calendar), use $skip to implement paging. When results of a query span multiple
pages, these APIs will return an @odata:nextLink property with a URL that contains a
$skip parameter. You can use this URL to return the next page of results. To learn more,
see Paging.
Directory objects such as user, group, and application don't support $skip .
skipToken parameter
Some requests return multiple pages of data, either due to server-side paging or due to
the use of the $top parameter to limit the page size of the response. Many Microsoft
Graph APIs use the skipToken query parameter to reference subsequent pages of the
result.
The $skiptoken parameter contains an opaque token that references the next page of
results and is returned in the URL provided in the @odata.nextLink property in the
response. To learn more, see Paging.
7 Note
If you're using OData Count (adding $count=true in the query string) for queries
against directory objects, the @odata.count property is present only in the first
page.
top parameter
Use the $top query parameter to specify the number of items to be included in the
result.
If more items remain in the result set, the response body will contain an
@odata.nextLink parameter. This parameter contains a URL that you can use to get the
next page of results. To learn more, see Paging.
The minimum value of $top is 1 and the maximum depends on the corresponding API.
For example, the following list messages request returns the first five messages in the
user's mailbox:
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/messages?$top=5
7 Note
HTTP
https://graph.microsoft.com/v1.0/me?$expand=photo
JSON
{
"error":{
"code":"ExpandNotSupported",
"message":"Expand is not allowed for property 'Photo' according to
the entity schema.",
"innerError":{
"request-id":"1653fefd-bc31-484b-bb10-8dc33cb853ec",
"date":"2017-07-31T20:55:01"
}
}
}
However, it is important to note that query parameters specified in a request might fail
silently. This can be true for unsupported query parameters as well as for unsupported
combinations of query parameters. In these cases, you should examine the data
returned by the request to determine whether the query parameters you specified had
the desired effect.
See also
Advanced query capabilities on Azure AD directory objects
Use the $search query parameter to match a search criterion
Query parameter limitations
Training module: Optimize data usage when using Microsoft Graph with query
parameters
Use the filter query parameter
Article • 04/14/2023
Microsoft Graph supports the $filter OData query parameter to retrieve a subset of
a collection.
The expression specified with $filter is evaluated for each resource in the collection,
and only items where the expression evaluates to true are included in the response.
Resources for which the expression evaluates to false or to null , or which reference
properties that are unavailable due to permissions, are omitted from the response.
The $filter query parameter can also be used to retrieve relationships like members,
memberOf, transitiveMembers, and transitiveMemberOf. For example, "get all the
security groups that I'm a member of".
7 Note
Support for these operators varies by entity and some properties support $filter
only with advanced queries. See the specific resource documentation for details.
any operator
The any operator iteratively applies a Boolean expression to each item of a collection
and returns true if the expression is true for at least one item of the collection,
otherwise it returns false .
The following is the syntax of the any operator:
HTTP
$filter=collection/any(property:property/subProperty eq 'value-to-match')
Where
C#
For example, the imAddresses property of the user resource contains a collection of
String primitive types. The following query retrieves only users with an imAddress of
[email protected] .
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?$filter=imAddresses/any(i:i
eq '[email protected]')
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?
$filter=assignedLicenses/any(s:s/skuId eq 184efa21-98c3-4e5d-95ab-
d07053a96e67)
To negate the result of the expression inside the any clause, use the not operator, not
the ne operator. For example, the following query retrieves only users who aren't
assigned the imAddress of [email protected] .
Note: For directory objects like users, the not and ne operators are supported only
in advanced queries.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?
$filter=NOT(imAddresses/any(i:i eq '[email protected]'))&$count=true
ConsistencyLevel: eventual
all operator
The all operator applies a Boolean expression to each member of a collection and
returns true if the expression is true for all the items of the collection, otherwise it
returns false . It isn't supported by any property.
7 Note
Examples marked with * are only supported with advanced query capabilities.
Click the examples to try them in Graph Explorer.
Description Example
Get all the signed-in user's events that GET ~/me/events?$filter=start/dateTime ge '2017-07-
start after 7/1/2017. 01T08:00' .
NOTE: The dateTime property is a String type.
Get all users in the Retail and Sales GET ~/users?$filter=department in ('Retail', 'Sales')
departments.
List all users whose company name GET ~/users?$filter=companyName ne null and
isn't undefined (that is, not a null NOT(companyName eq 'Microsoft')&$count=true *
value) or Microsoft.
These examples show how to use $filter to match against supported properties and
relationships that are primitive types, complex types, enumeration types, or a collection
of one of these types.
7 Note
Examples marked with * are only supported with advanced query capabilities.
Operator Syntax
eq ~/users?$filter=userType eq 'Member'
ne ~/users?$filter=companyName ne null *
endsWith ~/users?$filter=endsWith(mail,'@outlook.com') *
in ~/users?$filter=userType in ('Guest')
le ~/devices?$filter=registrationDateTime le 2021-01-02T12:00:00Z *
ge ~/devices?$filter=registrationDateTime ge 2021-01-02T12:00:00Z *
contains ~/identityGovernance/accessReviews/definitions?
$filter=contains(scope/microsoft.graph.accessReviewQueryScope/query,
'./members')
eq ~/groups?$filter=groupTypes/any(c:c eq 'Unified')
Operator (s) Syntax
ne ~/users?$filter=companyName ne null *
startsWith ~/users?$filter=businessPhones/any(p:startsWith(p,
'44')) *
endsWith ~/users?$filter=endsWith(mail,'@outlook.com') *
For the list of all properties of directory objects that support count of a collection in a
filter expression, see Count of a collection in a filter expression.
Operator Syntax
(s)
eq ~/servicePrincipals?$filter=appOwnerOrganizationId eq 72f988bf-86f1-41af-91ab-
2d7cd011db47 *
eq ~/devices?$filter=alternativeSecurityIds/any(a:a/type eq 2) *
le ~/devices?$filter=alternativeSecurityIds/any(a:a/type le 2) *
ge ~/devices?$filter=alternativeSecurityIds/any(a:a/type ge 2) *
Operator Syntax
(s)
eq ~/users?$filter=authorizationInfo/certificateUserIds/any(x:x eq
'9876543210@mil') *
startsWith ~/users?
$filter=authorizationInfo/certificateUserIds/any(x:startswith(x,'987654321')) *
endsWith ~/users?$filter=proxyAddresses/any(p:endsWith(p,'OnMicrosoft.com')) *
See also
Advanced query capabilities on Azure AD directory objects
Use the $search query parameter
Article • 03/02/2023
In addition to other OData query parameters, Microsoft Graph supports the $search query parameter
to restrict the results of a request to match a search criterion.
The support for the $search query parameter varies by entity, with some, such as Azure AD resources
that derive from directoryObject, supporting $search only in advanced queries.
7 Note
The $search query parameter is currently not available in Azure AD B2C tenants.
If you do a search on messages and specify only a value without specific message properties, the
search is carried out on the default search properties of from, subject, and body.
The following example returns all messages in the signed-in user's Inbox that contains "pizza" in any
of the three default search properties:
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/messages?$search="pizza"
Alternatively, you can search messages by specifying message property names in the following table,
that are recognized by the Keyword Query Language (KQL) syntax. These property names correspond
to properties defined in the message entity of Microsoft Graph. Outlook and other Microsoft 365
applications such as SharePoint support KQL syntax, providing the convenience of a common
discovery domain for their data stores.
For more information about searchable email properties, KQL syntax, supported operators, and tips
on searching, see the following articles:
Message properties and search operators for In-Place eDiscovery in Exchange 2016
Searches on people occur on both the displayName and emailAddress properties of the person
resource.
The following request does a search for a person named "Irene McGowen" in the displayName and
emailAddress properties in each person in the people collection of the signed-in user. Because a
person named "Irene McGowan" is relevant to the signed-in user, the information for "Irene
McGowan" is returned.
HTTP
HTTP
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "C0BD1BA1-A84E-4796-9C65-F8A0293741D1",
"displayName": "Irene McGowan",
"givenName": "Irene",
"surname": "McGowan",
"birthday": "",
"personNotes": "",
"isFavorite": false,
"jobTitle": "Auditor",
"companyName": null,
"yomiCompany": "",
"department": "Finance",
"officeLocation": "12/1110",
"profession": "",
"userPrincipalName": "[email protected]",
"imAddress": "sip:[email protected]",
"scoredEmailAddresses": [
{
"address": "[email protected]",
"relevanceScore": -16.446060612802224
}
],
"phones": [
{
"type": "Business",
"number": "+1 412 555 0109"
}
],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
}
]
}
To learn more about the People API, see Get information about relevant people.
⁽¹⁾ Currently, tokenization only works when the casing is changing from lowercase to uppercase, so
HELLOworld is considered a single token: helloworld , and HelloWORld is two tokens: hello , world . ⁽²⁾
Tokenization logic also combines words that are separated only by symbols; for example, searching
for helloworld will find hello-world and hello.world .
7 Note
After tokenization, the tokens are matched independently of the original casing, and they
are matched in any order. For example, displayName 李四(David Li) will match search
strings such as 李四(David Li) , 李四 , David , Li , David) , (李四 , Li 李 .
The tokenized search support works only on the displayName and description fields. Any
field of String type can be put in $search ; fields other than displayName and description
default to $filter startswith behavior. For example:
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/groups/?$search="displayName:OneVideo" OR
"mail:onevideo"
ConsistencyLevel: eventual
This looks for all groups with display names that has one and video tokens, or mail starting with
onevideo .
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/groups/?$filter=mailEnabled eq
true&$search="displayName:OneVideo"
ConsistencyLevel: eventual
This looks for all mail-enabled groups with display names that look like "OneVideo". The results are
restricted based on a logical conjunction (an "AND") of the $filter and the entire query in the
$search .
Both the string inputs you provide in $search , as well as the searchable properties, are split up into
parts by spaces, different casing, and character types (numbers and special characters).
See also
Use query parameters to customize responses
Advanced query capabilities on Azure AD directory objects
Query parameter limitations
Advanced query capabilities on Azure
AD objects
Article • 04/26/2023
As Azure Active Directory (Azure AD) continues to deliver more capabilities and
improvements in stability, availability, and performance, Microsoft Graph also continues
to evolve and scale to efficiently access the data. One way is through Microsoft Graph's
increasing support for advanced query capabilities on various Azure Active Directory
(Azure AD) objects, also called directory objects, and their properties. For example, the
addition of not ( not ), not equals ( ne ), and ends with ( endsWith ) operators on the
$filter query parameter.
The Microsoft Graph query engine uses an index store to fulfill query requests. To add
support for additional query capabilities on some properties, these properties are now
indexed in a separate store. This separate indexing allows Azure AD to increase support
and improve the performance of the query requests. However, these advanced query
capabilities are not available by default but, the requestor must also set the
ConsistencyLevel header to eventual and, with the exception of $search , use the
$count query parameter. The ConsistencyLevel header and $count are referred to as
advanced query parameters.
For example, to retrieve only inactive user accounts, you can run either of these queries
that use the $filter query parameter.
Option 1: Use the $filter query parameter with the eq operator. This request will work
by default, that is, the request does not require the advanced query parameters.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?$filter=accountEnabled eq
false
Option 2: Use the $filter query parameter with the ne operator. This request is not
supported by default because the ne operator is only supported in advanced queries.
Therefore, you must add the ConsistencyLevel header set to eventual and use the
$count=true query string.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?$filter=accountEnabled ne
true&$count=true
ConsistencyLevel: eventual
Object Relationships
administrativeUnit members
application owners
appRoleAssignment -
device memberOf
transitiveMemberOf
registeredUsers
registeredOwners
group members
transitiveMembers
memberOf
transitiveMemberOf
owners
appRoleAssignments
orgContact memberOf
transitiveMemberOf
servicePrincipal memberOf
transitiveMemberOf
appRoleAssignments
appRoleAssignmentsTo
oAuth2PermissionGrant
Object Relationships
user memberOf
transitiveMemberOf
ownedObjects
registeredDevices
ownedDevices
transitiveManagers
directReports
transitiveReports
appRoleAssignments
oAuth2PermissionGrant
Description Example
7 Note
The advanced query capabilities are currently not available for Azure AD B2C
tenants.
To use advanced query capabilities in batch requests, specify the
ConsistencyLevel header in the JSON body of the POST request.
Queries that are supported by default will also work with advanced query
parameters, but the response will be eventually consistent.
The in operator is supported by default whenever eq operator is supported by
default.
The endsWith operator is supported only with advanced query parameters by mail,
otherMails, userPrincipalName, and proxyAddresses properties.
Getting empty collections ( /$count eq 0 , /$count ne 0 ) and collections with less
than one object ( /$count eq 1 , /$count ne 1 ) is supported only with advanced
query parameters.
The not and ne negation operators are supported only with advanced query
parameters.
All properties that support the eq operator also support the ne or not
operators.
For queries that use the any lambda operator, use the not operator. See Filter
using lambda operators.
Legend
description
displayName
isMemberManagementRestricted
scopedRoleMembers/any(s:s/id)
Application properties
Property eq startsWith ge/le eq Null
Property eq startsWith ge/le eq Null
appId
createdDateTime
createdOnBehalfOf/id
description
disabledByMicrosoftStatus
displayName
federatedIdentityCredentials/any(f:f/issuer)
federatedIdentityCredentials/any(f:f/name)
federatedIdentityCredentials/any(f:f/subject)
identifierUris/any(p:p)
info/logoUrl
info/termsOfServiceUrl
publicClient/redirectUris/any(p:p)
publisherDomain
requiredResourceAccess/any(r:r/resourceAppId)
serviceManagementReference
signInAudience
spa/redirectUris/any(p:p)
tags/any(p:p)
uniqueName
verifiedPublisher/displayName
Property eq startsWith ge/le eq Null
web/homePageUrl
web/redirectUris/any(p:p)
extensionProperties/$count
federatedIdentityCredentials/$count
owners/$count
Contract properties
Property eq startsWith
customerId
defaultDomainName
displayName
Device properties
Property eq startsWith ge/le eq Null
accountEnabled
alternativeSecurityIds/any(a:a/identityProvider)
alternativeSecurityIds/any(a:a/type)
approximateLastSignInDateTime
deviceId
Property eq startsWith ge/le eq Null
displayName
extensionAttributes/extensionAttribute1
extensionAttributes/extensionAttribute10
extensionAttributes/extensionAttribute11
extensionAttributes/extensionAttribute12
extensionAttributes/extensionAttribute13
extensionAttributes/extensionAttribute14
extensionAttributes/extensionAttribute15
extensionAttributes/extensionAttribute2
extensionAttributes/extensionAttribute3
extensionAttributes/extensionAttribute4
extensionAttributes/extensionAttribute5
extensionAttributes/extensionAttribute6
extensionAttributes/extensionAttribute7
extensionAttributes/extensionAttribute8
extensionAttributes/extensionAttribute9
hostnames/any(p:p)
isCompliant
isManaged
mdmAppId
onPremisesLastSyncDateTime
Property eq startsWith ge/le eq Null
onPremisesSyncEnabled
operatingSystem
operatingSystemVersion
physicalIds/any(p:p)
profileType
registrationDateTime
trustType
The following properties of the device entity support $count of a collection in a filter
expression.
physicalIds/$count
systemLabels/$count
description
displayName
roleTemplateId
Group properties
Property eq startsWith ge/le eq
Null
appRoleAssignments/any(a:a/id)
Property eq startsWith ge/le eq
Null
assignedLicenses/any(a:a/skuId)
classification
createdByAppId
createdOnBehalfOf/id
description
displayName
expirationDateTime
hasMembersWithLicenseErrors
infoCatalogs/any(p:p)
isAssignableToRole
mailEnabled
mailNickname
membershipRule
membershipRuleProcessingState
onPremisesLastSyncDateTime
onPremisesProvisioningErrors/any(o:o/category)
onPremisesProvisioningErrors/any(o:o/propertyCausingError)
onPremisesSamAccountName
onPremisesSecurityIdentifier
onPremisesSyncEnabled
Property eq startsWith ge/le eq
Null
preferredLanguage
proxyAddresses/any(p:p)
renewedDateTime
resourceBehaviorOptions/any(p:p)
resourceProvisioningOptions/any(p:p)
securityEnabled
settings/any(s:s/displayName)
settings/any(s:s/id)
The following properties of the group entity support $count of a collection in a filter
expression.
onPremisesProvisioningErrors/$count
proxyAddresses/$count
companyName
department
displayName
givenName
jobTitle
Property eq startsWith ge/le eq
Null
mailNickname
manager/id
onPremisesLastSyncDateTime
onPremisesProvisioningErrors/any(o:o/category)
onPremisesProvisioningErrors/any(o:o/propertyCausingError)
onPremisesSyncEnabled
proxyAddresses/any(p:p)
surname
onPremisesProvisioningErrors/$count
proxyAddresses/$count
accountEnabled
alternativeNames/any(p:p)
appId
appOwnerOrganizationId
appRoleAssignedTo/any(a:a/id)
Property eq startsWith ge/le eq Null
appRoleAssignmentRequired
appRoleAssignments/any(a:a/id)
applicationTemplateId
createdObjects/any(c:c/id)
delegatedPermissionClassifications/any(d:d/id)
description
displayName
federatedIdentityCredentials/any(f:f/issuer)
federatedIdentityCredentials/any(f:f/name)
federatedIdentityCredentials/any(f:f/subject)
homepage
info/logoUrl
info/termsOfServiceUrl
oauth2PermissionGrants/any(o:o/id)
preferredSingleSignOnMode
preferredTokenSigningKeyEndDateTime
publisherName
servicePrincipalNames/any(p:p)
servicePrincipalType
tags/any(p:p)
verifiedPublisher/displayName
The following properties of the servicePrincipal entity support $count of a collection in
a filter expression.
federatedIdentityCredentials/$count
User properties
Property eq startsWith ge/le eq
Null
accountEnabled
ageGroup
appRoleAssignments/any(a:a/id)
assignedLicenses/any(a:a/skuId)
assignedPlans/any(a:a/capabilityStatus)
assignedPlans/any(a:a/service)
assignedPlans/any(a:a/servicePlanId)
authorizationInfo/certificateUserIds/any(p:p)
businessPhones/any(p:p)
city
companyName
consentProvidedForMinor
country
createdDateTime
createdObjects/any(c:c/id)
creationType
Property eq startsWith ge/le eq
Null
department
displayName
employeeHireDate
employeeId
employeeOrgData/costCenter
employeeOrgData/division
employeeType
externalUserState
faxNumber
givenName
identities/any(i:i/issuer)
imAddresses/any(p:p)
infoCatalogs/any(p:p)
isResourceAccount
jobTitle
licenseDetails/any(l:l/id)
mailNickname
manager/id
mobilePhone
oauth2PermissionGrants/any(o:o/id)
Property eq startsWith ge/le eq
Null
officeLocation
onPremisesExtensionAttributes/extensionAttribute1
onPremisesExtensionAttributes/extensionAttribute10
onPremisesExtensionAttributes/extensionAttribute11
onPremisesExtensionAttributes/extensionAttribute12
onPremisesExtensionAttributes/extensionAttribute13
onPremisesExtensionAttributes/extensionAttribute14
onPremisesExtensionAttributes/extensionAttribute15
onPremisesExtensionAttributes/extensionAttribute2
onPremisesExtensionAttributes/extensionAttribute3
onPremisesExtensionAttributes/extensionAttribute4
onPremisesExtensionAttributes/extensionAttribute5
onPremisesExtensionAttributes/extensionAttribute6
onPremisesExtensionAttributes/extensionAttribute7
onPremisesExtensionAttributes/extensionAttribute8
onPremisesExtensionAttributes/extensionAttribute9
onPremisesImmutableId
onPremisesLastSyncDateTime
onPremisesProvisioningErrors/any(o:o/category)
onPremisesProvisioningErrors/any(o:o/propertyCausingError)
onPremisesSamAccountName
Property eq startsWith ge/le eq
Null
onPremisesSecurityIdentifier
onPremisesSyncEnabled
otherMails/any(p:p)
passwordPolicies
passwordProfile/forceChangePasswordNextSignIn
passwordProfile/forceChangePasswordNextSignInWithMfa
postalCode
preferredLanguage
provisionedPlans/any(p:p/provisioningStatus)
provisionedPlans/any(p:p/service)
proxyAddresses/any(p:p)
scopedRoleMemberOf/any(s:s/id)
showInAddressList
state
streetAddress
surname
usageLocation
userPrincipalName
userType
The following table shows support for $filter by other extension properties on the
user object.
Extension type eq startsWith eq null
Schema extensions
Open extensions
Directory extensions
The following properties of the user entity support $count of a collection in a filter
expression.
assignedLicenses/$count
onPremisesProvisioningErrors/$count
otherMails/$count
ownedObjects/$count
proxyAddresses/$count
Legend
administrativeUnit createdDateTime
administrativeUnit deletedDateTime
administrativeUnit displayName
application createdDateTime
application deletedDateTime
application displayName
orgContact createdDateTime
orgContact displayName
device approximateLastSignInDateTime
device createdDateTime
device deletedDateTime
device displayName
group deletedDateTime
group displayName
servicePrincipal createdDateTime
servicePrincipal deletedDateTime
servicePrincipal displayName
user createdDateTime
user deletedDateTime
user displayName
user userPrincipalName
Error handling for advanced queries on
directory objects
Counting directory objects is only supported using the advanced queries parameters. If
the ConsistencyLevel=eventual header is not specified, the request returns an error
when the $count URL segment is used or silently ignores the $count query parameter ( ?
$count=true ) if it's used.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users/$count
JSON
{
"error": {
"code": "Request_BadRequest",
"message": "$count is not currently supported.",
"innerError": {
"date": "2021-05-18T19:03:10",
"request-id": "d9bbd4d8-bb2d-44e6-99a1-71a9516da744",
"client-request-id": "539da3bd-942f-25db-636b-27f6f6e8eae4"
}
}
}
For directory objects, $search works only in advanced queries. If the ConsistencyLevel
header is not specified, the request returns an error.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/applications?
$search="displayName:Browser"
JSON
{
"error": {
"code": "Request_UnsupportedQuery",
"message": "Request with $search query parameter only works through
MSGraph with a special request header: 'ConsistencyLevel: eventual'",
"innerError": {
"date": "2021-05-27T14:26:47",
"request-id": "9b600954-ba11-4899-8ce9-6abad341f299",
"client-request-id": "7964ef27-13a3-6ca4-ed7b-73c271110867"
}
}
}
If a property or query parameter in the URL is supported only in advanced queries but
either the ConsistencyLevel header or the $count=true query string is missing, the
request returns an error.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?
$filter=endsWith(mail,'@outlook.com')
JSON
{
"error": {
"code": "Request_UnsupportedQuery",
"message": "Unsupported Query.",
"innerError": {
"date": "2021-05-18T19:12:36",
"request-id": "63f2093c-399c-4350-9609-3ce9b62abe3c",
"client-request-id": "e60ed0ba-df5d-e190-f056-f9c0318456d7"
}
}
}
If a property has not been indexed to support a query parameter, even if the advanced
query parameters are specified, the request returns an error.
HTTP
HTTP
GET https://graph.microsoft.com/beta/groups?$filter=createdDateTime ge
2021-11-01&$count=true
ConsistencyLevel: eventual
JSON
{
"error": {
"code": "Request_UnsupportedQuery",
"message": "The request uses a filter property that is not indexed",
"innerError": {
"date": "2021-06-10T19:32:01",
"request-id": "5625ba13-0c9f-4fce-a853-4b52f3e0bd09",
"client-request-id": "76fe4cd8-df3a-f8c3-659b-594274b6bb31"
}
}
}
However, it is important to note that query parameters specified in a request might fail
silently. This can be true for unsupported query parameters as well as for unsupported
combinations of query parameters. In these cases, you should examine the data
returned by the request to determine whether the query parameters you specified had
the desired effect. For example, in the following example, the @odata.count parameter is
missing even if the query is successful.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?$count=true
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users",
"value":[
{
"displayName":"Oscar Ward",
"mail":"[email protected]",
"userPrincipalName":"[email protected]"
},
]
}
See also
Use query parameters to customize responses
Query parameter limitations
Use the $search query parameter to match a search criterion
Explore advanced query capabilities for Azure AD objects with the .NET SDK
Combine multiple requests in one HTTP
call using JSON batching
Article • 01/27/2023
JSON batching allows you to optimize your application by combining multiple requests
(up to 20) into a single JSON object. For example, a client might want to compose a view
of unrelated data such as:
Combining these three individual requests into a single batch request can save the
application significant network latency.
Microsoft Graph implements the $batch OData URL path segment to support JSON
batching.
https://www.youtube-nocookie.com/embed/tzWGOp8zYh8
HTTP
POST https://graph.microsoft.com/v1.0/$batch
Accept: application/json
Content-Type: application/json
{
"requests": [
{
"id": "1",
"method": "GET",
"url": "/me/drive/root:/{file}:/content"
},
{
"id": "2",
"method": "GET",
"url": "/me/planner/tasks"
},
{
"id": "3",
"method": "GET",
"url": "/groups/{id}/events"
},
{
"id": "4",
"url": "/me",
"method": "PATCH",
"body": {
"city" : "Redmond"
},
"headers": {
"Content-Type": "application/json"
}
},
{
"id": "5",
"url": "users?$select=id,displayName,userPrincipalName&$filter=city eq
null&$count=true",
"method": "GET",
"headers": {
"ConsistencyLevel": "eventual"
}
}
]
}
Responses to the batched requests might appear in a different order. The id property
can be used to correlate individual requests and responses.
HTTP
200 OK
Content-Type: application/json
{
"responses": [
{
"id": "1",
"status": 302,
"headers": {
"location": "https://b0mpua-
by3301.files.1drv.com/y23vmagahszhxzlcvhasdhasghasodfi"
}
},
{
"id": "3",
"status": 401,
"body": {
"error": {
"code": "Forbidden",
"message": "..."
}
}
},
{
"id": "5",
"status": 200,
"headers": {
"OData-Version": "4.0",
},
"body": {
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users(id,displayName,userPrincip
alName)",
"@odata.count": 12,
"value": [
{
"id": "071cc716-8147-4397-a5ba-b2105951cc0b",
"displayName": "Adele Vance",
"userPrincipalName": "[email protected]"
}
]
}
},
{
"id": "2",
"status": 200,
"body": {
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.plann
erTask)",
"value": []
}
},
{
"id": "4",
"status": 204,
"body": null
}
]
}
Request format
Batch requests are always sent using a POST to the /$batch endpoint.
A JSON batch request body consists of a single JSON object with one required property:
requests. The requests property is a collection of individual requests. For each individual
request, the following properties can be passed.
Property Description
Property Description
url Required. The relative resource URL the individual request would typically be sent to.
Therefore, while the absolute URL is https://graph.microsoft.com/v1.0/users , this url
is /users .
headers Optional but required when the body is specified. A JSON object with the key/value
pair for the headers. For example, when the ConsistencyLevel header is required, this
property would be represented as "headers": {"ConsistencyLevel": "eventual"} .
When the body is supplied, a Content-Type header must be included.
body Optional. Might be a JSON object or a base64 URL-encoded value for example, when
the body is an image. When a body is included with the request, the headers object
must contain a value for Content-Type.
Response format
The response format for JSON batch requests is similar to the request format. The
following are the key differences:
The property in the main JSON object is named responses as opposed to requests.
Individual responses might appear in a different order than the requests.
Rather than method and url, individual responses have a status property. The
value of status is a number that represents the HTTP status code.
The headers property in each individual response represents the headers returned
by the server, for example, Cache-Control and Content-Type headers.
The status code on a batch response is typically 200 or 400 . If the batch request itself is
malformed, the status code is 400 . If the batch request is parseable, the status code is
200 . A 200 status code on the batch response does not indicate that the individual
requests inside the batch succeeded. This is why each individual response in the
responses property has a status code.
JSON
{
"requests": [
{
"id": "1",
"method": "GET",
"url": "..."
},
{
"id": "2",
"dependsOn": [ "1" ],
"method": "GET",
"url": "..."
},
{
"id": "4",
"dependsOn": [ "2" ],
"method": "GET",
"url": "..."
},
{
"id": "3",
"dependsOn": [ "4" ],
"method": "GET",
"url": "..."
}
]
}
If an individual request fails, any request that depends on that request fails with status
code 424 (Failed Dependency).
Tip
Depending on the APIs that are part of the batch request, the underlying services
impose their own throttling limits that affect applications that use Microsoft Graph
to access them.
Requests in a batch are evaluated individually against throttling limits and if any
request exceeds the limits, it fails with a status of 429 .
Known issues
For a list of current limitations related to batching, see known issues.
See also
For more information about the JSON batch request/response format, see the OData
JSON Format Version 4.01 specification , section Batch Requests and Responses.
Microsoft Graph throttling guidance
Article • 02/07/2023
Throttling limits vary based on the scenario. For example, if you are performing a large
volume of writes, the possibility for throttling is higher than if you are only performing
reads.
7 Note
Solutions that need to extract a large volume of data from Microsoft Graph should
use Microsoft Graph Data Connect instead of the Microsoft Graph REST APIs.
Microsoft Graph Data Connect allows organizations to extract Microsoft 365 data in
bulk without being subject to throttling limits.
https://www.youtube-nocookie.com/embed/J4CFxVuzNMA
HTTP
{
"error": {
"code": "TooManyRequests",
"innerError": {
"code": "429",
"date": "2020-08-18T12:51:51",
"message": "Please retry after",
"request-id": "94fb3b52-452a-4535-a601-69e0a90e3aa2",
"status": "429"
},
"message": "Please retry again later."
}
}
When you implement error handling, use the HTTP error code 429 to detect throttling.
The failed response includes the Retry-After response header. Backing off requests
using the Retry-After delay is the fastest way to recover from throttling because
Microsoft Graph continues to log resource usage while a client is being throttled.
For a broader discussion of throttling in the Microsoft Cloud, see Throttling pattern.
7 Note
Microsoft Graph SDKs already implement handlers that rely on the Retry-After
header or default to an exponential backoff retry policy.
7 Note
Best practices for discovering files and detecting changes at scale describes best
practices in details.
If SDKs retry throttled requests automatically when they are not batched, throttled
requests that were part of a batch are not retried automatically.
Next steps
Identify the throttling limits that apply for each Microsoft Graph resource.
Training module: Optimize network traffic with Microsoft Graph
Microsoft Graph service-specific throttling limits
Article • 02/16/2023
Microsoft Graph allows you to access data in multiple services, such as Outlook or Azure Active Directory. These services
impose their own throttling limits that affect applications that use Microsoft Graph to access them.
Any request can be evaluated against multiple limits, depending on the scope of the limit (per app across all tenants, per
tenant for all apps, per app per tenant, and so on), the request type (GET, POST, PATCH, and so on), and other factors. The first
limit to be reached triggers throttling behavior. In addition to the service specific-limits described in the section, the following
global limits apply:
7 Note
In this section, the term tenant refers to the Microsoft 365 organization where the application is installed. This tenant can
be the same as the one where the application was created in the case of a single-tenant application, or it can be different
in the case of a multi-tenant application.
Request Type Limit per app per tenant Limit per tenant for all apps
Any 15000 requests per 3600 seconds 30000 requests per 3600 seconds
educationAssignment
educationSubmission
trending
educationResource
callRecord
Limit type Limit
Request type Limit per app for all tenants Limit per app per tenant
workbook workbookChartTitleFormat
workbookApplication workbookComment
workbookChart workbookCommentReply
workbookChartAreaFormat workbookFilter
workbookChartAxes workbookFormatProtection
workbookChartAxis workbookNamedItem
workbookChartAxisFormat workbookOperation
workbookChartAxisTitle workbookPivotTable
workbookChartAxisTitleFormat workbookRange
workbookChartDataLabelFormat workbookRangeBorder
workbookChartDataLabels workbookRangeFill
workbookChartFill workbookRangeFont
workbookChartFont workbookRangeFormat
workbookChartGridlines workbookRangeSort
workbookChartGridlinesFormat workbookRangeView
workbookChartLegend workbookTable
workbookChartLegendFormat workbookTableColumn
workbookChartLineFormat workbookTableRow
workbookChartPoint workbookTableSort
workbookChartPointFormat workbookWorksheet
workbookChartSeries workbookWorksheetProtection
workbookChartSeriesFormat
workbookChartTitle
educationClass educationSchool
educationCourse educationStudent
educationOnPremisesInfo educationTeacher
educationOrganization educationTerm
educationRelatedContact educationUser
educationRoot
Files and lists service limits
For service limits for OneDrive, OneDrive for Business, and SharePoint Online, see Avoid getting throttled or blocked in
SharePoint Online.
baseItem itemActivityStat
baseItemVersion itemAnalytics
columnDefinition list
columnLink listItem
contentType listItemVersion
drive permission
driveItem sharedDriveItem
driveItemVersion site
fieldValueSet thumbnailSet
itemActivity
applicationSignInDetailedSummary credentialUserRegistrationDetails
applicationSignInSummary directoryAudit
auditLogRoot provisioningObjectSummary
authenticationMethod relyingPartyDetailedSummary
azureADUserFeatureUsage signIn
credentialUsageSummary userCredentialUsageDetails
credentialUserRegistrationCount
Use filters to target your query to just the data you need. If you only need a certain type of event or a subset of users, for
example, filter out other events using the $filter and $select query parameters to reduce the size of your response
object and the risk of throttling.
If you need a broad set of Azure AD reporting data, use $filter on the createdDateTime to limit the amount of sign-in
events you query in a single call. Then, iterate through the next timespan until you have all the records you need. For
example, if you are being throttled, you can begin with a call that requests 3 days of data and iterate with shorter
timespans until your requests are no longer throttled.
Pattern
Throttling is based on a token bucket algorithm, which works by adding individual costs of requests. The sum of request costs
is then compared against pre-determined limits. Only the requests exceeding the limits will be throttled. If any of the limits are
exceeded, the response will be 429 Too Many Requests . It is possible to receive 429 Too Many Requests responses even when
the following limits are not reached, in situations when the services are under an important load or based on data volume for
a specific tenant. The following table lists existing limits.
application+tenant pair S: 3,500 requests per 10 seconds 3,000 requests per 2 minutes and 30 seconds
M: 5,000 requests per 10 seconds
L: 8,000 requests per 10 seconds
7 Note
The application + tenant pair limit varies based on the number of users in the tenant requests are run against. The tenant
sizes are defined as follows: S - under 50 users, M - between 50 and 500 users, and L - above 500 users.
application groupSettingTemplate
contract groupSetting
device group
directoryObjectPartnerReference homeRealmDiscoveryPolicy
directoryObject licenseDetails
directoryRoleTemplate oauth2PermissionGrant
directoryRole organization
domainDnsCnameRecord orgContact
domainDnsMxRecord policyBase
domainDnsRecord servicePrincipal
domainDnsSrvRecord stsPolicy
domainDnsTxtRecord subscribedSku
domainDnsUnavailableRecord tokenIssuancePolicy
domain tokenLifetimePolicy
endpoint user
extensionProperty
The following table lists base request costs. Any requests not listed have a base cost of 1.
GET applications 2 0
GET applications/{id}/extensionProperties 2 0
GET contracts 3 0
POST directoryObjects/getByIds 3 0
GET domains/{id}/domainNameReferences 4 0
POST getObjectsById 3 0
GET groups/{id}/members 3 0
GET groups/{id}/transitiveMembers 5 0
POST isMemberOf 4 0
POST me/checkMemberGroups 4 0
POST me/checkMemberObjects 4 0
Operation Request Path Base Resource Unit Cost Write Cost
POST me/getMemberGroups 2 0
POST me/getMemberObjects 2 0
GET me/licenseDetails 2 0
GET me/memberOf 2 0
GET me/ownedObjects 2 0
GET me/transitiveMemberOf 2 0
GET oauth2PermissionGrants 2 0
GET oauth2PermissionGrants/{id} 2 0
GET servicePrincipals/{id}/appRoleAssignments 2 0
GET subscribedSkus 3 0
GET users 2 0
) Important
The cost of POST, PATCH, and DELETE operations on the applications request path depends on the signInAudience type.
For apps where the signInAudience is AzureADMyOrg or AzureADMultipleOrgs , the cost is 70,000 requests per 5 minutes;
while for apps where the signInAudience is AzureADandPersonalMicrosoftAccount or PersonalMicrosoftAccount , the cost is
60 requests per minute.
7 Note
A request cost can never be lower than 1. Any request cost that applies to a request path starting with me/ also applies to
equivalent requests starting with users/{id | userPrincipalName}/ .
Additional headers
Request headers
x-ms-throttle-priority - If the header doesn't exist or is set to any other value, it indicates a normal request. We
recommend setting priority to high only for the requests initiated by the user. The values of this header can be the
following:
Low - Indicates the request is low priority. Throttling this request doesn't cause user-visible failures.
Normal - Default if no value is provided. Indicates that the request is default priority.
High - Indicates that the request is high priority. Throttling this request causes user-visible failures.
7 Note
Should requests be throttled, low priority requests will be throttled first, normal priority requests second, and high
priority requests last. Using the priority request header does not change the limits.
POST on exportPersonalData 1000 requests per day for any subject and 100 per subject per day
dataPolicyOperation
7 Note
The resources listed earlier do not return a Retry-After header on 429 Too Many Requests responses.
riskDetection
riskyUser
riskyUserHistoryItem
namedLocation
countryNamedLocation
ipNamedLocation
conditionalAccessPolicy
7 Note
The resources listed earlier do not return a Retry-After header on 429 Too Many Requests responses.
assignmentOrder identityUserFlowAttribute
authenticationFlowsPolicy identityUserFlowAttributeAssignment
b2cAuthenticationMethodsPolicy openIdConnectIdentityProvider
b2cIdentityUserFlow openIdConnectProvider
b2xIdentityUserFlow socialIdentityProvider
builtInIdentityProvider trustFrameworkKeySet
identityApiConnector trustFrameworkPolicy
identityBuiltInUserFlowAttribute userFlowLanguageConfiguration
identityCustomUserFlowAttribute userFlowLanguagePage
identityProvider
identityUserFlow
For email, the resource is a unique network message ID/recipient pair. For example, submitting an email with the same
message ID sent to the same person multiple times in a 15 minute period will trigger the limit per resource limits lited in the
following table. However, you can submit up to 150 unique emails every 15 minutes (tenant limit).
Operation Limit per tenant Limit per resource (email, URL, file)
POST 150 requests per 15 minutes and 10000 requests per 24 hours 1 request per 15 minutes and 3 requests per 24 hours
threatAssessmentRequest
threatAssessmentResult
mailAssessmentRequest
emailFileAssessmentRequest
fileAssessmentRequest
urlAssessmentRequest
Insights service limits
The following limits apply to any request on me/insights or users/{id}/insights .
Limit Applies to
people
sharedInsight
trending
usedInsight
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
microsoftTunnelConfiguration
microsoftTunnelHealthThreshold
microsoftTunnelServer
microsoftTunnelServerLogCollectionResponse
microsoftTunnelSite
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
androidDeviceOwnerEnrollmentProfile
androidForWorkAppConfigurationSchema
androidForWorkEnrollmentProfile
androidForWorkSettings
androidManagedStoreAccountEnterpriseSettings
androidManagedStoreAppConfigurationSchema
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
androidForWorkApp managedIOSStoreApp
androidForWorkMobileAppConfiguration managedMobileLobApp
androidLobApp microsoftStoreForBusinessApp
androidManagedStoreApp microsoftStoreForBusinessContainedApp
androidManagedStoreAppConfiguration mobileApp
androidManagedStoreWebApp mobileAppAssignment
androidStoreApp mobileAppCategory
enterpriseCodeSigningCertificate mobileAppContent
iosLobApp mobileAppContentFile
iosLobAppProvisioningConfiguration mobileAppDependency
iosLobAppProvisioningConfigurationAssignment mobileAppInstallStatus
iosMobileAppConfiguration mobileAppInstallSummary
iosStoreApp mobileAppProvisioningConfigGroupAssignment
iosVppApp mobileAppRelationship
iosVppAppAssignedDeviceLicense mobileAppSupersedence
iosVppAppAssignedLicense mobileContainedApp
iosVppAppAssignedUserLicense mobileLobApp
macOSLobApp officeSuiteApp
macOSMdatpApp symantecCodeSigningCertificate
macOSMicrosoftEdgeApp userAppInstallStatus
macOSOfficeSuiteApp webApp
macOsVppApp win32LobApp
macOsVppAppAssignedLicense windowsAppX
managedAndroidLobApp windowsMicrosoftEdgeApp
managedAndroidStoreApp windowsMobileMSI
managedApp windowsPhone81AppX
managedDeviceMobileAppConfiguration windowsPhone81AppXBundle
managedDeviceMobileAppConfigurationAssignment windowsPhone81StoreApp
managedDeviceMobileAppConfigurationDeviceStatus windowsPhoneXAP
managedDeviceMobileAppConfigurationDeviceSummary windowsStoreApp
managedDeviceMobileAppConfigurationUserStatus windowsUniversalAppX
managedDeviceMobileAppConfigurationUserSummary windowsUniversalAppXContainedApp
managedIOSLobApp
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
auditEvent
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
assignmentFilterEvaluationStatusDetails managedDeviceMobileAppConfigurationPolicySetItem
deviceAndAppManagementAssignmentFilter mdmWindowsInformationProtectionPolicyPolicySetItem
deviceCompliancePolicyPolicySetItem mobileAppPolicySetItem
deviceConfigurationPolicySetItem policySet
deviceManagementConfigurationPolicyPolicySetItem policySetAssignment
deviceManagementScriptPolicySetItem policySetItem
enrollmentRestrictionsConfigurationPolicySetItem targetedManagedAppConfigurationPolicySetItem
iosLobAppProvisioningConfigurationPolicySetItem, windows10EnrollmentCompletionPageConfigurationPolicySetItem
managedAppProtectionPolicySetItem windowsAutopilotDeploymentProfilePolicySetItem
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
chromeOSOnboardingSettings
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
termsAndConditions
termsAndConditionsAcceptanceStatus
termsAndConditionsAssignment
termsAndConditionsGroupAssignment
Intune device config v2 service limits
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
deviceManagementConfigurationCategory deviceManagementConfigurationSettingDefinition
deviceManagementConfigurationChoiceSettingCollectionDefinition deviceManagementConfigurationSettingGroupCollectionDefinition
deviceManagementConfigurationChoiceSettingDefinition deviceManagementConfigurationSettingGroupDefinition
deviceManagementConfigurationPolicy deviceManagementConfigurationSettingTemplate
deviceManagementConfigurationPolicyAssignment deviceManagementConfigurationSimpleSettingCollectionDefinition
deviceManagementConfigurationPolicyTemplate deviceManagementConfigurationSimpleSettingDefinition
deviceManagementConfigurationSetting deviceManagementReusablePolicySetting
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
advancedThreatProtectionOnboardingDeviceSettingState iosDerivedCredentialAuthenticationConfiguration
advancedThreatProtectionOnboardingStateSummary iosDeviceFeaturesConfiguration
androidCertificateProfileBase iosEasEmailProfileConfiguration
androidCompliancePolicy iosEducationDeviceConfiguration
androidCustomConfiguration iosEduDeviceConfiguration
androidDeviceComplianceLocalActionBase iosEnterpriseWiFiConfiguration
androidDeviceComplianceLocalActionLockDevice iosExpeditedCheckinConfiguration
androidDeviceComplianceLocalActionLockDeviceWithPasscode iosGeneralDeviceConfiguration
androidDeviceOwnerCertificateProfileBase iosikEv2VpnConfiguration
androidDeviceOwnerCompliancePolicy iosImportedPFXCertificateProfile
androidDeviceOwnerDerivedCredentialAuthenticationConfiguration iosPkcsCertificateProfile
androidDeviceOwnerEnterpriseWiFiConfiguration iosScepCertificateProfile
androidDeviceOwnerGeneralDeviceConfiguration iosTrustedRootCertificate
androidDeviceOwnerImportedPFXCertificateProfile iosUpdateConfiguration
androidDeviceOwnerPkcsCertificateProfile iosUpdateDeviceStatus
androidDeviceOwnerScepCertificateProfile iosVpnConfiguration
androidDeviceOwnerTrustedRootCertificate iosWiFiConfiguration
androidDeviceOwnerVpnConfiguration macOSCertificateProfileBase
androidDeviceOwnerWiFiConfiguration macOSCompliancePolicy
androidEasEmailProfileConfiguration macOSCustomAppConfiguration
androidEnterpriseWiFiConfiguration macOSCustomConfiguration
androidForWorkCertificateProfileBase macOSDeviceFeaturesConfiguration
androidForWorkCompliancePolicy macOSEndpointProtectionConfiguration
androidForWorkCustomConfiguration macOSEnterpriseWiFiConfiguration
androidForWorkEasEmailProfileBase macOSExtensionsConfiguration
androidForWorkEnterpriseWiFiConfiguration macOSGeneralDeviceConfiguration
androidForWorkGeneralDeviceConfiguration macOSImportedPFXCertificateProfile
androidForWorkGmailEasConfiguration macOSPkcsCertificateProfile
androidForWorkImportedPFXCertificateProfile macOSScepCertificateProfile
androidForWorkNineWorkEasConfiguration macOSSoftwareUpdateAccountSummary
androidForWorkPkcsCertificateProfile macOSSoftwareUpdateCategorySummary
androidForWorkScepCertificateProfile macOSSoftwareUpdateConfiguration
androidForWorkTrustedRootCertificate macOSSoftwareUpdateStateSummary
androidForWorkVpnConfiguration macOSTrustedRootCertificate
androidForWorkWiFiConfiguration macOSVpnConfiguration
androidGeneralDeviceConfiguration macOSWiFiConfiguration
androidImportedPFXCertificateProfile macOSWiredNetworkConfiguration
androidOmaCpConfiguration managedAllDeviceCertificateState
androidPkcsCertificateProfile managedDeviceCertificateState
androidScepCertificateProfile managedDeviceEncryptionState
androidTrustedRootCertificate managedDeviceMobileAppConfigurationState
androidVpnConfiguration ndesConnector
androidWiFiConfiguration restrictedAppsViolation
androidWorkProfileCertificateProfileBase settingStateDeviceSummary
androidWorkProfileCompliancePolicy sharedPCConfiguration
androidWorkProfileCustomConfiguration softwareUpdateStatusSummary
androidWorkProfileEasEmailProfileBase unsupportedDeviceConfiguration
androidWorkProfileEnterpriseWiFiConfiguration vpnConfiguration
androidWorkProfileGeneralDeviceConfiguration windows10CertificateProfileBase
androidWorkProfileGmailEasConfiguration windows10CompliancePolicy
androidWorkProfileNineWorkEasConfiguration windows10CustomConfiguration
androidWorkProfilePkcsCertificateProfile windows10DeviceFirmwareConfigurationInterface
androidWorkProfileScepCertificateProfile windows10EasEmailProfileConfiguration
androidWorkProfileTrustedRootCertificate windows10EndpointProtectionConfiguration
androidWorkProfileVpnConfiguration windows10EnterpriseModernAppManagementConfiguration
androidWorkProfileWiFiConfiguration windows10GeneralConfiguration
aospDeviceOwnerCompliancePolicy windows10ImportedPFXCertificateProfile
aospDeviceOwnerDeviceConfiguration windows10MobileCompliancePolicy
appleDeviceFeaturesConfigurationBase windows10NetworkBoundaryConfiguration
appleExpeditedCheckinConfigurationBase windows10PFXImportCertificateProfile
appleVpnConfiguration windows10PkcsCertificateProfile
cartToClassAssociation windows10SecureAssessmentConfiguration
defaultDeviceCompliancePolicy windows10TeamGeneralConfiguration
deviceComplianceActionItem windows10VpnConfiguration
deviceComplianceDeviceOverview windows81CertificateProfileBase
deviceComplianceDeviceStatus windows81CompliancePolicy
deviceCompliancePolicy windows81GeneralConfiguration
deviceCompliancePolicyAssignment windows81SCEPCertificateProfile
deviceCompliancePolicyDeviceStateSummary windows81TrustedRootCertificate
deviceCompliancePolicyGroupAssignment windows81VpnConfiguration
deviceCompliancePolicySettingStateSummary windows81WifiImportConfiguration
deviceCompliancePolicyState windowsAssignedAccessProfile
deviceComplianceScheduledActionForRule windowsCertificateProfileBase
deviceComplianceSettingState windowsDefenderAdvancedThreatProtectionConfiguration
deviceComplianceUserOverview windowsDeliveryOptimizationConfiguration
deviceComplianceUserStatus windowsDomainJoinConfiguration
deviceConfiguration windowsHealthMonitoringConfiguration
deviceConfigurationAssignment windowsIdentityProtectionConfiguration
deviceConfigurationConflictSummary windowsKioskConfiguration
deviceConfigurationDeviceOverview windowsPhone81CertificateProfileBase
deviceConfigurationDeviceStateSummary windowsPhone81CompliancePolicy
deviceConfigurationDeviceStatus windowsPhone81CustomConfiguration
deviceConfigurationGroupAssignment windowsPhone81GeneralConfiguration
deviceConfigurationState windowsPhone81ImportedPFXCertificateProfile
deviceConfigurationUserOverview windowsPhone81SCEPCertificateProfile
deviceConfigurationUserStateSummary windowsPhone81TrustedRootCertificate
deviceConfigurationUserStatus windowsPhone81VpnConfiguration
deviceManagement windowsPhoneEASEmailProfileConfiguration
deviceSetupConfiguration windowsPrivacyDataAccessControlItem
easEmailProfileConfigurationBase windowsUpdateForBusinessConfiguration
editionUpgradeConfiguration windowsUpdateState
iosCertificateProfile windowsVpnConfiguration
iosCertificateProfileBase windowsWifiConfiguration
iosCompliancePolicy windowsWifiEnterpriseEAPConfiguration
iosCustomConfiguration
Request type Limit per tenant for all apps Limit per app per tenant
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
complianceManagementPartner deviceManagementExchangeOnPremisesPolicy
deviceAppManagement deviceManagementPartner
deviceCategory enrollmentConfigurationAssignment
deviceComanagementAuthorityConfiguration mobileThreatDefenseConnector
deviceEnrollmentConfiguration onPremisesConditionalAccessSettings
deviceEnrollmentLimitConfiguration sideLoadingKey
deviceEnrollmentPlatformRestrictionsConfiguration vppToken
deviceEnrollmentWindowsHelloForBusinessConfiguration windows10EnrollmentCompletionPageConfiguration
deviceManagementExchangeConnector
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
deviceManagementAbstractComplexSettingDefinition deviceManagementIntentUserState
deviceManagementAbstractComplexSettingInstance deviceManagementIntentUserStateSummary
deviceManagementBooleanSettingInstance deviceManagementSettingCategory
deviceManagementCollectionSettingDefinition deviceManagementSettingDefinition
deviceManagementCollectionSettingInstance deviceManagementSettingInstance
deviceManagementComplexSettingDefinition deviceManagementStringSettingInstance
deviceManagementComplexSettingInstance deviceManagementTemplate
deviceManagementIntegerSettingInstance deviceManagementTemplateSettingCategory
deviceManagementIntent securityBaselineCategoryStateSummary
deviceManagementIntentAssignment securityBaselineDeviceState
deviceManagementIntentDeviceSettingStateSummary securityBaselineSettingState
deviceManagementIntentDeviceState securityBaselineState
deviceManagementIntentDeviceStateSummary securityBaselineStateSummary
deviceManagementIntentSettingCategory securityBaselineTemplate
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 400 requests per 20 seconds 200 requests per 20 seconds
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
deviceManagementDerivedCredentialSettings
deviceManagementResourceAccessProfileAssignment
deviceManagementResourceAccessProfileBase
windows10XCertificateProfile
windows10XSCEPCertificateProfile
windows10XTrustedRootCertificate
windows10XVpnConfiguration
windows10XWifiConfiguration
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
groupPolicyMigrationReport
groupPolicyObjectFile
groupPolicySettingMapping
unsupportedGroupPolicyExtension
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
androidManagedAppProtection managedAppStatusRaw
androidManagedAppRegistration managedMobileApp
defaultManagedAppProtection mdmWindowsInformationProtectionPolicy
iosManagedAppProtection targetedManagedAppConfiguration
iosManagedAppRegistration targetedManagedAppPolicyAssignment
managedAppConfiguration targetedManagedAppProtection
managedAppOperation windowsInformationProtection
managedAppPolicy windowsInformationProtectionAppLockerFile
managedAppPolicyDeploymentSummary windowsInformationProtectionDeviceRegistration
managedAppProtection windowsInformationProtectionPolicy
managedAppRegistration windowsInformationProtectionWipeAction
managedAppStatus
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
deviceManagementDomainJoinConnector
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
appVulnerabilityManagedDevice
appVulnerabilityMobileApp
appVulnerabilityTask
configManagerCollection
deviceAppManagementTask
securityConfigurationTask
unmanagedDeviceDiscoveryTask
vulnerableManagedDevice
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
deviceAndAppManagementRoleAssignment
deviceAndAppManagementRoleDefinition
resourceOperation
roleAssignment
roleDefinition
roleScopeTag
roleScopeTagAutoAssignment
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
remoteAssistancePartner
remoteAssistanceSettings
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
embeddedSIMActivationCodePool
embeddedSIMActivationCodePoolAssignment
embeddedSIMDeviceState
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
telecomExpenseManagementPartner
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
appleVppTokenTroubleshootingEvent
deviceManagementAutopilotEvent
deviceManagementAutopilotPolicyStatusDetail
deviceManagementTroubleshootingEvent
enrollmentTroubleshootingEvent
mobileAppIntentAndState
mobileAppTroubleshootingEvent
Intune unlock service limits
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
windowsDefenderApplicationControlSupplementalPolicy
windowsDefenderApplicationControlSupplementalPolicyAssignment
windowsDefenderApplicationControlSupplementalPolicyDeploymentStatus
windowsDefenderApplicationControlSupplementalPolicyDeploymentSummary
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
windowsFeatureUpdateCatalogItem
windowsFeatureUpdateProfile
windowsFeatureUpdateProfileAssignment
windowsQualityUpdateCatalogItem
windowsQualityUpdateProfile
windowsQualityUpdateProfileAssignment
windowsUpdateCatalogItem
Request type Limit per tenant for all apps Limit per app per tenant
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
intuneBrandingProfile
intuneBrandingProfileAssignment
windowsInformationProtectionAppLearningSummary
windowsInformationProtectionNetworkLearningSummary
Operation Limit per app per tenant Limit per tenant for all apps
The preceding limits apply individually to each report API. For example, a request to the Microsoft Teams user activity report
API and a request to the Outlook user activity report API within 10 minutes will count as 1 request out of 14 for each API, not 2
requests out of 14 for both.
Teams request type Limit per app per tenant Limit per app across all tenants
GET /teams/ {team-id} /schedule and all APIs under this path 30 rps 600 rps
POST, PATCH, PUT /teams/ {team-id} /schedule and all APIs under this path 30 rps 300 rps
DELETE /teams/ {team-id} /schedule and all APIs under this path 15 rps 150 rps
Other GET API calls for Microsoft Teams 30 rps 1500 rps
A maximum of 4 requests per second per app can be issued on a given team or channel. A maximum of 3000 messages per
app per day can be sent to a given channel (except when using migration mode).
aadUserConversationMember swapShiftsChangeRequest
changeTrackedEntity team
channel teamsApp
chatMessage teamsAppDefinition
chatMessageHostedContent teamsAppInstallation
conversationMember teamsAsyncOperation
offerShiftRequest teamsTab
openShift teamsTemplate
openShiftChangeRequest teamwork
schedule timeOff
schedulingGroup timeOffReason
shift timeOffRequest
shiftPreferences userSettings
workforceIntegration
POST, PUT, DELETE, PATCH 200 requests per 20 seconds 100 requests per 20 seconds
aggregatedPolicyCompliance managementIntent
cloudPcConnection managementTemplate
cloudPcDevice riskyUser
cloudPcOverview tenant
conditionalAccessPolicyCoverage tenantCustomizedInformation
credentialUserRegistrationsSummary tenantDetailedInformation
deviceCompliancePolicySettingStateSummary tenantGroup
managedDeviceCompliance tenantRelationship
managedDeviceComplianceTrend tenantTag
managedTenant windowsDeviceMalwareState
managementAction windowsProtectionState
managementActionTenantDeploymentStatus
Requests rate 120 requests per 1 minute and 400 per 1 hour 240 requests per 1 minute and 800 per 1 hour
Limit type Limit per app per user (delegated context) Limit per app (app-only context)
notebook
onenote
onenoteOperation
onenotePage
onenoteResource
onenoteSection
sectionGroup
You can find additional information about best practices in OneNote API throttling and how to avoid it.
7 Note
The resources listed earlier do not return a Retry-After header on 429 Too Many Requests responses.
administrativeUnit openTypeExtension
contact organization
device post
event schemaExtension
group user
message
Limit Applies to
150 megabytes (MB) upload (PATCH, POST, PUT) in a 5 minute period v1.0 and beta endpoints
API Resources
API Resources
Alternatively, an app can use the dependsOn property to order requests within a batch. Microsoft Graph sends the Outlook
service one request from the batch at a time following the specified order, and Outlook executes each individual request in the
batch sequentially.
In other words, when targeting the same mailbox, apps that allow multiple batch requests to run in parallel can use either of
the following approaches:
If the individual requests do not have to be ordered, have individual requests from a single batch run concurrently.
Use the dependsOn property to order requests in a batch, and have up to 4 such batch requests run concurrently.
GET 400 requests per 5 minutes and 12000 requests per 1 day
POST, PUT, PATCH, DELETE 100 requests per 5 minutes and 8000 requests per 1 day
activityHistoryItem
userActivity
Security detections and incidents service limits
The following limits apply to any request on /security .
audioRoutingGroup onlineMeeting
call participant
cancelMediaProcessingOperation participantJoiningNotification
cloudCommunications participantLeftNotification
commsApplication playPromptOperation
commsOperation presence
inviteParticipantsOperation recordOperation
meetingAttendanceReport subscribeToToneOperation
muteParticipantOperation unmuteParticipantOperation
muteParticipantOperation updateRecordingStatusOperation
POST, PUT, DELETE, PATCH 2000 requests per 20 seconds 500 requests per 20 seconds
GET Subscription by Id 2000 requests per 20 seconds 500 requests per 20 seconds
Request type Limit per app for all tenants Limit per app per tenant
planner plannerPlanDetails
plannerAssignedToTaskBoardTaskFormat plannerProgressTaskBoardTaskFormat
plannerBucket plannerTask
plannerBucketTaskBoardTaskFormat plannerTaskDetails
plannerGroup plannerUser
plannerPlan
Set up notifications for changes in
resource data
Article • 04/20/2023
https://www.youtube-nocookie.com/embed/rC1bunenaq4
Basic notifications: Change notifications that don't contain resource data other
than the id of the resource that changed. All Microsoft Graph resources support
basic notifications. When an app receives a basic notification, the service can use
the id to query to changed object.
Rich notifications: Change notifications that include the resource data of the
object that changed. For more information about rich notifications, see Rich
notifications.
Lifecycle notifications: Notifications that alert the customer when they are at risk
of missing change notifications due to the lifecycle of their subscription. For more
information about lifecycle notifications, see Lifecycle notifications.
Supported resources
An app can subscribe to changes on the Microsoft Graph resources listed in the table,
which also indicates the limits that apply for subscriptions to the resources. When any
limit is exceeded, attempts to create a subscription will result in an 403 Forbidden error
response. The message property of the error response will explain the limit that has
been exceeded.
7 Note
Cloud printing Changes when there is a valid job in the queue (jobStarted -
printTaskDefinition event): /print/printtaskdefinition/{id}/tasks
Not
supported for
Azure AD
B2C tenants.
A known
issue for the
subscription
changeType.
Teams chatMessage Changes to chat messages in all channels in all teams: Maximum
/teams/getAllMessages subscription
quotas:
Changes to chat messages in a specific channel: Per app
/teams/{id}/channels/{id}/messages and channel
or chat
Changes to chat messages in all chats: /chats/getAllMessages combination:
1
Changes to chat messages in a specific chat: subscription.
/chats/{id}/messages Per user
(for
Changes to chat messages in all chats a particular user is part subscriptions
of: /users/{id}/chats/getAllMessages tracking chat
messages in
Changes to chat messages for all chats in an organization all chats the
where a particular Teams app is installed: user is part
/appCatalogs/teamsApps/{id}/installedToChats/getAllMessages of): 10
subscriptions.
Per
organization:
10,000 total
subscriptions.
Resource Supported resource paths Limitations
Not
supported for
personal
Microsoft
accounts like
outlook.com.
Not
supported for
Azure AD
B2C tenants.
A known
issue for the
subscription
changeType.
Some of these resources support rich notifications (notifications with resource data). For
more information about resources that support rich notifications, see Set up change
notifications that include resource data.
Subscription lifetime
Subscriptions have a limited lifetime. Apps need to renew their subscriptions before the
expiration time; Otherwise, they need to create a new subscription. Apps can also
unsubscribe at any time to stop getting change notifications.
The following table shows the maximum expiration times for subscriptions per resource
in Microsoft Graph.
Webhooks for this resource are only available in the global endpoint
and not in the national clouds.
Note: Existing applications and new applications should not exceed the supported
value. In the future, any requests to create or renew a subscription beyond the
maximum value will fail.
Managing subscriptions
Clients can create subscriptions, renew subscriptions, and delete subscriptions. Then
while the subscription is valid and when changes occur in the subscribed resource,
Microsoft Graph sends change notifications to the specified notification endpoint.
You manage the subscription using the subscription resource type and its related
methods. While the subscription is valid and changes occur in the subscribed resource,
Microsoft Graph sends a change notification in a structure defined in the
changeNotificationCollection resource type.
For more information about managing subscriptions for the different delivery channels
using Microsoft Graph, see the following articles.
Code samples
The following code samples are available on GitHub.
Microsoft Graph Training Module - Using Change Notifications and Track Changes
with Microsoft Graph
Microsoft Graph Webhooks Sample for Node.js
Microsoft Graph Webhooks Sample for ASP.NET Core
Microsoft Graph Webhooks Sample for Java Spring
Latency
The following table lists the latency to expect between an event happening in the
service and the delivery of the change notification.
Deployment resources
Get change notifications through webhooks
Get change notifications through Azure Event Hubs
Get change notifications through Azure Event Grid
Rich notifications (notifications with resource data)
Lifecycle notifications
Tutorials
Change notifications for cloud printing
Change notifications for Outlook resources
Change notifications for Microsoft Teams resources
See also
Training: Use change notifications and track changes with Microsoft Graph
Use delta query to track changes in
Microsoft Graph data
Article • 03/15/2023
Delta query enables applications to discover newly created, updated, or deleted entities
without performing a full read of the target resource with every request. Microsoft
Graph applications can use delta query to efficiently synchronize changes with a local
data store.
1. The application begins by calling a GET request with the delta function on the
desired resource.
2. Microsoft Graph sends a response containing the requested resource and a state
token.
3. When the application needs to learn about changes to the resource, it makes a
new request using the @odata.deltaLink URL received in step 2. This request may
be made immediately after completing step 2 or when the application checks for
changes.
4. Microsoft Graph returns a response describing changes to the resource since the
previous request, and either a @odata.nextLink URL or a @odata.deltaLink URL.
7 Note
Resources stored in Azure Active Directory (such as users and groups) support
"sync from now" scenarios. This allows you to skip steps 1 and 2 (if you're not
interested in retrieving the full state of the resource) and ask for the latest
@odata.deltaLink instead. Append $deltaToken=latest to the delta function
Graph SDKs.
The initial request to the delta query function (no $deltaToken or $skipToken )
will return the resources that currently exist in the collection. Resources that
have been created and deleted prior to the initial delta query won't be
returned. Updates made before the initial request are summarized on the
resource returned as its latest state.
Note that $select and $deltaLink query parameters will be supported for
Azure Active Directory (Azure AD) resources so that customers can change the
properties they want to track for an existing @odata.deltaLink . Delta queries
with both $select and $skipToken will not be supported.
State tokens
A delta query GET response always includes a URL specified in a @odata.nextLink or
@odata.deltaLink response header. The @odata.nextLink URL includes a $skipToken ,
These tokens are opaque to the client. The following details are what you need to know
about them:
Each token reflects the state and represents a snapshot of the resource in that
round of change tracking.
The state tokens also encode and include other query parameters (such as
$select ) specified in the initial delta query request. Therefore, it's not required to
repeat them in subsequent delta query requests.
When carrying out delta query, you can copy and apply the @odata.nextLink or
@odata.deltaLink URL to the next delta function call without having to inspect the
contents of the URL, including its state token.
Note the general limited support of the following optional query parameters:
$orderby
Do not assume a specific sequence of the responses returned from a delta query.
Assume that the same item can show up anywhere in the @odata.nextLink
sequence and handle that in your merge logic.
$top
The number of objects in each page can vary depending on the resource type and
the type of changes made to the resource.
For the message resource, see details for query parameters support in a delta query.
For the user and group resources, there are restrictions on using some query
parameters:
If a $select query parameter is used, the parameter indicates that the client
prefers to only track changes on the properties or relationships specified in the
$select statement. If a change occurs to a property that is not selected, the
resource for which that property changed does not appear in the delta response
after a subsequent request.
$select also supports manager and members navigation properties for users and
Scoping filters allow you to track changes to one or more specific users or groups,
filtering only by object ID. For example, the following request returns changes for
the groups matching the IDs specified in the query filter.
HTTP
https://graph.microsoft.com/beta/groups/delta/?$filter=id eq '477e9fc6-5de7-
4406-bb2a-7e5c83c9ae5f' or id eq '004d6a07-fe70-4b92-add5-e6e37b8acd8e'
Updated instances are represented by their id with at least the properties that have
been updated, but additional properties may be included.
changed indicates the item was deleted and can be restored from deletedItems.
The @removed object can be returned in the initial delta query response and in tracked
(deltaLink) responses. Clients using delta query requests should be designed to handle
these objects in the responses.
7 Note
It's possible that a single entity will be contained multiple times in the response, if
that entity was changed multiple times and under certain conditions. Delta queries
enable your application to list all the changes, but can't ensure that entities are
unified in a single response.
Supported resources
Delta query is currently supported for the following resources. Note that some resources
which are available in v1.0 have their corresponding delta functions still in preview
status, as indicated.
Events in a calendar view (date range) of the delta function of the event resource
primary calendar
* The usage pattern for OneDrive and SharePoint resources is similar to the other
supported resources with some minor syntax differences. Delta query for drives and
lists will be updated in the future to be consistent with other resource types. For
more detail about the current syntax, see driveItem: delta and listItem: delta.
** The usage pattern for Planner resources is similar to other supported resources
with a few differences. For details, see planner: delta.
Limitations
To verify that a property can be used in delta query, try to perform a regular GET
operation on the resource collection, and select the property you're interested in. For
example, you can try the skills property on the users collection.
HTTP
GET https://graph.microsoft.com/v1.0/users/?$select=skills
Because the skills property is stored outside of Azure AD, the following is the response.
HTTP
{
"error": {
"code": "NotImplemented",
"message": "This operation target is not yet supported.",
"innerError": {
"request-id": "...",
"date": "2019-09-20T21:47:50"
}
}
}
This tells you that the skills property is not supported for delta query on the user
resource.
Navigation properties
Navigation properties are not supported. For example, you cannot track changes to the
users collection that would include changes to their photo property; photo is a
navigation property stored outside of the user entity, and changes to it do not cause the
user object to be included in the delta response.
Processing delays
Expect varying delays between the time a change is made to a resource instance, which
can be through an app interface or API, and the time the tracked change is reflected in a
delta query response.
Sometimes the changes that have occurred to the object might not be indicated when
you select the @odata.nextLink or the @odata.deltaLink . This is because some requests
might have replication delays for objects that were recently created, updated, or
deleted. Retry the @odata.nextLink or @odata.deltaLink after some time to retrieve the
latest changes.
National clouds
Delta queries are available for customers hosted on the public cloud and Microsoft
Graph China operated by 21Vianet only.
Replays
Your application must be prepared for replays, which occur when the same change
appears in subsequent responses. While delta query makes a best effort to reduce
replays, they are still possible.
Synchronization reset
Delta query can return a response code of 410 (gone) and a Location header containing
a request URL with an empty $deltaToken (same as the initial query). This is an
indication that the application must restart with a full synchronization of the target
tenant. This usually happens to prevent data inconsistency due to internal maintenance
or migration of the target tenant.
Token duration
Delta tokens are only valid for a specific period before the client application needs to
run a full synchronization again.
In case of an expired token, the service should respond with a 40X-series error with error
codes such as syncStateNotFound . For more information, see Error codes in Microsoft
Graph.
Prerequisites
The same permissions that are required to read a specific resource are also required to
perform delta query on that resource.
Microsoft Graph provides a single API endpoint to access rich people-centric data and
insights through resources such as user and message. You can also extend Microsoft
Graph by adding custom properties to resource instances without requiring an external
data store.
In this article, we'll discuss how Microsoft Graph supports extending its resources, the
options available to add custom properties and when to use them.
) Important
The extensions mentioned in this article are not similar to Azure AD custom
security attributes. To understand their differences, see How do custom security
attributes compare with extensions?
Extension attributes
Directory (Azure AD) extensions
Schema extensions
Open extensions
Extension attributes
Azure AD offers a set of 15 extension attributes with predefined names on the user and
device resources. These properties were initially custom attributes provided in on-
premises Active Directory (AD) and Microsoft Exchange. However, they can now be used
for more than syncing on-premises AD and Microsoft Exchange data to Azure AD
through Microsoft Graph.
Developer experience
You can use the 15 extension attributes to store String values on user or device resource
instances, through the onPremisesExtensionAttributes and extensionAttributes
properties respectively. The values may be assigned when creating a new resource
instance or when updating an existing resource instance. You can also filter by the
values.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/071cc716-8147-4397-a5ba-
b2105951cc0b
{
"onPremisesExtensionAttributes": {
"extensionAttribute1": "skypeId.adeleVance",
"extensionAttribute13": null
}
}
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users?
$select=id,displayName,onPremisesExtensionAttributes
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users(id,displayName,onPremisesE
xtensionAttributes)",
"value": [
{
"id": "071cc716-8147-4397-a5ba-b2105951cc0b",
"displayName": "Adele Vance",
"onPremisesExtensionAttributes": {
"extensionAttribute1": "Contractor",
"extensionAttribute2": "50",
"extensionAttribute3": null,
"extensionAttribute4": "1478354",
"extensionAttribute5": "10239390",
"extensionAttribute6": null,
"extensionAttribute7": null,
"extensionAttribute8": null,
"extensionAttribute9": null,
"extensionAttribute10": "11",
"extensionAttribute11": null,
"extensionAttribute12": "/o=ExchangeLabs/ou=Exchange
Administrative Group
(FYDIBOHF47SPDLT)/cn=Recipients/cn=5ee781fc7egc7aa0b9394bddb44e7f04-Adele
Vance",
"extensionAttribute13": null,
"extensionAttribute14": null,
"extensionAttribute15": null
}
}
]
}
The 15 extension attributes are already predefined in Microsoft Graph and their property
names can't be changed. Therefore, you can't use custom names such as SkypeId for
the extension attributes. This requires you and the organization to be aware of the
extension attribute properties that are in use so that the values aren't inadvertently
overwritten by other apps.
For the list of resource types that can be specified as target objects for a directory
extension, see Comparison of extension types.
Developer experience
Directory extension definitions are managed through the extensionProperty resource
and its associated methods. The data is managed through the REST API requests that
you use to manage the resource instance.
Before you can add a directory extension to a resource instance, you must first define
the directory extension.
Request
HTTP
POST https://graph.microsoft.com/v1.0/applications/30a5435a-1871-485c-
8c7b-65f69e287e7b/extensionProperties
{
"name": "jobGroupTracker",
"dataType": "String",
"targetObjects": [
"User"
]
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#applications('30a5435a-1871-
485c-8c7b-65f69e287e7b')/extensionProperties/$entity",
"id": "4e3dbc8f-ca32-41b4-825a-346215d7d20f",
"deletedDateTime": null,
"appDisplayName": "HR-sync-app",
"dataType": "String",
"isSyncedFromOnPremises": false,
"name": "extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker",
"targetObjects": [
"User"
]
}
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
{
"accountEnabled": true,
"displayName": "Adele Vance",
"mailNickname": "AdeleV",
"userPrincipalName": "[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn": false,
"password": "xWwvJ]6NMw+bWH-d"
},
"extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker":
"JobGroupN"
}
The request returns a 201 Created response code and a user object in the response
body.
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/users?
$select=id,displayName,extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGro
upTracker,extension_b7d8e648520f41d3b9c0fdeb91768a0a_permanent_pensionab
le
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users(id,displayName,extension_b
7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker,extension_b7d8e648520f41d3b9
c0fdeb91768a0a_permanent_pensionable)",
"value": [
{
"id": "63384f56-42d2-4aa7-b1d6-b10c78f143a2",
"displayName": "Adele Vance",
"extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker":
"E4",
"extension_b7d8e648520f41d3b9c0fdeb91768a0a_permanent_pensionable": true
}
]
}
To update or delete the value of the directory extension for a resource instance, use the
PATCH method. To delete the extension property and its associated value, set its value to
null .
The following request updates the value of one directory extension and deletes another
extension property.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/63384f56-42d2-4aa7-b1d6-
b10c78f143a2
{
"extension_b7d8e648520f41d3b9c0fdeb91768a0a_permanent_pensionable":
null,
"extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker": "E4"
}
When the definition is deleted before data in the associated extension property is
deleted, there's no way to know the existence of the extension property via Microsoft
Graph - even though the undiscoverable property counts against the 100-limit.
Deleting an owner app in the home tenant makes the associated directory extensions
and their data undiscoverable. Restoring an owner app restores the directory extension
definitions but doesn't make the directory extension properties or their data immediately
discoverable. This is because restoring an app doesn't automatically restore the
associated service principal in the tenant. To make the directory extension properties
and their data discoverable, either create a new service principal or restore the deleted
service principal. NO changes are made to other tenants where the app has been
consented to.
Schema extensions
Microsoft Graph schema extensions are conceptually similar to directory extensions.
First, you define your schema extension. Then, use it to extend supported resource
instances with strongly typed custom properties. In addition, you can control the status
of your schema extension and let it be discoverable by other apps.
For the list of resource types that support schema extensions, see Comparison of
extension types.
https://www.youtube-nocookie.com/embed/3MOAlUFNus0
Developer experience
When creating a schema extension definition, you must provide a unique name for its
id. There are two naming options:
If you already have a vanity .com , .net , .gov , .edu or a .org domain that you've
verified with your tenant, you can use the domain name along with the schema
name to define a unique name, in this format {domainName}_{schemaName}. For
example, if your vanity domain is contoso.com , you can define an id of
contoso_mySchema . This option is highly recommended.
Alternatively, you can set the id to a schema name (without a domain name prefix).
For example, mySchema . Microsoft Graph will assign a string ID for you based on
the supplied name, in this format: ext{8-random-alphanumeric-chars}_{schema-
name} . For example, extkvbmkofy_mySchema .
The id will be the name of the complex type that will store your data on the extended
resource instance.
Once you register a schema extension, it's available to be used by all applications in the
same tenant as the associated owner application (when in the InDevelopment state) or
by all applications in any tenant (when in the Available state). Like directory extensions,
authorized apps have the ability to read and write data on any extensions defined on
the target object.
You manage the schema extension definitions and the data in the corresponding
schema extension property using separate sets of API operations. To manage the
schema extension data on the extended resource instance, use the same REST request
that you use to manage the resource instance.
Use POST to store data in the schema extension property when you're creating a
new user.
Use PATCH to either store data in the schema extension property or update or
delete the stored data.
To delete data from a property, set its value to null .
To delete data from all properties, set its value to null . If all properties are
null , the schema extension object is also deleted.
To update any property, you must specify all properties in the request body.
Otherwise, Microsoft Graph will update the unspecified properties to null .
Use GET to read the schema extension properties for all users or individual users in
the tenant.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/schemaExtensions
{
"id": "graphLearnCourses",
"description": "Graph Learn training courses extensions",
"targetTypes": [
"user"
],
"properties": [
{
"name": "courseId",
"type": "Integer"
},
{
"name": "courseName",
"type": "String"
},
{
"name": "courseType",
"type": "String"
}
]
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#schemaExtensions/$entity",
"id": "extkmpdyld2_graphLearnCourses",
"description": "Graph Learn training courses extensions",
"targetTypes": [
"user"
],
"status": "InDevelopment",
"properties": [
{
"name": "courseId",
"type": "Integer"
},
{
"name": "courseName",
"type": "String"
},
{
"name": "courseType",
"type": "String"
}
]
}
HTTP
HTTP
POST https://graph.microsoft.com/beta/users
{
"accountEnabled": true,
"displayName": "Adele Vance",
"mailNickname": "AdeleV",
"userPrincipalName": "[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn": false,
"password": "xWwvJ]6NMw+bWH-d"
},
"extkmpdyld2_graphLearnCourses": {
"courseId": 100,
"courseName": "Explore Microsoft Graph",
"courseType": "Online"
}
}
The request returns a 201 Created response code and a schemaExtension object in the
response body
The following example deletes the value of the courseId property and updates the
courseType property. To delete the extkmpdyld2_graphLearnCourses extension property
in its entirety, set its value to null .
HTTP
HTTP
PATCH https://graph.microsoft.com/beta/users/0668e673-908b-44ea-861d-
0661297e1a3e
{
"extkmpdyld2_graphLearnCourses": {
"courseType": "Instructor-led",
"courseId": null
}
}
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/users/0668e673-908b-44ea-861d-
0661297e1a3e?$select=id,displayName,extkmpdyld2_graphLearnCourses
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users(id,displayName,extkmpdyld2
_graphLearnCourses)/$entity",
"id": "63384f56-42d2-4aa7-b1d6-b10c78f143a2",
"displayName": "Adele Vance",
"extkmpdyld2_graphLearnCourses": {
"@odata.type": "#microsoft.graph.ComplexExtensionValue",
"courseType": "Instructor-led",
"courseName": "Explore Microsoft Graph",
"courseId": null
}
}
Deleting a schema extension definition without setting the schema extension to null
makes the property and its associated user data undiscoverable.
Deleting an owner app in the home tenant doesn't delete the associated schema
extension definition or the property and the data it stores. The schema extension
property can still be read, deleted, or updated for users. However, the schema extension
definition can't be updated.
Open extensions
Microsoft Graph open extensions are open types that offer a simple and flexible way
to add untyped data directly to a resource instance. These extensions aren't strongly
typed, discoverable, or filterable.
For the list of resource types that support Microsoft Graph open extensions, see
Comparison of extension types.
https://www.youtube-nocookie.com/embed/ibdlADb8IZc
Developer experience
Open extensions, together with their data, are accessible through the extensions
navigation property of the resource instance. They allow you to group related properties
for easier access and management.
You define and manage open extensions on the fly on resource instances. They're
considered unique for each object, and it's not required to apply a universally consistent
pattern for all objects. For example, in the same tenant:
The user object for Adele can have an open extension named socialSettings that
has three properties: linkedInProfile, skypeId, and xboxGamertag.
The user object for Bruno can have no open extension property.
The user object for Alex can have an open extension named socialSettings with five
properties: theme, color, language, font, and fontSize.
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users/3fbd929d-8c56-4462-851e-
0eb9a7b3a2a5/extensions
{
"@odata.type": "#microsoft.graph.openTypeExtension",
"extensionName": "com.contoso.socialSettings",
"skypeId": "skypeId.AdeleV",
"linkedInProfile": "www.linkedin.com/in/testlinkedinprofile",
"xboxGamerTag": "AwesomeAdele",
"id": "com.contoso.socialSettings"
}
The request returns a 201 Created response code and an openTypeExtension object in
the response body.
To update an open extension, you must specify all its properties in the request body.
Otherwise, the unspecified properties will be updated to null and deleted from the
open extension.
The following request specifies only the linkedInProfile and xboxGamerTag properties.
The value of the xboxGamerTag property is being updated while the linkedInProfile
property remains the same. This request also deletes the unspecified skypeId property.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/users/3fbd929d-8c56-4462-851e-
0eb9a7b3a2a5/extensions/com.contoso.socialSettings
{
"xboxGamerTag": "FierceAdele",
"linkedInProfile": "www.linkedin.com/in/testlinkedinprofile"
}
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/users/3fbd929d-8c56-4462-851e-
0eb9a7b3a2a5/extensions/com.contoso.socialSettings
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('3fbd929d-8c56-4462-
851e-0eb9a7b3a2a5')/extensions/$entity",
"@odata.type": "#microsoft.graph.openTypeExtension",
"xboxGamerTag": "FierceAdele",
"linkedInProfile": "www.linkedin.com/in/testlinkedinprofile",
"id": "com.contoso.socialSettings"
}
7 Note
1
Due to an existing service limitation, delegates cannot create open extension-
appended events in shared mailbox calendars. Attempts to do so will result in an
ErrorAccessDenied response.
2
Only available in public preview for directory extensions.
3 These limits on open extensions apply to the following directory resources: user,
group, device, and organization.
4
Each open extension is stored in a MAPI named property, which are a limited
resource in a user's mailbox. This limit applies to the following Outlook resources:
message, event, and contact
You can manage all extensions when you're signed in with a work or school
account. Additionally, you can manage open extensions for the following resources
when signed-in with a personal Microsoft account: event, post, group, message,
contact, and user.
Known limitations
For known limitations using extensions, see the extensions section in the known issues
article.
Next steps
Training module: Add custom data to your app using extensions in Microsoft
Graph
Add custom data to users using open extensions
Add custom data to groups using schema extensions
Enable metered APIs and services in
Microsoft Graph
Article • 05/17/2023
Some APIs and services in Microsoft Graph are metered and require payment for use.
For a current list of APIs that require payment, see Metered APIs and services in
Microsoft Graph.
To consume metered APIs and services in Microsoft Graph, the application registration
for the Azure Active Directory application that consumes the APIs must be associated
with an Azure subscription. This subscription will be billed for any metered charges. This
association also allows you to use Azure Cost Management + Billing to understand and
manage the costs of the application.
This article describes how to associate your application with an Azure subscription.
Known limitations
The following limitations apply to metered APIs:
Metered APIs and services in Microsoft Graph are currently available only in the
Microsoft global environment and not in national cloud deployments, including
Microsoft 365 GCC deployments accessed through the worldwide Microsoft Graph
endpoint. For details about national clouds, see National cloud deployments.
The target application must be a confidential client application (for example, web
application, web API, or daemon/service). Public client applications (desktop and
mobile applications) are not supported.
Prerequisites
Before you can access metered APIs and services in Microsoft Graph, you must complete
the following steps:
Create an application registration in Azure Active Directory (Azure AD) for the
application that will be making calls to the metered Microsoft 365 APIs and
services.
If you don't have an Azure subscription, create one now in the tenant that
includes the application registration.
You must have contributor permissions to the active Azure subscription you want
to use, as well as application owner permissions for the target application
registration.
If you plan to use protected APIs, submit a request form, as applicable:
Teams protected API request form
SharePoint protected API request form
Enable an application
To enable an application to use metered APIs and services in Microsoft Graph, it must be
associated with an Azure subscription. To create this association, you must create an
Azure resource of type Microsoft.GraphServices/accounts. The Azure resource connects
a single Azure AD application registration with the Azure subscription where the
application's usage of metered APIs is billed.
1. If you have multiple Azure subscriptions, for information about setting the active
subscription, see Use multiple Azure subscriptions; otherwise, go to the next step.
PowerShell
myRG The name of an existing Azure resource group to add the newly created
resource to.
mySubscriptionGUID The ID of the Azure subscription that will receive billing events, provided
as a string parameter; for example, 00000000-0000-0000-0000-
000000000000.
{
"extendedLocation": null,
"id": "/subscriptions/00000000-0000-0000-0000-
000000000000/resourceGroups/myRG/providers/Microsoft.GraphServices/accounts/
myGraphAppBilling",
"identity": null,
"kind": null,
"location": "Global",
"managedBy": null,
"name": "myGraphAppBilling",
"plan": null,
"properties": {
"appId": "00000000-0000-0000-0000-000000000000",
"billingPlanId": "00000000-0000-0000-0000-000000000000",
"provisioningState": "Succeeded"
},
"resourceGroup": "myRG",
"sku": null,
"systemData": {
"createdAt": "2023-01-31T00:12:20.7893671Z",
"createdByType": "User",
"lastModifiedAt": "2023-01-31T00:12:20.7893671Z",
"lastModifiedByType": "User"
},
"tags": null,
"type": "microsoft.graphservices/accounts"
}
Verify setup
Use the following steps to verify that an application is properly enabled to use metered
APIs and services in Microsoft Graph.
Note: You can complete the following steps by signing in to
https://portal.azure.com and choosing Cloud Shell, or by using your local Azure
command-line interface. If you're using Cloud Shell for the first time, you might
need to create a storage account. Select an Azure subscription, choose Create, and
follow the instructions to create a storage account. To use a local Azure command-
line interface, install the Azure CLI.
1. If you have multiple Azure subscriptions, for information about setting the active
subscription, see Use multiple Azure subscriptions; otherwise, go to the next step.
2. Use az resource list to list the resources associated with the active Azure
subscription. Copy the following command into your command-line interface and
type <Enter>. If the command succeeds, the response will include a JSON
representation of the resources associated with the active Azure subscription.
PowerShell
[
{
"changedTime": "2023-04-25T18:12:30.586342+00:00",
"createdTime": "2023-04-25T18:02:30.141407+00:00",
"extendedLocation": null,
"id": "/subscriptions/00000000-0000-0000-0000-
000000000000/resourceGroups/myRG/providers/Microsoft.GraphServices/accounts/
myGraphAppBilling",
"identity": null,
"kind": null,
"location": "global",
"managedBy": null,
"name": "myGraphAppBilling",
"plan": null,
"properties": null,
"provisioningState": "Succeeded",
"resourceGroup": "myRG",
"sku": null,
"tags": null,
"type": "Microsoft.GraphServices/accounts"
}
]
3. With the values returned in step 2, use az resource show to show the full details of
the resource. Copy the following command into your command-line interface,
replace the parameters listed in the table with your own values, and type <Enter>.
If the command succeeds, the response will include a JSON representation of the
requested resource.
PowerShell
Parameter Description
myRG The name of the Azure resource group provided in the result of step 2.
{
"extendedLocation": null,
"id": "/subscriptions/00000000-0000-0000-0000-
000000000000/resourceGroups/myRG/providers/Microsoft.GraphServices/accounts/
myGraphAppBilling",
"identity": null,
"kind": null,
"location": "Global",
"managedBy": null,
"name": "myGraphAppBilling",
"plan": null,
"properties": {
"appId": "00000000-0000-0000-0000-000000000000",
"billingPlanId": "00000000-0000-0000-0000-000000000000"
},
"resourceGroup": "myRG",
"sku": null,
"tags": null,
"type": "microsoft.graphservices/accounts"
}
The properties property will include the application ID of the associated application
registration.
Note: Your application might need to request a new OAuth access token before
requests to metered APIs will be allowed.
You can monitor cost and usage of metered APIs and services in Microsoft Graph
through Azure Cost Management + Billing. This provides access to costs within the
subscription, which can be split based on application, calling tenant, or meter.
The invoice will include details that allow you to understand the amount of usage your
application generates, and for multi-tenant applications, where that usage is happening.
For details, see Understand your Azure invoice.
See also
Overview of metered APIs and services in Microsoft Graph
Metered APIs and services in Microsoft Graph
Use Graph Explorer to try Microsoft
Graph APIs
Article • 11/03/2022
Graph Explorer is a developer tool that lets you learn about Microsoft Graph APIs. Use
Graph Explorer to try the APIs on the default sample tenant to explore capabilities, or
sign in to your own tenant and use it as a prototyping tool to fulfill your app scenarios.
This tool includes helpful features such as code snippets (C#, Java, JavaScript, Go and
PowerShell), Microsoft Graph Toolkit and adaptive cards integration, and more.
Graph Explorer handles the authentication process for you. Customize the experience by
collapsing the sidebar or changing the theme.
Get started
Graph Explorer is a web application hosted on the Microsoft Graph developer center. It's
an open-source project, and we welcome your contributions and feedback on GitHub .
Make requests
With Graph Explorer, you can make requests to the Microsoft Graph APIs to retrieve,
add, delete and update data. Your requests can send parameters, authorization details,
and any body data you require.
To create the request, you can either select a sample query from the menu at the left,
which fills in the query field, or you can choose to manually type your request in the
field. Once you run the request, you will get the HTTP response code and the response
will be displayed in the response preview area.
When you sign in to Graph Explorer and run the same query, the response is returned
with real data from the tenant that you signed in to.
) Important
For example, to run a POST request, select POST in the drop-down list for the HTTP
verb, and add a request body and request headers as appropriate.
Next steps
Try Graph Explorer.
Explore the different Graph Explorer features.
Contribute or provide feedback on GitHub .
Work with Graph Explorer
Article • 11/03/2022
Graph Explorer is a developer tool that you can use to learn about Microsoft Graph APIs.
It has a variety of features to help you on your journey. This article describes some of
the important features of Graph Explorer and how to use them.
For an overview, see Use Graph Explorer to try Microsoft Graph APIs.
Header
From the top navigation, you can sign in, view the tenant you're using, access your
settings, and find helpful links and a feedback mechanism.
Consent to permissions
The user or administrator must grant Graph Explorer the correct permissions by using a
consent process to access data in Microsoft Graph. You can consent to permissions in
Graph Explorer by choosing either the Modify permissions tab or the Consent to
permissions option under the profile avatar when you’re signed in.
The Consent to permissions option in the profile avatar contains the list of all available
permissions:
1. Click the profile avatar and choose the Consent to permissions option. This option
contains the list of all available permissions.
2. From the list of all the permissions, consent to the ones you want.
The Modify permissions tab lists all the permissions that you might need to run the
query in the address bar. When possible, choose the least privileged permission.
To consent to permissions:
7 Note
The Modify permissions feature is currently in preview, and some queries might be
missing permissions.
Left pane
The left pane allows you to access the main features of Graph Explorer:
Sample queries
Resources
History
Sample queries
The Sample queries tab provides a set of queries categorized by service that you can
select and run to help you get started with Microsoft Graph API calls.
When you select a query, the selected query populates the query box. To try the request,
choose Run query.
Resources
Use the Resources tab to explore Microsoft Graph resources in the beta and v1.0
endpoints. Browse the list of resources or use the search bar to search for a specific
resource.
From the Resources tab, you can export a collection of resources into a Postman
collection by doing the following:
1. From the kebab menu next to the resource, select Add to collection.
2. When you're finished adding resources, choose Preview collection.
3. From the collection view, you can review the resources you selected and remove
any if you choose.
4. Choose Download Postman collection.
History
All queries you run in Graph Explorer are saved for 30 days in the History tab. From the
History tab, you can:
Query area
Use the query area to run requests and see the responses. The query area includes the
following elements:
When you run a query, you will see a Response preview and Response headers in the
response pane.
Code snippets
Microsoft Graph Toolkit integration
Adaptive cards integration
Graph Explorer allows you to visualize Microsoft Graph Toolkit components that
correspond to the API queries. A blue dot on the toolkit component tab indicates that
the Toolkit provides a component for the currently specified REST API query in Graph
Explorer. You can conveniently copy the code for the component to your app.
Postman is an API platform for building and using APIs. Postman simplifies each step of
the API lifecycle and streamlines collaboration so that you can create better APIs faster.
You can use the Microsoft Graph Postman collection to get started with Microsoft Graph
APIs in minutes.
This article explains how to get up and running with Postman and Microsoft Graph. You
can also explore Microsoft Graph APIs directly in your web browser by using Graph
Explorer.
For details about how to use Postman, follow the steps in this article or watch the
Getting started with Microsoft Graph Postman workspace video.
Tip
The Microsoft Graph Postman collection is configured to authenticate with the
global Azure AD service and access the global Microsoft Graph service
( graph.microsoft.com ). If you want to use the collection to connect to a national
cloud deployment, you must modify your fork of the collection.
cloud.
Update the Scope value on the Authorization tab of the Delegated and
Application folders, replacing graph.microsoft.com with the Microsoft Graph
service root endpoint for your national cloud.
You are redirected to a fork of the main Microsoft Graph Postman collection in your own
workspace.
You don't need the agent if you're using the Postman for Windows app. If you open
Postman for Windows, you see this forked collection in your workspace.
Step 3: Create an Azure AD application
To use this collection in your own developer tenant, create an Azure Active Directory
(Azure AD) application and give it the appropriate permissions for the requests that you
want to call. If you don't have a developer tenant, you can sign up for one through the
Microsoft 365 Developer Program.
The application now has two permissions configured. Mail.Read is added as a delegated
permission, which is a permission that requires a signed-in user. The application can
read mail on behalf of the user. User.Read.All is added as an application permission,
which is a permission that does not require a signed-in user. The application can read
users in Azure AD.
1. Go to Fork environment .
2. Add a label for the fork. This can be any text.
3. Under Workspace, ensure that My Workspace is selected in the dropdown list.
4. Select Fork Environment.
5. In ClientID , set the Current value to the application (client) ID value from step
3.16.
6. In ClientSecret , set the Current value to the client secret value from step 3.18.
7. In TenantID , set the Current value to the directory (tenant) ID value from step 3.16.
8. On the top right, select Save.
9. Close the Manage Environments tab.
10. On the top right, next to the eye icon, verify that M365 Environment is selected in
the dropdown and not No environment.
You now have a valid access token to use for delegated requests.
1. Expand the Delegated folder, and then expand the Mail folder.
2. Double-click Get my messages to open the request.
3. On the top right, select Send.
You have now successfully made a Microsoft Graph call using delegated authentication.
You now have a valid access token to use for application requests.
1. Expand the Application folder, and then expand the User folder.
2. Double-click Get Users to open the request.
3. On the top right, select SendAccess to OData is disabled.
You have now successfully made a Microsoft Graph call using application authentication.
You can follow these steps to make other requests to Microsoft Graph. Remember that
you have to add permissions to your Azure AD application for other requests to work;
otherwise, you get permission denied errors in your responses.
Known issues
Authentication fails with "You can't get there from here"
Certain conditional access policies configured by your organization's administrators can
block the authentication flow from Postman. To explore alternatives, contact your
administrators.
See also
Use Postman with the Microsoft Graph connectors API
Migrate your apps from Azure AD
Graph to Microsoft Graph
Article • 01/27/2023
) Important
Azure Active Directory (Azure AD) Graph is deprecated and will be retired at any
time after June 30, 2023, without advance notice, as we announced in September,
2022 . Though we reserve the right to turn it off after June 30, 2023, we want to
ensure all customers migrate off and discourage applications from taking
production dependencies on Azure AD Graph. Investments in new features and
functionalities will only be made in Microsoft Graph and we'll only make security-
related fixes to Azure AD Graph.
Microsoft Graph is also more secure and resilient than Azure AD Graph.
Microsoft Graph has all the capabilities that have been available in Azure AD Graph and
new APIs like identity protection and authentication methods. Its client libraries offer
built-in support for features like retry handling, secure redirects, transparent
authentication, and payload compression.
The rest of the articles in this section help you migrate your app from Azure AD Graph
to Microsoft Graph. You'll find:
Send any other questions, open issues, and feature requests through Microsoft Q&A by
using the tag azure-ad-graph-deprecation.
Next steps
Walk through the app migration checklist to help you plan the migration.
Explore Microsoft Graph concepts and practices.
Use Graph Explorer to experiment with Microsoft Graph.
Learn more about progress updates and timelines in Microsoft Graph or the Azure
AD Graph.
Get answers to questions you might have about the migration.
Azure AD Graph app migration planning
checklist
Article • 01/27/2023
Use the following checklist to plan your migration from Azure Active Directory (Azure
AD) Graph to Microsoft Graph.
Nonetheless, there are differences. Certain resources, properties, methods, and core
capabilities have changed.
Verify that the APIs your app needs are generally available in Microsoft Graph v1.0 and
that these APIs work the same way.
In some cases, new capabilities and features are designed to replace earlier approaches.
Use Graph Explorer to experiment with new calls and to develop new approaches. For
best results, sign in using the credentials of a test user in a test tenant so that you see
what the API does over important data sets.
Step 3: Review app details
App registration and consent changes (which should be none).
Token acquisition and authentication libraries.
For .NET applications, use of client libraries.
Now you've made the switch to Microsoft Graph, it's never been easier for you to unlock
many more datasets and features that are now at your fingertips. You can get a taste of
what's possible by looking at some of the Major services and features in Microsoft
Graph.
Next steps
Learn about request call syntax to start step 1: reviewing API differences.
Request differences between Azure AD
Graph and Microsoft Graph
Article • 01/27/2023
This article is part of step 1: review API differences of the process to migrate apps.
Microsoft Graph and the Azure Active Directory (Azure AD) Graph API are both REST APIs
and they each support OData conventions for query parameters. However, the syntax
varies between these two APIs.
Use Graph Explorer to try these request patterns against your own data, as it's a great
way to learn about the request and response differences.
Basic requests
The following table highlights the main request differences between the two APIs:
Service endpoints:
{tenant_id} Specify the ID of the tenant in the It's optional to specify a tenant ID in the
request. request as it is inferred from the access
token.
{version} Specify the release version of Azure AD Specify the release version of Microsoft
Graph in the request using a required Graph in the request as part of the URL
query parameter. path just after the service endpoint.
You can continue to use the same query parameters in Microsoft Graph as Azure AD
Graph.
GET https://graph.windows.net/contoso.com/users?
$filter=startswith(givenName,'Dan')&api-version=1.6 or
GET https://graph.windows.net/myOrganization/users?
$filter=startswith(givenName,'Dan')&api-version=1.6
This request:
Results include users with names like Daniel, Danforth, Danielle, Danerys, and so on.
GET https://graph.microsoft.com/v1.0/users?$filter=startswith(givenName,'Dan')
Here:
NOTE: If you're using the Azure AD Graph .NET client library, see .NET client libraries
for more specific strategies and assistance to move to the Microsoft Graph .NET
client library.
Microsoft Graph get or list operations for user or group resources returns only a subset
of all properties, known as the default properties. The default properties represent the
most commonly-used properties for a resource. On the other hand, Azure AD Graph
returns the full set of all properties for the respective resource.
To get other properties in v1.0, your app needs to explicitly request them, using the
$select query parameter. This includes any directory schema extensions your app might
be using. It's a best practice to only request the properties your app really needs.
To illustrate the difference, use Graph Explorer to run the following requests and compare
the different responses.
HTTP
GET https://graph.microsoft.com/v1.0/me/
GET https://graph.microsoft.com/beta/me/
Review the responses from each query. You'll notice that address information is returned
by the /beta version, but not the /v1.0 version. That's because the address properties
aren't in the default property set.
If your app relies on the address properties, you need to update your v1.0 requests to
include the $select query parameter:
HTTP
https://graph.microsoft.com/v1.0/me/?
$select=displayName,streetAddress,city,state,postalCode
The response for this request would include the address properties. It also includes the
displayName property, but only because it was specified by the query parameter.
Relationships also define memberships, such as the groups a user belongs to, the
members belonging to a group or a directory role, and so on.
When migrating your apps to Microsoft Graph, look for requests that use $links to
associate resources; change these to use $ref instead.
Next Steps
Learn about service feature differences between Azure AD Graph and Microsoft
Graph.
Review the checklist again.
Feature differences between Azure AD
Graph and Microsoft Graph
Article • 01/27/2023
This article is part of step 1: review API differences of the process to migrate apps.
Many features in Microsoft Graph work similarly to their Azure Active Directory (Azure
AD) Graph counterparts. However, a few have been changed or improved. Here, you'll
learn how to adapt your apps to take advantage of these differences. Frequently, the
changes are minor, but well worth the effort.
Directory extensions
If your app uses Azure AD Graph directory extensions, you can continue to use the same
basic APIs (with Microsoft Graph request URLs) to:
Then, you can switch to using Microsoft Graph schema extensions. In some cases,
switching will not be appropriate. Do not switch if:
To switch to the newer Microsoft Graph schema extension model, you'll need to:
Differential queries
Azure AD Graph and Microsoft Graph let you track changes using queries. The high-
level approach is similar between the two APIs, but the syntax is different.
Azure AD Graph calls these differential queries. In Microsoft Graph, they're delta queries.
Sync from now Uses a custom HTTP header: Uses a query parameter:
ocp-aad-dq-include-only- GET /groups/delta?$deltaToken=latest
delta-token: true
Delta request Azure AD Graph Microsoft Graph
Track changes Gets changes for multiple Uses separate queries with Microsoft Graph,
for resource (user and group) in one for each resource.
directoryObjects the same operation:
GET /directoryObject?
$filter=isof('User') or
isof('Group')&deltaLink=
Response Indicates a deleted item with Indicates a deleted item with the @removed
indicating an additional property of annotation. It may also contain a reason code,
deleted items aad.isDeleted set to true. which indicates if the item is deleted, but can
be restored, or is permanently deleted.
If your app is already storing state data, consider using the "sync from now" shown
earlier to help manage the transition to delta queries.
Batching
Azure AD Graph used a system called multi-part MIME messages to manage batching.
Microsoft Graph uses JSON batching to permit up to 20 requests in a single batch
operation. The JSON batching mechanism is significantly simpler to use, especially
together with JSON parsing libraries. It also allows for sequencing batch operations.
However, it is not backwards compatible with the Azure AD Graph batching approach.
Next Steps
Learn about resource differences between Azure AD Graph and Microsoft Graph.
Review the checklist again.
Resource type differences between
Azure AD Graph and Microsoft Graph
Article • 01/27/2023
This article is part of step 1: review API differences of the process to migrate apps.
When migrating apps from Azure Active Directory (Azure AD) Graph to Microsoft Graph,
be aware that some resources have different names and different types. For example, if
your Azure AD Graph app uses the TenantDetail resource, you'll need to update your
code to refer to organization instead.
The following table highlights differences between Azure AD Graph and Microsoft Graph
resources. It shows resources that have different names or are not available; it also
highlights resources available in the beta version of Microsoft Graph but not in the v1.0
version.
If a resource is not shown in this list, it is already available in the v1.0 version of
Microsoft Graph, with the same name as in Azure AD Graph.
7 Note
Next Steps
Learn about entity property differences between Azure AD Graph and Microsoft
Graph.
Review the checklist again.
Property differences between Azure AD Graph and
Microsoft Graph
Article • 01/27/2023
This article is part of step 1: review API differences of the process to migrate apps.
In general, the best way to compare the Azure Active Directory (Azure AD) Graph API to Microsoft Graph is to compare the
underlying metadata for each service, especially the resource descriptions:
This article highlights property differences between resources. If a property is not shown in this list, it is already available in
the v1.0 version of Microsoft Graph, with exactly the same name as in Azure AD Graph.
Because the user and group resources are so frequently used, they're listed first. Other resources are listed alphabetically.
The Microsoft Graph v1.0 endpoint returns a limited set of user properties by default, while Azure AD Graph returns all
properties. To read other properties that aren't returned by default, specify them in a $select query. For more information,
see the user resource type.
passwordProfile/forceChangePasswordNextLogin beta -
passwordProfile/forceChangePasswordNextSignInWithMfa
v1.0 -
passwordProfile/forceChangePasswordNextSignInWithMfa
Azure AD Graph Microsoft Graph Comments
(v1.6) property property
provisioningErrors beta - Not available This property and its information is deprecated. However, a new property
v1.0 - Not available describing any AD Connect related provisioning errors can be found in
onPremisesProvisioningErrors
id beta - appRoleId
v1.0 - appRoleId
city beta - addresse/city The city property is part of the addresses resource collection.
v1.0 - addresses/city
country beta - addresses/countryOrRegion The countryOrRegion property is part of the addresses resource
v1.0 - addresses/countryOrRegion collection.
facsimileTelephoneNumber beta - phones/businessFax Now part of the phones collection which supports various phone
v1.0 - phones/businessFax types.
postalCode beta - addresses/postalCode The postalCode property is part of the addresses resource collection.
v1.0 - addresses/postalCode
provisioningErrors beta - not available This property and its information is deprecated. However, a new
v1.0 - not available property describing any AD Connect related provisioning errors can
be found in onPremisesProvisioningErrors. Currently this is only
available in beta .
state beta - addresses/state The state property is part of the addresses resource collection.
v1.0 - addresses/state
streetAddress beta - addresses/street The street property is part of the addresses resource collection.
v1.0 - addresses/street
telephoneNumber beta - phones/business Now part of the phones collection which supports various phone
v1.0 - phones/business types.
deletionTimestamp beta - deletedDateTime While deletionTimestamp was a DateTime type, deletedDateTime is a DateTimeOffset
v1.0 - type.
deletedDateTime
objectId beta - id The id property in Microsoft Graph is inherited from the entity resource.
v1.0 - id
objectType beta - Not available This property is not used in Microsoft Graph. Instead, Microsoft Graph returns the
v1.0 - Not available @odata.type property but only for APIs that might return objects of different types or
derived types. For example, the List group members API might return members who are
users, groups, service principals, organizational contacts, or devices. For users, the
@odata.type is #microsoft.graph.user .
name beta - id In Microsoft Graph, the unique identifier (id) contains the domain name; the
v1.0 - id name property doesn't exist.
forceDeleteState beta - state In Azure AD Graph, there are separate forceDelete and domain state
v1.0 - state properties. In Microsoft Graph, all domain states are handled by the state
property.
expiryTime beta - expiryTime This property is not used and is removed in Microsoft Graph v1.0.
v1.0 - Removed
startTime beta - startTime This property is not used and is removed in Microsoft Graph v1.0.
v1.0 - Removed
provisioningErrors beta - Not available This property and its information is deprecated.
v1.0 - Not available
authorityType beta - isRootAuthority This property's type has also changed into a Boolean. Previously
v1.0 - isRootAuthority this property had to be set to either "RootAuthority" or
"IntermediateAuthority". Setting the new property to true is
equivalent to "RootAuthority".
Next Steps
Learn about method differences between Azure AD Graph and Microsoft Graph.
Review the checklist again.
Method differences between Azure AD
Graph and Microsoft Graph
Article • 01/27/2023
This article is part of step 1: review API differences of the process to migrate apps.
A handful of Azure Active Directory (Azure AD) Graph methods have also changed. If a method
is not shown in this list, it is already available in the v1.0 version of Microsoft Graph, with exactly
the same name as in Azure AD Graph.
restore beta - restore (applications, users, and groups) You can also view
v1.0 - restore (applications, users, and groups) deleted applications,
users, and groups
and permanently
delete them.
Next Steps
Learn about permissions differences between Azure AD Graph and Microsoft Graph.
Review the checklist again.
Permissions differences between Azure
AD Graph and Microsoft Graph
Article • 01/27/2023
This article is part of step 1: review API differences of the process to migrate apps.
The least privileged permission for a specific scenario might be different between Azure
AD Graph and Microsoft Graph. When migrating your apps to call Microsoft Graph,
analyze whether you also need to migrate to more narrowly scoped Microsoft Graph
permissions to maintain least privilege.
For example, on Azure AD Graph, reading users in app-only scenarios requires the
Directory.Read.All permission. This permission also allows your app to read all the
groups, apps, and some policies in your tenant. However, on Microsoft Graph, reading
users in app-only scenarios requires only the User.Read.All permission.
While the permission strings might be the same in both Azure AD Graph and Microsoft
Graph, they have different identifiers. However, similar to Azure AD Graph, Microsoft
Graph also exposes both application and delegated permissions. In addition, admin
consent is always required for application permissions.
Application.Read.All
Delegated
Application
Application.ReadWrite.All
Delegated
Application
Application.ReadWrite.OwnedBy
Delegated
Not applicable.
Application
Display Manage apps that this app creates or Manage apps that this app creates or
String owns owns
Device.ReadWrite.All
Delegated
Not applicable.
Application
Directory.Read.All
Delegated
Application
Directory.ReadWrite.All
Delegated
Display String Read and write directory data Read and write directory data
Application
Display Read and write directory data Read and write directory data
String
Directory.AccessAsUser.All
Delegated
Display String Access the directory as the signed- Access the directory as the signed-
in user in user
Domain.ReadWrite.All
Delegated
Application
Group.Read.All
Delegated
Application
----------------- ----------------- ---------------------------------------
Group.ReadWrite.All
Delegated
Display String Read and write all groups Read and write all groups
Application
Member.Read.Hidden
Delegated
Policy.Read.All
Delegated
Application
User.Read
Delegated
Display String Sign in and read user profile Sign in and read user profile
Parameter Azure AD Graph Microsoft Graph
Admin consent No No
required?
Application
Not applicable.
User.ReadBasic.All
Delegated
Display String Read all users' basic profiles Read all users' basic profiles
Admin consent No No
required?
Application
User.Read.All
Delegated
Display String Read all users' full profiles Read all users' full profiles
Parameter Azure AD Graph Microsoft Graph
Application
Next Steps
Learn how to examine API differences in your app between Azure AD Graph and
Microsoft Graph.
Review the checklist again.
Examine Azure AD Graph APIs app
usage
Article • 01/27/2023
While planning your migration to Microsoft Graph, take time to review your existing
application and to catalog the Azure Active Directory (Azure AD) Graph APIs you're
currently using.
Compare your list to the known differences. This helps identify specific changes you'll
need to make to migrate your app. These include simple changes easily resolved using
an editor's search-and-replace features or more complicated updates that might require
more analysis.
Microsoft Graph supports many of the same features and capabilities of Azure AD
graph. There are a few key differences:
Request differences
Feature differences
Resource type differences
Property differences
Method differences
Permissions differences
You'll also want to verify the permissions required for the features your app is using. In
some cases, more granular permissions are available.
Next Steps
Learn about app registration, permissions and consent differences between Azure
AD Graph and Microsoft Graph.
Review the checklist again.
Review app registration, permissions,
and consent
Article • 01/27/2023
This article is part of step 3: review app details of the process to migrate apps.
App registration: You can continue to use your existing app registration ( appId ) in
your application code.
You do not have to re-register your app to migrate to Microsoft Graph. Simply
update the code, test heavily, and then deploy your update.
If your update also includes the use of features or capabilities that aren't available
to Azure AD Graph, you'll likely need to request permissions for these new
features. If that's the case, you can switch your app to use MSAL and the v2
endpoint, and request additional/incremental consent dynamically. Find more
details about switching to MSAL in review app authentication library changes.
Consent: End-users who have already granted consent for delegated permissions
(or for whom consent has already been granted by an admin) can continue using
your app without being asked to grant consent again.
Users who have already granted consent to your app to access their data can
continue to use your app after it's been updated to use Microsoft Graph, without
being asked to consent again. New users will be prompted for consent.
However, if you use new features, services, or add additional capabilities, you may need
new permissions and end-user consent may be required. In such cases, consent is
requested when tokens are refreshed.
Next Steps
Learn authentication library differences between Azure AD Graph and Microsoft
Graph.
Review the checklist again.
Review app authentication library
changes
Article • 01/27/2023
This article is part of step 3: review app details of the process to migrate apps.
Most apps use an authentication library to acquire and manage access tokens to call
Microsoft Graph. Microsoft offers two authentication libraries:
Updating ADAL
If your app currently uses ADAL, use a two-stage migration approach:
1. Update your app to acquire access tokens for Microsoft Graph. Continue to use
ADAL for this step. Update the resourceURL, which holds the URI representing the
resource web API, from:
https://graph.windows.net
To:
https://graph.microsoft.com
Newly acquired tokens have the same scopes after this change, but the audience
of the access tokens is now Microsoft Graph.
2. Next, begin work migrating your app to use MSAL, which is the supported library
to use moving forward, now that ADAL is deprecated.
Migrating to MSAL
MSAL provides multiple benefits over ADAL, including incremental consent, richer single
sign-on experiences, support for personal Microsoft accounts, use of standards-based
protocols and so on.
When you switch your app over to MSAL, you'll need to make a few changes, including
setting the scopes parameter in the token acquisition request:
C#
The expression above limits the permission scopes request to those configured during
application registration in the Azure Portal, and saves your existing users from having to
consent to your app again.
See Migrating ADAL to MSAL for direct and extensive help with the process, including
troubleshooting and help with common errors.
Once you've migrated to MSAL, you can request additional scopes dynamically, and
users are prompted to provide incremental consent the next time they use your app.
Next Steps
Learn .NET client library differences between Azure Active Directory (Azure AD)
Graph and Microsoft Graph.
Review the checklist again.
Migrate .NET client library use to
Microsoft Graph
Article • 01/27/2023
This article is part of step 3: review app details of the process to migrate apps.
If your app currently uses the Azure Active Directory (Azure AD) Graph client library,
switch to the Microsoft Graph .NET client library .
NOTE: The Microsoft Graph .NET client library is only supported for .NET Framework
4.5 and .NET Standard 1.1. However please consult Microsoft Graph .NET client
library for the latest support information.
Here, we'll look at some general steps to migrate over to the Microsoft Graph .NET
client library:
How to create a Microsoft Graph client, given an access token (that you can
acquire using either Azure Active Directory Authentication Library (ADAL) or
Microsoft Authentication Library (MSAL))
How to formulate requests
How to use query builders
How to handle collections and paging
2. In your app, update references to the Microsoft Graph client library by changing:
C#
using Microsoft.Azure.ActiveDirectory.GraphClient;
To:
C#
using Microsoft.Graph;
3. Use your package manager to download and update the Microsoft Graph NuGet
package and update dependencies.
Change:
C#
To:
C#
For Microsoft Graph client library, the serviceRoot value also includes the version
number. Currently, that value is https://graph.microsoft.com/v1.0 .
5. Update requests to use the Microsoft Graph client request builder syntax, by
changing:
C#
To:
C#
To do so, change:
C#
To:
C#
6. If your code pages through collections, make the following minor adjustments. The
following example compares and contrasts fetching a group and paging through
its members, 5 at a time. While the code for Azure AD Graph requires a fetcher
construct in order to fetch a group's members, Microsoft Graph has no such
requirement. Other than that, the code is relatively similar. To be concise, only user
members are displayed, try/catch and error conditions are not shown, and the
code snippets are for a single-threaded console app.
As an example, change the following code using the Azure AD Graph .NET client
library:
C#
var membersPage =
retrievedGroupFetcher.Members.Take(5).ExecuteAsync().Result;
Console.WriteLine(" Members:");
do
{
List<IDirectoryObject> members = membersPage.CurrentPage.ToList();
foreach (IDirectoryObject member in members)
{
if (member is User)
{
User memberUser = (User)member;
Console.WriteLine(" User: {0} ",
memberUser.DisplayName);
}
}
membersPage = membersPage.GetNextPageAsync().Result;
} while (membersPage != null);
To the following code using the Microsoft Graph .NET client library:
C#
var membersPage =
client.Groups[id].Members.Request().Top(5).GetAsync().Result;
Console.WriteLine(" Members:");
do
{
List<DirectoryObject> members = membersPage.CurrentPage.ToList();
foreach (DirectoryObject member in members)
{
if (member is User)
{
User memberUser = (User)member;
Console.WriteLine(" User: {0} ",
memberUser.DisplayName);
}
}
if (membersPage.NextPageRequest != null)
membersPage = membersPage.NextPageRequest.GetAsync().Result;
else membersPage = null;
} while (membersPage != null);
7. Build and fix any resource, property, navigation, and service action errors, generally
related to name changes.
See also
The C# console snippets app highlights more of the differences between Microsoft
Graph client library and Azure AD Graph client library.
The Azure AD Graph client library supports only the .NET platform. However, Microsoft
Graph client library supports additional platforms and languages that you may find
more useful for your solutions.
Next Steps
Learn how to deploy, test, and extend apps you've migrated to Microsoft Graph.
Review the checklist again.
Deploy, test, and extend
Article • 01/27/2023
1. Test throughly
Once you've updated your app, test it thoroughly to verify that it works as
expected and that you haven't introduced any regressions.
Be sure to use multiple environments, data sets, and end-user personas, e.g.
credentials with different roles, rights, and responsibilities. Go through the entire
lifecycle, by having a new test user acquire the app for the first time, as well as an
existing user (who already consented) trying to use the app again.
If the initial roll-out goes well, monitor progress as you deploy to larger audiences.
Now you've made the switch to Microsoft Graph, it's never been easier for you to
unlock many more datasets and features that are now at your fingertips. Microsoft
Graph supports many new Azure Active Directory (Azure AD) datasets and features
that are not available in Azure Active Directory (Azure AD) Graph.
Microsoft Graph offers access to many more services than just Azure Active
Directory. It's the API gateway to Microsoft 365 services too. Check for new
datasets and capabilities regularly.
Next Steps
Use quick starts and samples to come up to speed quickly.
Leverage client libraries and SDKs to develop custom applications
Explore Microsoft Graph concepts and practices.
Use Graph Explorer to experiment with Microsoft Graph.
Azure AD Graph to Microsoft Graph
migration FAQ
Article • 01/27/2023
This article provides answers to frequently asked questions about migrating from Azure
Active Directory (Azure AD) Graph to Microsoft Graph.
Microsoft Graph is also more secure and resilient than Azure AD Graph. For this reason,
Azure AD Graph has been on a deprecation path since June 30, 2020, and will be retired
in the near future as we move all investments to Microsoft Graph. After the retirement,
your apps will receive error responses from the Azure AD Graph endpoint. Migrate to
Microsoft Graph to avoid loss of functionality.
4. In the App registrations window, enable the App registrations search preview.
Select the All Applications tab then select the Add filters option. Choose the
Application (client) ID option from the list of available filters and select Apply. A
filter pops up.
5. In the text box, enter the app ID you retrieved in Step 1 and select Apply. The list
has narrowed down to the specified app.
7. From the left pane of the window, select API permissions. This reveals configured
API permissions for your app, including Azure AD Graph permissions.
As an IT admin, how do I identify apps in my
tenant that use Azure AD Graph?
Use one of the following three methods to identify apps in your tenant with a
dependency on Azure AD Graph.
4. In the App registrations window, enable the App registrations search preview.
Select the All Applications tab then select the Add filters option. Choose the
Requested API option from the list of available filters and select Apply. The
Requested API filter pops up.
5. Select Microsoft APIs. Select the Please select an API drop down and choose
Azure Active Directory Graph. Select Apply. This lists all apps with a dependency
on Azure AD Graph.
Method 3: Use a PowerShell script
Download and run this PowerShell script . Use this method to retrieve apps with their
home directory in your tenant and apps with their home directories in other tenants.
4. In the App registrations window, enable the App registrations search preview.
Select the All Applications tab then select the Add filters option. Choose the
Application (client) ID option from the list of available filters and select Apply. A
filter pops up.
5. Enter an app ID in the text box and select Apply. The list has narrowed down to the
specified app.
6. Select the app. This reveals the app's menu. From the left pane of the window,
menu options such as Owners allow you to retrieve the app's details.
3. In the relevant directory, search for and select Azure Active Directory. This reveals
a menu for your active tenant.
4. From the left pane of the window, under Manage, select Properties.
5. In the Tenant properties window, first verify the value of Tenant ID matches a
tenant ID you received in the email. Retrieve the Technical contact details to
contact the tenant so they can be aware of the deprecation.
6. From the left pane of the window, menu options reveal the app's details including
its Owners.
My organization runs Azure Stack Hub. What
actions should I take?
If your organization runs Azure Stack Hub, the most important action is to follow the
Azure Stack Hub servicing policy.
To migrate, customers will be notified through the Azure Stack Hub admin portal to
update their home and guest tenant directories. The migration to Microsoft Graph will
be managed by the integrated system update experience.
If you still need to configure Azure AD Graph permissions for your applications, use one
of the following workarounds.
Use the Azure portal to find the APIs your organization uses
Update the application manifest on the Azure portal
Use the application API in Microsoft Graph to update the requiredResourceAccess
object
Use the Update-MgApplication cmdlet in Microsoft Graph PowerShell SDK
For examples using the listed workarounds, see Use Microsoft Graph to configure
required Azure AD Graph permissions for an app registration
See also
Checklist to migrate apps
Configure required Azure AD Graph
permissions for an app registration
Article • 03/02/2023
Azure Active Directory (Azure AD) Graph is deprecated and will be retired in the near
future. As part of this deprecation path, adding Azure AD Graph permissions to an app
registration through the Azure portal is now disabled. We recommend that you follow
the App migration planning checklist to help you transition your apps to Microsoft
Graph API.
However, your app might still temporarily require Azure AD Graph permissions to access
resources. This article describes the following four methods for configuring required
Azure AD Graph permissions for your app registration:
1. Use the Azure portal to find the APIs your organization uses
2. Update the application manifest on the Azure portal
3. Use the Microsoft Graph API
4. Use the Microsoft Graph PowerShell SDK
U Caution
Any app using Azure AD Graph will still stop functioning after the Azure AD Graph
API retirement. For more information, see Migrate Azure AD Graph apps to
Microsoft Graph.
4. In the App registrations window, under the All applications tab, select the app for
which you wish to add Azure AD Graph permissions. This opens the app
registration's Overview pane.
5. From the left pane of the window, under the Manage menu group, select API
permissions. This reveals the Configured permissions for your app registration.
Select Add a permission.
6. In the Request API permissions window that's revealed, switch to the APIs my
organization uses tab and search for Windows Azure Active Directory or
00000002-0000-0000-c000-000000000000 . Select from the filtered list to reveal the
Azure Active Directory Graph permissions window.
8. After adding the permissions you need, back in the Configured permissions
window, select Grant admin consent to grant the Azure AD Graph permissions to
your app registration.
4. In the App registrations window, under the All applications tab, select the app for
which you wish to add Azure AD Graph permissions. This opens the app
registration's Overview pane.
5. From the left pane of the window, under the Manage menu group, select
Manifest. This opens up an editor that allows you to directly edit the attributes of
the app registration object.
6. Carefully edit the requiredResourceAccess property in the app's manifest file to
add the following details:
Note: You can edit the app manifest on the Azure portal or select Download to
edit the manifest locally, and then use Upload to reapply it to your application.
JSON
"requiredResourceAccess": [
{
"resourceAppId": "00000002-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "311a71cc-e848-46a1-bdf8-97ff7156d8e6",
"type": "Scope"
},
{
"id": "3afa6a7d-9b1a-42eb-948e-1650a849e176",
"type": "Role"
}
]
}
],
7. Save your changes.
8. Select API permissions and in the Configured permissions for your app
registration, select Grant admin consent to grant the Azure AD Graph permissions
to your app registration.
Prerequisites
To complete the following steps, you need the following resources and privileges:
Run the HTTP requests in a tool of your choice, for example in your app, through
Graph Explorer , or Postman.
Run the APIs as a user in a Global Administrator or Application Administrator role,
or as owner of the target app registration. For more information about the actions
supported by these roles, see Azure AD built-in roles.
The app used to make these changes must be granted the
Application.ReadWrite.All permission.
displayName and appDisplayName. Run the following request to retrieve the service
principal object for Azure AD Graph.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/servicePrincipals?$filter=appId eq
'00000002-0000-0000-c000-000000000000'
Response
In the response object, details for Azure AD Graph application permissions are listed in
the appRoles object while details for delegated permissions are listed in the
oauth2PermissionScopes object.
Note: The response object shown here might be shortened for readability.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#servicePrincipals",
"value": [
{
"id": "1804a6f8-e623-4520-8f40-ba1b0c11c42d",
"accountEnabled": true,
"appDisplayName": "Windows Azure Active Directory",
"appDescription": null,
"appId": "00000002-0000-0000-c000-000000000000",
"appOwnerOrganizationId": "f8cdef31-a31e-4b4a-93e4-
5f571e91255a",
"appRoleAssignmentRequired": false,
"displayName": "Windows Azure Active Directory",
"servicePrincipalNames": [
"https://graph.windows.net",
"00000002-0000-0000-c000-
000000000000/graph.microsoftazure.us",
"00000002-0000-0000-c000-000000000000/graph.windows.net",
"00000002-0000-0000-c000-
000000000000/directory.windows.net",
"00000002-0000-0000-c000-000000000000",
"https://graph.windows.net/",
"https://graph.microsoftazure.us"
],
"servicePrincipalType": "Application",
"signInAudience": "AzureADMultipleOrgs",
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "Allows the app to read applications and
service principals without a signed-in user",
"displayName": "Read all applications",
"id": "3afa6a7d-9b1a-42eb-948e-1650a849e176",
"isEnabled": true,
"origin": "Application",
"value": "Application.Read.All"
}
],
"oauth2PermissionScopes": [
{
"adminConsentDescription": "Allows users to sign in to
the app, and allows the app to read the profile of signed-in users. It also
allow the app to read basic company information of signed-in users.",
"adminConsentDisplayName": "Sign in and read user
profile",
"id": "311a71cc-e848-46a1-bdf8-97ff7156d8e6",
"isEnabled": true,
"type": "User",
"userConsentDescription": "Allows you to sign in to the
app with your work account and let the app read your profile. It also allows
the app to read basic company information.",
"userConsentDisplayName": "Sign you in and read your
profile",
"value": "User.Read"
}
]
}
]
}
) Important
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/581088ba-83c5-4975-
b8af-11d2d7a76e98
Content-Type: application/json
{
"requiredResourceAccess": [
{
"resourceAppId": "00000002-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "311a71cc-e848-46a1-bdf8-97ff7156d8e6",
"type": "Scope"
},
{
"id": "3afa6a7d-9b1a-42eb-948e-1650a849e176",
"type": "Role"
}
]
}
]
}
Response
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/applications/581088ba-83c5-4975-b8af-
11d2d7a76e98?$select=id,requiredResourceAccess
Note: Though you've configured the permissions the app requires, these
permissions haven't been granted. Many permissions require admin consent before
they can be used to access organizational data.
Prerequisites
To complete the following steps, the following privileges are required:
Request
Create a new PowerShell script named fetchPermissions.ps1 and add the following code.
This code retrieves Azure AD Graph permission IDs and types. The output displays and
formats the output of the AppRoles and Oauth2PermissionScopes objects.
PowerShell
PowerShell
.\fetchPermissions.ps1
Response
The following is an example of the output.
PowerShell
Delegated permissions:
) Important
PowerShell
@{
# Application.Read.All app role (application permission) to
view application data
id = "3afa6a7d-9b1a-42eb-948e-1650a849e176";
type = "Role";
}
)
}
## If the app already has existing permissions from our new permissions
resource
else {
$newResourceAccess.ResourceAccess +=
$existingResourceAccess.ResourceAccess
Update-MgApplication -ApplicationId $applicationId -
RequiredResourceAccess $newResourceAccess
}
PowerShell
.\updatePermissions.ps1
Response
The following is an example of the output.
PowerShell
Note: Though you've configured the permissions the app requires, these
permissions haven't been granted. Many permissions require admin consent before
they can be used to access organizational data.
See also
application API
Update-MgApplication
Grant permissions programmatically without interactive consent
Migrate Exchange Web Services (EWS)
apps to Microsoft Graph
Article • 07/01/2022
Exchange Web Services (EWS) is a legacy protocol that has been in usage since
Exchange Server 2007. In August 2018, Microsoft announced that there will not be any
active investment in EWS APIs for Exchange Online. It is strongly recommended to
migrate your EWS apps that access Exchange Online to Microsoft Graph.
Security
Microsoft Graph has stricter security and governance policies with OAuth and granular
scoping to limit data access in a mailbox as opposed to the all or none access model in
EWS.
Developer simplicity
Microsoft Graph offers Graph Explorer to discover and test APIs easily and quickly, SDKs
in different programming languages, and an active developer community.
REST efficiency
Microsoft Graph APIs are REST-based, where EWS APIs are SOAP-based. The advantage
of using REST-based protocols include faster JSON serialization and lower network
usage.
Next steps
Learn about authentication differences in Microsoft Graph and EWS.
Review API mappings to find Microsoft Graph equivalents for the EWS APIs you
currently use.
Explore Microsoft Graph concepts and practices.
Use Graph Explorer to experiment with Microsoft Graph.
Authentication differences between
Exchange Web Services (EWS) and
Microsoft Graph
Article • 05/19/2022
Exchange Web Services (EWS) and Microsoft Graph both use Microsoft identity platform
OAuth 2.0 for authentication and authorization.
7 Note
Permissions
EWS and Microsoft Graph offer two types of permissions: delegated and application.
Delegated permissions are in the context of an authenticated user. Application
permissions are granted to an application that does not act on a user's behalf.
With EWS, an application has access to everything that the user has access to (in the
case of delegated permissions) or everything that EWS can access (with application
permissions).
EWS has all or nothing access model and there is no granular scoping for limiting data
access in a mailbox. Whereas, Microsoft Graph offers granular permissions to specific
features within an Exchange Online mailbox. For example, it is possible to allow an
application to only read mail messages, and have no access to calendars or contacts.
The effective permissions for delegated authentication is the intersection of the user's
privileges and the permissions that have been consented for the application. For
application authentication, the effective permissions are the set of permissions
consented to by an administrator.
Mail permissions
Calendar permissions
Personal contacts permissions
Tasks permissions
Impersonation
EWS impersonation provides a mechanism for EWS applications that run as a service
account to act as a user. This allows the app to take actions, such as sending an email,
that appear to come from the impersonated user.
With Microsoft Graph, there are no service accounts. Instead, permissions are granted to
applications directly. The application authenticates using client credentials flow with its
own identity. By default, admin consent grants access to all users' mailboxes, but apps
can be limited to specific mailboxes by an administrator. The way to achieve
Impersonation in Microsoft Graph is by making use of app-access policy and application
permissions.
Exchange Web Services (EWS) to
Microsoft Graph API mappings
Article • 05/19/2022
This article lists the Microsoft Graph APIs that map to Exchange Web Services (EWS)
APIs.
Utility APIs
EWS API Microsoft Graph API
Mail APIs
Messages
Folders
Attachments
Rules
MailTips
Notifications
7 Note
Microsoft Graph only requires a subscription for push notifications. If you are
currently using EWS pull notifications, see Get messages delta.
Synchronization
Calendar APIs
Availability
Reminders
Permissions
Invitations
GetSharingInvitation Sharee: Get a shared calendar or its events directly from calendar
owner's mailbox
Shared Information
GetUnifiedGroupsSettings groupSetting
SetUnifiedGroupUserSubscribeState Subscribe/unsubscribeByMail
JoinPrivateUnifiedGroup Subscribe/unsubscribeByMail
The Microsoft Graph SDKs are designed to simplify building high-quality, efficient, and
resilient applications that access Microsoft Graph. The SDKs include two components: a
service library and a core library.
The service library contains models and request builders that are generated from
Microsoft Graph metadata to provide a rich, strongly typed, and discoverable experience
when working with the many datasets available in Microsoft Graph.
The core library provides a set of features that enhance working with all the Microsoft
Graph services. Embedded support for retry handling, secure redirects, transparent
authentication, and payload compression improve the quality of your application's
interactions with Microsoft Graph, with no added complexity, while leaving you
completely in control. The core library also provides support for common tasks such as
paging through collections and creating batch requests.
Supported languages
SDKs are currently available for the following languages:
C#
PowerShell
TypeScript | JavaScript
Java
Go
PHP
Python (preview)
In addition, do not use a preview release of an SDK in production apps, regardless of the
version of Microsoft Graph API (v1.0 or beta) it uses.
A release of an SDK in GA status can use the Microsoft Graph API v1.0 endpoint or beta
endpoint as specified. Because Microsoft Graph APIs in the beta endpoint are subject to
breaking changes, do not use in production apps a GA release of an SDK that accesses
the Microsoft Graph API beta endpoint.
See also
For more details about the features and capabilities of the SDK, see the SDK design
requirements documentation .
Request or vote on additional features at the Microsoft 365 Developer Platform
ideas forum .
For a list of samples for Microsoft Graph, see the Microsoft Graph resources page.
Install a Microsoft Graph SDK
Article • 01/31/2023
Microsoft Graph SDKs are available to be included in your projects via GitHub and
popular platform package managers. This article describes how you can install a
Microsoft Graph SDK into your project.
.NET
Go (preview)
Java
JavaScript
PHP
PowerShell
Python (preview)
Microsoft.Graph : Contains the models and request builders for accessing the
v1.0 endpoint with the fluent API. Microsoft.Graph has a dependency on
Microsoft.Graph.Core.
Microsoft.Graph.Beta : Contains the models and request builders for accessing
the beta endpoint with the fluent API. Microsoft.Graph.Beta has a dependency on
Microsoft.Graph.Core.
Microsoft.Graph.Core : The core library for making calls to Microsoft Graph.
To install the Microsoft.Graph packages into your project, you can use either the
Package Manager UI in Visual Studio or the Package Manager Console. The following
Package Manager Console commands install the Microsoft.Graph and
Microsoft.Graph.Core libraries. Microsoft.Graph.Core is installed as a dependency of
Microsoft.Graph.
PowerShell
Install-Package Microsoft.Graph
The Microsoft Graph SDK for Go is currently in preview. Use of this SDK in
production is not supported.
Microsoft Graph SDK for Go : Contains the models and request builders for
accessing the v1.0 endpoint with the fluent API.
Microsoft Graph Beta SDK for Go : Contains the models and request builders for
accessing the beta endpoint with the fluent API.
Microsoft Graph Core SDK for Go : The core library for making calls to Microsoft
Graph.
Shell
go get github.com/microsoftgraph/msgraph-sdk-go
go get github.com/Azure/azure-sdk-for-go/sdk/azidentity
microsoft-graph : Contains the models and request builders for accessing the
v1.0 endpoint with the fluent API.
microsoft-graph-beta : Contains the models and request builders for accessing
the beta endpoint with the fluent API.
microsoft-graph-core : The core library for making calls to Microsoft Graph.
microsoft-graph-auth : Provides an authentication scenario-based wrapper of
Microsoft Authentication Library (MSAL) for use with the Microsoft Graph SDK.
Use Gradle to install the Microsoft Graph Java SDK. Add the repository and a
compile dependency for microsoft-graph to your project's build.gradle:
Gradle
repository {
mavenCentral()
}
dependency {
// Include the sdk as a dependency
implementation 'com.microsoft.graph:microsoft-graph:5.+'
// Include Azure identity for authentication
implementation 'com.azure:azure-identity:1.+'
}
Use Maven to install the Microsoft Graph Java SDK. Add the dependency in the
dependencies element in pom.xml:
XML
<dependency>
<groupId>com.microsoft.graph</groupId>
<artifactId>microsoft-graph</artifactId>
<version>[5.0,)</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>[1.3,)</version>
</dependency>
Shell
JSON
{
"require": {
"microsoft/microsoft-graph": "^1.8"
}
}
PowerShell
Install-Module Microsoft.Graph
If you're upgrading from the preview modules, run Install-Module with AllowClobber
and Force parameters to avoid command name conflicts:
PowerShell
) Important
The Microsoft Graph SDK for Python is currently in preview. Use of this SDK in
production is not supported.
py
pip install msgraph-sdk
See also
For more details about the features and capabilities of the SDK, see the SDK design
requirements documentation .
For a list of samples for Microsoft Graph, see the Microsoft Graph resources page.
For step-by-step training for creating a Microsoft Graph app, see the Microsoft
Graph tutorials.
Create a Microsoft Graph client
Article • 05/19/2023
The Microsoft Graph client is designed to make it simple to make calls to Microsoft
Graph. You can use a single client instance for the lifetime of the application. For
information about how to add and install the Microsoft Graph client package into your
project, see Install the SDK.
The following code examples show how to create an instance of a Microsoft Graph
client with an authentication provider in the supported languages. The authentication
provider will handle acquiring access tokens for the application. Many different
authentication providers are available for each language and platform. The different
authentication providers support different client scenarios. For details about which
provider and options are appropriate for your scenario, see Choose an Authentication
Provider.
C#
C#
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
//
https://learn.microsoft.com/dotnet/api/azure.identity.devicecodecredenti
al
var deviceCodeCredential = new DeviceCodeCredential(
callback, tenantId, clientId, options);
The Microsoft Graph SDK client configures a default set of middleware that allows the
SDK to communicate with the Microsoft Graph endpoints. This default set is
customizable, allowing you to change the behavior of the client. For example, you can
insert customized logging, or add a test handler to simulate specific scenarios. You can
add and remove middleware components. It is important to note that the order in which
middleware components run is significant.
C#
C#
// using Azure.Identity;
//
https://learn.microsoft.com/dotnet/api/azure.identity.interactivebrowser
credential
var interactiveCredential = new InteractiveBrowserCredential(...);
C#
C#
// URI to proxy
var proxyAddress = "http://localhost:8888";
Authentication providers implement the code required to acquire a token using the
Microsoft Authentication Library (MSAL); handle a number of potential errors for cases
like incremental consent, expired passwords, and conditional access; and then set the
HTTP request authorization header. The following table lists the set of providers that
match the scenarios for different application types.
Daemon app
7 Note
The following code snippets were written with the latest versions of their respective
SDKs. If you encounter compiler errors with these snippets, make sure you have the
latest versions. The authentication providers used are provided by the following
Azure Identity libraries:
C#
C#
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
//
https://learn.microsoft.com/dotnet/api/azure.identity.authorizationcodec
redential
var authCodeCredential = new AuthorizationCodeCredential(
tenantId, clientId, clientSecret, authorizationCode, options);
C#
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
//
https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcreden
tial
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
//
https://learn.microsoft.com/dotnet/api/azure.identity.clientcertificatec
redential
var clientCertCredential = new ClientCertificateCredential(
tenantId, clientId, clientCertificate, options);
On-behalf-of provider
The on-behalf-of flow is applicable when your application calls a service/web API which
in turns calls the Microsoft Graph API. Learn more by reading Microsoft identity platform
and OAuth 2.0 On-Behalf-Of flow
C#
The Azure.Identity package does not support the on-behalf-of flow as of version
1.4.0. Instead create a custom authentication provider using MSAL.
C#
// using Azure.Identity;
var options = new OnBehalfOfCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
Implicit provider
Implicit Authentication flow is not recommended due to its disadvantages . Public
clients such as native apps and JavaScript apps should now use the authorization code
flow with the PKCE extension instead. Reference .
C#
C#
var scopes = new[] { "User.Read" };
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
//
https://learn.microsoft.com/dotnet/api/azure.identity.devicecodecredenti
al
var deviceCodeCredential = new DeviceCodeCredential(
callback, tenantId, clientId, options);
C#
C#
C#
Interactive provider
The interactive flow is used by mobile applications (Xamarin and UWP) and desktops
applications to call Microsoft Graph in the name of a user. For details, see Acquiring
tokens interactively .
C#
C#
var scopes = new[] { "User.Read" };
// using Azure.Identity;
var options = new InteractiveBrowserCredentialOptions
{
TenantId = tenantId,
ClientId = clientId,
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
// MUST be http://localhost or http://localhost:PORT
// See https://github.com/AzureAD/microsoft-authentication-library-
for-dotnet/wiki/System-Browser-on-.Net-Core
RedirectUri = new Uri("http://localhost"),
};
//
https://learn.microsoft.com/dotnet/api/azure.identity.interactivebrowser
credential
var interactiveCredential = new InteractiveBrowserCredential(options);
Username/password provider
The username/password provider allows an application to sign in a user by using their
username and password. Use this flow only when you cannot use any of the other
OAuth flows. For more information, see Microsoft identity platform and the OAuth 2.0
resource owner password credential
C#
C#
//
https://learn.microsoft.com/dotnet/api/azure.identity.usernamepasswordcr
edential
var userNamePasswordCredential = new UsernamePasswordCredential(
userName, password, tenantId, clientId, options);
Next steps
For code samples that show you how to use the Microsoft identity platform to
secure different application types, see Microsoft identity platform code samples
(v2.0 endpoint).
Authentication providers require an client ID. You'll want to register your
application after you set up your authentication provider.
Let us know if a required OAuth flow isn't currently supported by voting for or
opening a Microsoft Graph feature request .
Access national cloud deployments with
the Microsoft Graph SDKs
Article • 03/02/2023
By default, the Microsoft Graph SDKs are configured to access data in the Microsoft
Graph global service, using the https://graph.microsoft.com root URL to access the
Microsoft Graph REST API. Developers can override this configuration to connect to
Microsoft Graph national cloud deployments.
Prerequisites
You will need the following information to configure a Microsoft Graph SDK to connect
to a national cloud deployment.
Application registration details, such as client ID, tenant ID, and client secret or
certificate. The application registration MUST be created in the Azure portal that
corresponds to the national cloud deployment. See App registration and token
service root endpoints for details.
The token endpoint for the national cloud deployment.
The Microsoft Graph service root endpoint for the national cloud deployment. See
Microsoft Graph and Graph Explorer service root endpoints for a list of endpoints.
Permission scopes
Any permission scope value (including the .default scope) that contains the Microsoft
Graph domain MUST use the domain of the Microsoft Graph service root endpoint for
the national cloud deployment. The shortened permission scope names, such as
User.Read or Mail.Send , are also valid.
Examples
The following example configures an Interactive authentication provider with the
Microsoft Graph SDK to connect to the Microsoft Graph for US Government L4 national
cloud.
C#
C#
using Azure.Identity;
using Microsoft.Graph;
using Microsoft.Graph.Authentication;
The Microsoft Graph SDK service libraries provide a client class that you can use as the
starting point for creating all API requests. There are two styles of client class: one uses a
fluent interface to create the request (for example, client.Users["user-id"].Manager )
and the other accepts a path string (for example, api("/users/user-id/manager") ). When
you have a request object, you can specify a variety of options such as filtering and
sorting, and finally, you select the type of operation you want to perform.
There is also the Microsoft Graph PowerShell SDK, which has no client class at all.
Instead, all requests are represented as PowerShell commands. For example, to get a
user's manager, the command is Get-MgUserManager . For more information on finding
commands for API calls, see Navigating the Microsoft Graph PowerShell SDK.
C#
C#
// GET https://graph.microsoft.com/v1.0/me
C#
// GET https://graph.microsoft.com/v1.0/me?$select=displayName,jobTitle
7 Note
Some requests for Azure Active Directory resources require the use of advanced
query capabilities. If you get a response indicating a bad request, unsupported
query, or a response that includes unexpected results, including the $count query
parameter and ConsistencyLevel header may allow the request to succeed. For
details and examples, see Advanced query capabilities on Azure AD directory
objects.
C#
C#
// GET https://graph.microsoft.com/v1.0/me/messages?
$select=subject,sender&$filter=<some condition>&orderBy=receivedDateTime
The object returned when retrieving a list of entities is likely to be a paged collection.
For details about how to get the complete list of entities, see paging through a
collection.
C#
C#
// GET https://graph.microsoft.com/v1.0/me/messages/{message-id}
C#
C#
// GET https://graph.microsoft.com/v1.0/me/messages/{message-id}?
$expand=attachments
C#
C#
// DELETE https://graph.microsoft.com/v1.0/me/messages/{message-id}
C#
C#
// POST https://graph.microsoft.com/v1.0/me/calendars
C#
C#
// PATCH https://graph.microsoft.com/v1.0/teams/{team-id}
await graphClient.Teams[teamId]
.PatchAsync(team);
C#
C#
// GET https://graph.microsoft.com/v1.0/users/{user-id}/events
C#
C#
//GET https://graph.microsoft.com/v1.0/me/calendarView
For performance reasons, collections of entities are often split into pages and each page
is returned with a URL to the next page. The PageIterator class simplifies consuming of
paged collections. PageIterator handles enumerating the current page and requesting
subsequent pages automatically.
Request headers
If you send any additional request headers in your initial request, those headers are not
included by default in subsequent page requests. If those headers need to be sent on
subsequent requests, you must set them explicitly.
Tip
This example sets a small page size using the top parameter for demonstration
purposes. You can set the page size up to 999 to minimize the number of requests
that are necessary.
C#
C#
await pageIterator.IterateAsync();
C#
C#
int count = 0;
int pauseAfter = 25;
await pageIterator.IterateAsync();
Batching is a way of combining multiple requests into a single HTTP request. The
requests are combined in a single JSON payload, which is sent via POST to the \$batch
endpoint. Microsoft Graph SDKs have a set of classes to simplify how you create batch
payloads and parse batch response payloads.
) Important
For current limitations with JSON batching in Microsoft Graph, see Known Issues.
C#
C#
// Use the request builder to generate a regular
// request to /me
var userRequest = graphClient.Me.ToGetRequestInformation();
7 Note
If the add event request fails, the get calendar view request will fail with a 424
Failed Dependency error.
C#
C#
C#
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Graph;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
};
events.Add(@event);
}
// if the requests are more than 20 limit, we need to create
multiple batches of the BatchRequestContent
List<BatchRequestContent> batches = new List<BatchRequestContent>();
var batchRequestContent = new BatchRequestContent(graphClient);
foreach (OnlineMeeting e in events)
{
//create online meeting for particular user or we can use /me as
well
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post,
$"https://graph.microsoft.com/v1.0/users/{userID}/onlineMeetings/createOrGet
")
{
Content = new StringContent(JsonConvert.SerializeObject(e),
Encoding.UTF8, "application/json")
};
BatchRequestStep requestStep = new
BatchRequestStep(events.IndexOf(e).ToString(), httpRequestMessage, null);
batchRequestContent.AddBatchRequestStep(requestStep);
if (events.IndexOf(e) > 0 && ((events.IndexOf(e) + 1) %
maxNoBatchItems == 0))
{
batches.Add(batchRequestContent);
batchRequestContent = new BatchRequestContent(graphClient);
}
}
if (batchRequestContent.BatchRequestSteps.Count < maxNoBatchItems)
{
batches.Add(batchRequestContent);
}
C#
try
{
// Upload the file
var uploadResult = await fileUploadTask.UploadAsync(progress);
Console.WriteLine(uploadResult.UploadSucceeded ?
$"Upload complete, item ID: {uploadResult.ItemResponse.Id}" :
"Upload failed");
}
catch (ServiceException ex)
{
Console.WriteLine($"Error uploading: {ex.ToString()}");
}
C#
C#
fileUploadTask.ResumeAsync(progress);
C#
// Create message
var draftMessage = new Message
{
Subject = "Large attachment"
};
try
{
// Upload the file
var uploadResult = await fileUploadTask.UploadAsync(progress);
Many of the Microsoft Graph SDKs use the v1.0 Microsoft Graph endpoint by default.
The SDKs can be used with the beta endpoint for non-production applications. The
method for accessing the beta endpoint depends on which SDK you are using.
) Important
APIs under the /beta version in Microsoft Graph are subject to change. Use of
these APIs in production applications is not supported. To determine whether an
API is available in v1.0, use the Version selector.
C#
In order to call the beta API, you must install the Microsoft.Graph.Beta package.
Usage is the same as the Microsoft.Graph package.
C#
// Version 5.x
using Microsoft.Graph.Beta;
// Version 4.x and earlier
// using Microsoft.Graph;
See also
SDKs in preview or GA status.
Microsoft Graph connectors SDK
overview
Article • 03/16/2023
The Microsoft Graph connectors SDK simplifies the process of building high-quality,
efficient, and resilient connectors in scenarios where you can't find a pre-built connector
for the data source you want to index into Microsoft Graph.
The SDK includes the framework and contract components to help you write the code
and the tools to test your code.
The connectors SDK enables you to create custom Microsoft Graph connectors directly
within the Visual Studio integrated development environment (IDE). It provides
everything you need to build, debug, and deploy your custom connector.
Components
The connectors SDK includes the following components:
Custom connector template: If you want to develop your custom connector in C#,
you can download the template from Visual Studio Marketplace and get started
quickly. You can also choose to develop your custom connector in any of the
languages in this list .
Contracts: These are gRPC protocol buffer files that contain the contracts for
interaction between the Microsoft platform (Microsoft Graph connector agent) and
your custom connector code.
Download the latest version of the connector agent and run the installation
configuration assistant. For more details, see Microsoft Graph connector agent.
Connectors SDK test utility: Includes pre-built test scenarios that you can use to
test your custom connector code and communicate with the connector agent
platform.
Get data from connector: The agent can connect to your custom connector to get
data from the source using the logic implemented by your connector.
Microsoft 365 admin center integration: The agent enables you to configure,
manage, and monitor your custom connectors through the Microsoft 365 admin
center .
Crawl scheduling and management: The agent is capable of crawling the data
source through full crawls and incremental crawls. Full crawls (list-based or
Microsoft Graph-based) go through your entire data periodically at an interval
defined by you. Incremental crawls are more frequent and they crawl the data
source from the previous timestamp/checkpoint at an interval defined by you.
Delete, difference, and cycle detection: The agent is capable of detecting items
deleted from your data source based on the items sent by your connector during
periodic full crawls. The agent then takes care of deleting the item from the
Microsoft index as well.
The agent also detects items that have changed since the last crawl by computing
a hash of the item and comparing it with the hash of the item seen previously. To
make crawls faster, the agent sends the data to be indexed only when the item has
changed.
The agent also detects duplicate items that arise from data sources that have
linked items (like websites) and skips crawling these items.
Identity mapping: The connector agent enables the stamping of Access Control
Lists (ACLs) on your data to enable security trimming. You can enable security
trimming based on Azure Active Directory (Azure AD) or ACLs from your data
source.
Microsoft Graph ingestion: The agent ingests the data into Microsoft Graph after
receiving it from your custom connector.
7 Note
You can get started in C# with our sample connector or in other supported languages
using the contracts from the Microsoft Graph connectors SDK page in GitHub .
Next steps
Learn more about the contracts.
Develop your first custom connector in C#.
Develop your custom connector in other languages.
Microsoft Graph connectors SDK
services
Article • 03/16/2023
This article describes the services that are part of the contract protocol buffer files.
Implement these services as part of the connector.
Services Description
ConnectorInfo Includes APIs to get information about the connector. If you're using
the Visual Studio extension, you can use the default implementation
for this service without changes.
ConnectionManagement Contains APIs that are called during the process of custom connector
connection creation in the Microsoft 365 admin center.
ConnectorOAuth Service for OAuth flows such as refreshing access tokens during
crawls.
You can download the contract protocol buffer files from the Microsoft Graph
connectors SDK contracts page on GitHub.
Microsoft Graph connectors SDK
ConnectorInfo API and models
Article • 03/16/2023
The Microsoft Graph connectors SDK contracts ConnectorInfo API allows you to get
information about the connector.
ConnectorInfo API
Method Parameters Return Type Description
GetBasicConnectorInfoResponse
Response model that holds basic connector information.
GetBasicConnectorInfoRequest
Request model to retrieve basic connector information. This model doesn't have any
properties; properties might be added in the future as required.
HealthCheckRequest
Request model for the HealthCheck API. This model doesn't have any properties; properties
might be added in the future as required.
HealthCheckResponse
Response model for the HealthCheck API. This model doesn't have any properties;
properties might be added in the future as required.
Microsoft Graph connectors SDK connection
management API and models
Article • 03/16/2023
The Microsoft Graph connectors SDK contracts connection management API and models are called during
the process of custom connector connection creation on the Microsoft 365 admin center .
authenticationData AuthenticationData Holds the data source access URL and the credentials to access it.
ValidateAuthenticationResponse
ValidateCustomConfigurationRequest
authenticationData AuthenticationData Holds the data source access URL and the credentials to access it.
ValidateCustomConfigurationResponse
status OperationStatus Shows the status of the operation and details such as error messages.
GetDataSourceSchemaRequest
authenticationData AuthenticationData Holds the data source access URL and the credentials to access it.
GetDataSourceSchemaResponse
Request model to get the schema response of the data source.
status OperationStatus Shows the status of the operation and details such as error messages.
See also
Microsoft Graph connectors API schema resource type
Microsoft Graph connectors SDK contracts
connector crawler API and models
Article • 03/16/2023
The Microsoft Graph connectors SDK contracts connector crawler API and models are called
during a crawl.
GetCrawlStreamRequest
Request model for getting items during crawl.
authenticationData AuthenticationData Holds the data source access URL and the credentials
to access it.
crawlProgressMarker CrawlCheckpoint Holds data to identify items that were processed in the
last crawl. The connector returns the item's
information, and it uses it if the platform crashes
during the crawl.
Schema DataSourceSchema Shows the schema of the connection. This property can
also be used to set the value.
CrawlStreamBit
Response model that contains the item status indicating success or failure and the
indicator/checkpoint for the item being crawled during full or periodic crawl.
status OperationStatus Shows the status of the operation and error details.
crawlItem CrawlItem Shows a single item crawled from the data source.
crawlProgressMarker CrawlCheckpoint Identifies the item crawled from the data source.
GetIncrementalCrawlStreamRequest
authenticationData AuthenticationData Holds the data source access URL and the
credentials to access it.
previousCrawlStartTimeInUtc Timestamp Shows the previous crawl start time in UTC. This
value can be used in the first incremental crawl,
but subsequent calls should use the checkpoint
value.
IncrementalCrawlStreamBit
Response model containing the item, status indicating success/failures if any and the
indicator/checkpoint for the item being crawled during incremental crawl.
status OperationStatus Shows the status of the operation and error details.
crawlItem IncrementalCrawlItem Shows a single item crawled from the data source
during and incremental crawl.
crawlProgressMarker CrawlCheckpoint Identifies the last item crawled from the data source
during the last incremental crawl.
ItemType enumeration members for CrawlItem
Enumeration fields for crawl items.
ContentItem 0 Data items with content to ingest. For example: website content.
LinkItem 1 Link to a content item that will be used in subsequent crawls. For example:
Links to a website or a folder.
CrawlItem
Represents an entity in the data source. The maximum size allowed is 4 MB. For example: a
file, a folder or a record in a table.
itemId string Shows the unique ID that represents the item in the data source.
contentItem ContentItem Shows a data item with content to ingest. For example: the content of a
website.
linkItem LinkItem Link to a content item that will be used in subsequent crawls. For
example: a link to a website or a folder.
itemType ItemType Shows the type of item being sent. This model should have a
contentItem or a linkItem set and this enumeration field should
correspond to that item.
7 Note
ContentItem 0 Data items with content to ingest. For example: the content of a website.
LinkItem 1 Link to a content item that will be used in subsequent crawls. For example: a
link to a website or a folder.
DeletedItem 2 Item that was deleted from the data source and should be deleted from the
index.
IncrementalCrawlItem
Represents an entity in the data source. For example: a file, a folder or a record in a table.
itemId string Shows the unique ID that represents the item in the data source.
contentItem ContentItem Shows a data item with content to ingest. For example: the content of a
website.
linkItem LinkItem Link to a content item that will be used in subsequent crawls. For
example: a link to a website or a folder.
deletedItem DeletedItem Item that is deleted from the datasource and should be removed from
the index. If deletedItem is set, contentItem or linkItem can't be set.
itemType ItemType Shows the type of item being sent. This model should have a
contentItem or a linkItem set and this enumeration field should
correspond to that item.
7 Note
ContentItem
Item that holds the content of the data source entity to be ingested. For example: the
content of a website.
propertyValues SourcePropertyValueMap Holds the key and values of each property in the item.
content Content Shows the content property of the item that can be used
when displaying search results.
LinkItem
Item that acts as a link to another item. These link items will be sent again to connector for
recrawl; for example, in a folder content, files will be content items and sub folders will be
link items.
metadata map<string, Holds the metadata needed by the connector to recrawl the
GenericType> item.
DeletedItem
Represents an item that was deleted from the data source and has to be removed from the
index.
AccessControlList
Restricts the users that can see the search results.
Entries repeated AccessControlEntry Shows the array or collection of access control list entries.
Deny 2 The entry is for users/groups with no access the item and overrides grant for any
user/group.
AccessControlEntry
accessType AclAccessType Shows the access type of the entity either grant or deny.
IS_None 0 Indicates the default value: Azure Active Directory (Azure AD).
ActiveDirectorySId 1 SID (On premise security identifier) provided by Active Directory (AD).
Principal
value string Principal value: the value of the SID, UPN, Azure ADId,
and so on.
Property Type Description
SourcePropertyValueMap
Map of the source property key and its value in the data source. It stores the property value
of each item.
values map<string, Holds the key and values of the properties of the item. The key is the
GenericType> property name and the value is property value. For example, file content
has properties like title, modifiedDate, and so on. The properties keys will
be the properties themselves and their values will be the title of the file
and file modified date respectively.
CrawlCheckpoint
Identifies the item that was crawled last. It will be saved by the platform and the checkpoint
from last successful item batch will be used for resuming crawl if there is a failure or crash.
The platform will send the checkpoint in the GetCrawlStream API.
batchSize uint32 Holds the number of items returned in every batch. It has a constant
value of 1 because each item is streamed individually.
customMarkerData string Custom data needed to identify the last item crawled from the data
source.
GenericType
Model to hold the supported types of values by the platform in certain fields like source
property values. Only one of the following fields must be set.
IntCollectionType
DoubleCollectionType
TimestampCollectionType
The Microsoft Graph connectors SDK contracts connector OAuth API is used for OAuth
flows such as refreshing access tokens during crawls.
RefreshAccessTokenRequest
Request model for refreshing the OAuth token.
authenticationData AuthenticationData Holds the data source access URL, the credentials to
access the data source, and current token information.
RefreshAccessTokenResponse
Response model for the refresh OAuth token request.
This article describes the common models used in the Microsoft Graph connectors SDK.
CustomConfiguration
Search Admin provides the connector-specific custom configuration information during
the connection creation. The platform doesn't manage the structure and format of the
configuration. Connector developers can use a format of their choice.
configuration string Holds the configuration information as a string. The connector should
have the capability to interpret the content of the string.
AuthenticationData
Contains credentials provided by the admin to access the data source, including the
authentication type, data source URL, and the credentials data.
BasicCredential
Represents the basic credentials model.
secret string Secret to use with the username for accessing data source.
WindowsCredential
Represents the Windows credentials model.
secret string Secret to use with the username for accessing data source.
domain string Active Directory domain of the account. If not provided by the admin
explicitly, this property holds the value of the computer name.
oAuth2ClientCredential
Represents the credential model for OAuth2 client credentials.
oAuth2ClientCredentialResponse
Represents the response model from the authentication server for the OAuth2 token
request. The fields present in this model are the common response fields specified in
OAuth2 documentation. Additionally, idToken can be set when the auth servers support
OpenIDConnect.
tokenType string Type of the token – usually Bearer token for OAuth.
scope string Scopes supported by the token if auth server sends it.
OperationResult
The OperationResult enumeration contains the possible values for operation results.
TokenExpired 7 To be used in OAuth flow when the token sent to the connector by
the platform has expired. During the crawl, on receiving this status,
the platform will trigger the refresh token flow and call the
RefreshAccessToken method in ConnectorOAuthService.
OperationStatus
Represents the status of an operation, including error/warnings and retry details. This
model is part of the response of all APIs in ConnectionManagementService and
ConnectorCrawlerService.
statusMessage string Custom message that can be used for logging and
monitoring purposes.
Property Type Description
RetryDetails
This model is used for communicating the retry policy where retry is required.
DataSourceSchema
Represents the schema of the properties that represent a data entity in the data source.
For details, see schema resource type.
None 0 None
IsSearchable 1 If a property is searchable, its value is added to the full-text index. When a
user performs a search, results are returned if there's a search hit in one of
the searchable fields or its content. For example, if the property is
"Author," searching "Smith" returns items whose Author property contains
"Smith."
IsRetrievable 4 If a property is retrievable, it can return its value in search results. Any
property you want to add to the display template or return from the query
and be relevant in search results must be retrievable. Marking large or too
many properties as retrievable will increase search latency. Be selective
and choose relevant properties.
IsContent 8 Content property is to identify a property that can be full text indexed.
Admins will choose among the available properties, which one should be
the property to be treated as content for that specific connection. For
details, see Content property.
SearchPropertyLabel
Search property labels are well-known tags published by Microsoft that you can add
against a property in your schema. Adding a semantic label helps various Microsoft
products understand the property and provide a better experience. For details, see
Semantic labels.
Title 0 The title of the item that you want to show in search and other
experiences.
CreatedBy 2 Name of the person who created the item in the data source.
LastModifiedBy 3 Name of the person who most recently edited the item in the
data source.
CreatedDateTime 5 Date and time that the item was created in the data source.
LastModifiedDateTime 6 Date and time the item was last modified in the data source.
LastModifiedByUpn 9 UPN of the person who most recently edited the item in the
data source.
CreatedByUpn 10 UPN of the person who created the item in the data source.
SourcePropertyDefinition
Defines a single source property for an item in data source. For details about schema
property definitions, see property resource type.
The GraphConnectorAgentTest executable file is a test utility for the custom connector.
It doesn't create connections or add data into the Microsoft index. The test utility runs
on the computer where you installed the agent and doesn't connect to external
resources except for the data source that is part of the test. You can find the test
application in the TestApp folder in your Microsoft Graph connector agent installation
folder.
ConnectionInfo.json: This file contains all the information about the connection -
the connector ID that identifies the custom connector for which this connection is
being created, the data source URL, credentials to access the data source, the
schema associated with the connection, and extra parameters for the connection.
This configuration file is in the Config folder of the test application.
7 Note
You can add multiple connector IDs and their corresponding port information
to this file using the <Connector Id>:<Port> format. Each unique connector
should be running on a different port.
Manifest.json: The manifest file is required in order to identify a connector and its
configuration while publishing a connection through the Microsoft 365 Admin
Center. Update this manifest file to use it for validation in this test application. This
file is in the Config folder of the test application.
{
// This is the unique connector ID/provider ID.
"connectorId": "<ConnectorGuid>",
// This is a list of all supported auth types. Remove the ones that
the connector does not support.
"authTypes": [ "Windows", "Basic", "Anonymous",
"OAuth2ClientCredentials" ],
Test scenarios
The test utility has five options:
Test connectivity to the connector service: Verifies that the test utility can connect
to the connector specified in ConnectionInfo.json over the port specified for that
connector ID in CustomConnectorPortMap.json.
Test data source crawl with simulated connection: Tests the methods in
ConnectorCrawlerService. It invokes the crawl with the schedule specified in
ConnectionInfo.json and prints the status of the ongoing or last completed crawl
every minute. When the first crawl finishes successfully, it displays the message
that the crawl has completed, and the platform keeps running to trigger additional
crawls at the interval specified in ConnectionInfo.json. If you specify an incremental
crawl frequency in the ConnectionInfo.json file, it triggers the incremental crawl
after the first full crawl.
Test end-to-end connection publish flow: Validates the entire flow from creating
the custom connection to crawling the datasource. You will be prompted to give
inputs in the same sequence as the Microsoft 365 Admin Center connection
publish flow. Validation happens at every step based on your inputs.
To stop the utility from crawling the data source, close and restart the
GraphConnectorAgentTest executable file. You can then choose a different test option,
or retest an option after you update the connector code or the configuration files.
When you test the connection creation flow or the data source crawl, specify the
credentials to access the data source in the ConnectionInfo.json configuration file. The
platform reads the credentials and passes them to the connector to access the data
source. As long as no one else has access to the ConnectionInfo.json configuration file,
the credentials are secure.
See also
Best practices
Troubleshooting
Publish custom connectors to the
Microsoft 365 admin center
Article • 03/16/2023
When you use the Microsoft Graph connectors SDK, you can publish your custom
connectors through the Microsoft 365 admin center, the same way that Microsoft built-
in connectors are published.
7 Note
Read the Setup for your Graph connector article to understand the general Graph
connectors setup instructions.
Use the following steps to publish a connection for your custom connector:
7 Note
You can add multiple connector IDs and their corresponding port
information to this file using the <Connector Id>:<Port> format. Each
unique connector should be running on a different port.
If you have upgraded from a GCA version lower than 1.8.0.0, please
follow the troubleshooting steps to fix connection failures.
2. Add a Microsoft Graph connector in the Microsoft 365 admin center from the Data
Sources tab in the Search & Intelligence section. For details, see Add a Microsoft
Graph connector in the Microsoft 365 admin center.
3. Choose Custom Connector and provide the manifest validated by the test
application.
4. Name the connection. For details, see Step 2: Name the connection.
5. Provide the URL to the data source you're connecting to and credentials to access
it. Choose the Microsoft Graph connector agent, and validate the information
provided. Choose Next.
6. Provide any extra configuration if required by your connector. You can pass any
information specific to the connection to the datasource.
For example, if you're building a connector for Azure DevOps Services, the projects
that need to be indexed can be the extra parameters. For a Wiki connector, the
subsections that need to be indexed can be the extra parameters. The API to query
the wiki can take the filters specified in the extra parameters and get the items
from data source.
The data in the parameter is opaque to the platform. It's serialized and stored as a
string and passed to the connector. The connector can deserialize this data as
required and use it.
7. On the Assign property labels page, assign semantic labels to your source
properties. The default result type will not work if semantic labels are not assigned.
9. You can manage search permissions basis Access control lists (ACLs) that
determine which users in your organization can access each item. Only Azure AD-
based Access Control Lists are supported for people with access to the data
source. For details, see Step 5: Manage search permissions.
10. Choose the refresh frequencies of crawls. The refresh interval determines how
often your data is synced between the data source and Microsoft Search. For
details, see Step 8: Refresh frequencies.
11. Review the details provided and choose Finish. For details, see Step 9: Review
connection.
12. Customize the search results page by setting up verticals and result types. For
details, see Step 10: Customize the search results page.
13. Review the published connection under the Data sources tab to confirm that the
connection setup worked. For details, see Step 11: Confirm that the connection
setup worked.
See also
Best practices
Troubleshooting
Build a Microsoft Graph connector using
other languages
Article • 08/26/2022
You can develop your custom Microsoft Graph connector in languages other than C#. To
do so, use the following steps:
1. Install the Microsoft Graph connector agent and register it. For details, see
Microsoft Graph connector agent.
2. Download the protocol buffer files with gRPC contracts from the Contracts
folder.
3. Download the protobuf compiler from the protobuf repo and extract it.
Update the environment path with the bin folder in the extracted root.
Compile contracts to create server-side stubs in the language of your choice.
For details, see supported languages .
4. Create a project in your integrated development environment (IDE) and place all
the protocol files in a folder named Contracts.
6. Create a server, run the application, and generate the executable/output binaries.
8. Publish a connection for your custom connector on the Microsoft 365 admin
center .
See also
Best practices
Troubleshooting
Microsoft Graph connectors SDK best
practices
Article • 03/16/2023
This article provides best practices to follow when you use the Microsoft Graph
connectors SDK to implement a custom connector.
Periodic full crawls get all items in the data source and ingest only the items that are
modified or not present in the index. If it doesn't find an item, it deletes it from the
index.
Incremental crawls get items added or modified since the last incremental crawl. The
connector can also send items to be deleted as a part of this crawl. For the first
incremental crawl, the last full crawl's start time is also sent. The connector can
optionally use this crawl to fetch items changed only after the last full crawl.
Both periodic full and incremental crawls have their crawl progress markers.
If the previous crawl did not crash, you have to crawl the data source from the
beginning.
C#
// Long value
int64 intValue = 2;
// Double value
double doubleValue = 3;
// DateTime value
google.protobuf.Timestamp dateTimeValue = 4;
// Boolean value
bool boolValue = 5;
// Collection of string
message StringCollectionType {
// Value of string collection
repeated string values = 1;
}
// Collection of long
message IntCollectionType {
// Value of long collection
repeated int64 values = 1;
}
// Collection of double
message DoubleCollectionType {
// Value of double collection
repeated double values = 1;
}
// Collection of DateTime
message TimestampCollectionType {
// Value of DateTime collection
repeated google.protobuf.Timestamp values = 1;
}
GenericType can have one of the following types: string, int64, double, DateTime, and
Boolean or a collection of string, int64, double, and DateTime. The following are
examples of how to set these types:
C#
dateTimeCollection.Values.Add(Google.Protobuf.WellKnownTypes.Timestamp.FromD
ateTime(DateTime.UtcNow));
dateTimeCollection.Values.Add(Google.Protobuf.WellKnownTypes.Timestamp.FromD
ateTime(DateTime.UtcNow.AddDays(-1)));
GenericType dateTimeCollectionType = new GenericType
{
DateTimeCollectionValue = dateTimeCollection
};
Building search schema
The connectors schema has the following restrictions:
Property name: The name of the property can have a maximum of 32 characters
and only alphanumeric characters are allowed.
Search annotations:
Only properties of type String or StringCollection can be searchable.
Only properties of type String can be a content property.
Content properties must be searchable.
Content properties can't be queryable or retrievable.
Refinable property shouldn't be searchable.
Refinable property should be queryable and retrievable.
Boolean properties can't be refinable.
Aliases: A set of aliases or a friendly name for the property can have a maximum
32 characters and only alphanumeric characters allowed.
To get a good throughput, the connector should retrieve a batch of items from the data
source, convert each item to the CrawlStreamBit, and send them over the response
stream. The batch size depends on the data source. We recommend 25 as an optimal
size to maintain continuous flow of items over the stream.
Connection management flows send a response with the StatusMessage that appears in
the Microsoft 365 admin center. Sending meaningful messages makes it easier to debug
the errors on the user interface, and avoid leaving unhandled exceptions.
Timeouts
All methods in ConnectionManagementService should complete and return within 30
seconds; otherwise, the platform will return a time-out error message for the request.
The OperationStatus structure has three fields that can be used to represent any errors.
OperationResult
OperationResult is an enumeration that can hold the failure reason.
StatusMessage
StatusMessage is a property of OperationStatus that can store the custom message to
show the failure reason that will appear to the admin during the connection setup. For
example, if the credentials are incorrect during the validation with the
ValidateAuthentication method, the result property can be set to AuthenticationIssue
and the statusMessage property can be set to Incorrect credentials provided. When the
ValidateAuthentication method is called, this statusMessage will be shown to the
search admin. During crawls, this scenario will move the connection to failed state,
display the authentication error to the admin, and prompt the admin to update the
credentials to access the data source.
RetryDetails
RetryDetails allows the connector to resend information to the platform about transient
errors during the crawls and use it to repeat the operation.
The retry can be a standard or exponential back-off. The connector can set the pause
time, back-off rate, and back-off coefficient and send them back. For example, if the
data source is throttled during the crawl, the connector can set the OperationResult to
DatasourceError and send the retry details according to the retry-header in the
response headers from the data source.
Error mapping for OperationResult
The following errors move the connection to failed state:
OperationResult.AuthenticationIssue
OperationResult.ValidationFailure
The other operation codes will be treated as transient failures and will be retried in
subsequent crawls.
See also
Troubleshooting issues with your connector
Troubleshoot issues with the Microsoft
Graph connectors SDK
Article • 03/16/2023
This article describes some of the most common issues with the Microsoft Graph
connectors SDK, and how to troubleshoot them.
If the connector sends transient failure responses, and more than 10% of the items
resulted in crawl failures, items that aren't included in the last two crawls will be deleted.
1. Open the GCA Control panel. In Programs and features, select Graph connector
agent from the list of programs, and choose Repair.
2. Update the new port map file configuration with the previous configurations.
3. Resume any failed connections from Microsoft 365 admin center.
Connector service is unavailable
If the crawls are failing with a connector unavailable on specified port error, verify the
following:
1. The connector is indeed running on the specified port and hasn't crashed and isn't
stuck.
2. The port specified in the port map configuration file is correct.
3. If the port map configuration file has been edited, be sure to restart
GcaHostService.
If the error code is Unknown, there's likely an unhandled exception in your connector
code. Make sure that you send a response with success/failure operation status in all
cases.
The following are the locations of the log path, depending on your use case:
Path
C:\Users\{User Account}\AppData\Local\Microsoft\{Connector
Name}\Logs\ConnectorLog.log
Path
C:\Windows\system32\config\systemprofile\AppData\Local\Microsoft\
{Connector Name}\Logs\ConnectorLog.log
Connector hosted as a Windows service under the virtual account:
Path
C:\Windows\ServiceProfiles\{Network Service
Name}\AppData\Local\Microsoft\{Connector Name}\Logs\ConnectorLog.log
Path
C:\Windows\ServiceProfiles\LocalService\AppData\Local\Microsoft\
{Connector Name}\Logs\ConnectorLog.log
7 Note
1. Right-click the folder that contains the executable and choose Properties.
2. Open the Security tab and under Group or user names, choose Edit.
3. Choose Add.
4. Enter 'LOCAL SERVICE' as the object name and choose Check Names.
5. Choose OK on each dialog box.
More help
If you need more help troubleshooting an issue, you can raise an issue or start a
discussion on relevant topics through our GitHub repository.
You can also reach out to the Microsoft Graph Connectors team for more help and
troubleshooting.
See also
Best practices
Microsoft Graph PowerShell overview
Article • 12/14/2022
The Microsoft Graph PowerShell SDK acts as an API wrapper for the Microsoft Graph
APIs, exposing the entire API set for use in PowerShell. It contains a set of cmdlets that
helps you manage identities at scale from automating tasks to managing users in bulk
using Azure Active Directory (Azure AD). It will help administer every Azure AD feature
that has an API in Microsoft Graph.
The commands in Microsoft Graph PowerShell are autogenerated from the Microsoft
Graph API schema making it easier to get faster updates and functionality. The cmdlet
reference content is also autogenerated from the API reference.
Microsoft Graph PowerShell is the replacement for the Azure AD PowerShell and
MSOnline modules and is recommended for interacting with Azure AD.
Get started
To perform basic tasks, use the Get-started guide.
Next steps
If you don't have an Azure account, create a free account .
If you already have access to an Azure AD tenant, Install the SDK.
Install the Microsoft Graph PowerShell
SDK
Article • 04/25/2023
The Microsoft Graph PowerShell SDK is published on the PowerShell Gallery . In this
article you will learn how to install the Microsoft Graph PowerShell SDK using
PowerShellGet.
Prerequisites
PowerShell 7 and later is the recommended PowerShell version for use with the
Microsoft Graph PowerShell SDK on all platforms. There are no additional prerequisites
to use the SDK with PowerShell 7 or later.
The following prerequisites are required to use the Microsoft Graph PowerShell SDK
with Windows PowerShell.
The PowerShell script execution policy must be set to remote signed or less
restrictive . Use Get-ExecutionPolicy to determine the current execution policy.
PowerShell
Installation
Using the Install-Module cmdlet is the preferred installation method for the Microsoft
Graph PowerShell module.
7 Note
Installing the main module of the SDK, Microsoft.Graph, will install all 38 sub
modules. Consider only installing the necessary modules, including
Microsoft.Graph.Authentication which is installed by default when you opt to
install the sub modules individually. For a list of available Microsoft Graph modules,
use Find-Module Microsoft.Graph* . Only cmdlets for the installed modules will be
available for use.
Run the following command to install the SDK in PowerShell Core or Windows
PowerShell.
PowerShell
Optionally, you can change the scope of the installation using the -Scope parameter.
This requires admin permissions.
PowerShell
Installing the SDK in one version of PowerShell does not install it for the other. Run the
installation command inside the version of PowerShell you intend to use it in.
Verify installation
After the installation is completed, you can verify the installed version with the following
command.
PowerShell
Get-InstalledModule Microsoft.Graph
PowerShell
Get-InstalledModule
The version in the output should match the latest version published on the PowerShell
Gallery. Now you're ready to use the SDK.
Updating the SDK
You can update the SDK and all of its dependencies using the following command.
PowerShell
Update-Module Microsoft.Graph
PowerShell
Uninstall-Module Microsoft.Graph
Then, remove all of the dependency modules by running the following commands.
PowerShell
Next steps
Learn how to perform basic tasks with Microsoft Graph PowerShell in the Get started.
Get started with the Microsoft Graph
PowerShell SDK
Article • 04/25/2023
In this guide, you'll use the Microsoft Graph PowerShell SDK to perform some basic
tasks. If you haven't already, install the SDK before following this guide.
API version
By default, the SDK uses the Microsoft Graph REST API v1.0. Cmdlets are available for
the API version that is selected. You can change the profile by using the Select-
MgProfile command.
PowerShell
Authentication
The PowerShell SDK supports two types of authentication: delegated access, and app-
only access. In this guide, you'll use delegated access to sign in as a user, grant consent
to the SDK to act on your behalf, and call the Microsoft Graph.
For details on using app-only access for unattended scenarios, see Use app-only
authentication with the Microsoft Graph PowerShell SDK.
The User.Read.All permission scope will enable the first two calls, and the
Group.ReadWrite.All scope will enable the rest. These permissions require an admin
account.
PowerShell
Output
Sign in
Use the Connect-MgGraph command to sign in with the required scopes. You'll need to
sign in with an admin account to consent to the required scopes.
PowerShell
The command prompts you to go to a web page to sign in using a device code. Once
you've done that, the command indicates success with a Welcome To Microsoft Graph!
message. You only need to sign in once per session.
Tip
7 Note
Some requests for Azure Active Directory resources require the use of advanced
query capabilities. If you get a response indicating a bad request, unsupported
query, or a response that includes unexpected results, including the $count query
parameter and ConsistencyLevel header may allow the request to succeed. For
details and examples, see Advanced query capabilities on Azure AD directory
objects.
PowerShell
Get-MgUser
PowerShell
Id DisplayName Mail
UserPrincipalName
-- ----------- ----
-----------------
88d1ba68-8ff5-4de2-90ed-768c00abcfae Conf Room Adams
[email protected] Adams@contoso.…
3103c7b9-cfe6-4cd3-a696-f88909b9a609 Adele Vance
[email protected] AdeleV@contoso…
da3a885e-2d97-41de-9347-5271ef321b58 MOD Administrator
[email protected] admin@contoso.…
e0c6ee40-e105-476d-9597-acd061d21fcb Alex Wilber
[email protected] AlexW@contoso.…
17c6bdee-8ed3-49af-a65e-71b64cca8382 Allan Deyoung
[email protected] AllanD@contoso…
e5b78950-27cd-4f01-b083-eab4da97ca6a Conf Room Baker
[email protected] Baker@contoso.…
40467725-1a58-495d-9e2f-5970c6306d8d Bianca Pisani
BiancaP@contoso…
ce73bdb5-bf12-405e-ab85-40122fdd6eb7 Brian Johnson (TAILSPIN)
[email protected] BrianJ@contoso…
df1347a3-7ce7-4b4d-8aab-7c65b5c907b9 Cameron White
CameronW@contoso…
You can use an OData filter to help locate the specific user you want. Run the following
command, replacing Megan Bowen with the display name of the user you signed in with.
PowerShell
PowerShell
$user.DisplayName
PowerShell
Just like the Get-MgUser command, this command gives a list of teams. Select one of the
user's joined teams and copy its Id .
List team channels
Now use the team's Id as a parameter to the Get-MgTeamChannel command, following a
similar pattern of listing all channels, then filtering the list to get the specific channel you
want.
PowerShell
Send a message
Now that you have both the Team Id and the channel Id, you can post a message to the
channel. Use the following command to send the message.
PowerShell
This command differs from the previous commands you used. Instead of querying data,
it's creating something. In Microsoft Graph, this command translates to an HTTP POST ,
and it requires an object in the body of that post. In this case, the object is a
chatMessage. The -Body parameter to the command maps to the body property on
chatMessage . Other properties are mapped in a similar way, so you can change the
message you send. For example, to send an urgent message use the following
command.
PowerShell
Sign out
Use the Disconnect-MgGraph command to sign out.
PowerShell
Disconnect-MgGraph
Next steps
Learn how to navigate the SDK
Use app-only authentication with the Microsoft Graph PowerShell SDK
Navigating the Microsoft Graph
PowerShell SDK
Article • 04/25/2023
The Microsoft Graph API is huge, and it's growing all the time. Therefore, the number of
commands in the Microsoft Graph PowerShell SDK is also large. Finding the right
command for what you want to achieve can be challenging, especially if you're not
already familiar with Microsoft Graph. Let's look at some ways to help find a particular
command.
7 Note
Some requests for Azure Active Directory resources require the use of advanced
query capabilities. If you get a response indicating a bad request, unsupported
query, or a response that includes unexpected results, including the $count query
parameter and ConsistencyLevel header may allow the request to succeed. For
details and examples, see Advanced query capabilities on Azure AD directory
objects.
Command verbs
For basic REST operations, the verb is determined by the HTTP method used for the API.
For functions and actions, it's a little more complicated. APIs in Microsoft Graph that are
implemented as OData functions or actions are typically named with at least a verb. The
corresponding command's verb is based on the verb in the function or action name.
However, command verbs in PowerShell have to conform to specific naming rules, which
can result in non-intuitive name-to-command mappings.
Let's look at some examples. The getSchedule API uses get , and Get is an approved
PowerShell verb, so its command is Get-MgUserCalendarSchedule . The cancel API on an
event on the other hand, uses a non-approved verb cancel . The approved verb for
canceling or discontinuing something is Stop , so the command is Stop-MgUserEvent .
Finally, the snoozeReminder API's verb, snooze , has no PowerShell-approved equivalent.
For APIs like that, the SDK uses the verb Invoke , so that API's command is Invoke-
MgSnoozeUserEventReminder .
Command nouns
By now you may have noticed that all nouns in the SDK's commands start with Mg . This
prefix helps to avoid naming conflicts with other PowerShell modules. With that in mind,
it should make sense that a command like Get-MgUser is used to get a user. Following
PowerShell convention, even though the noun is singular, those same commands can
return multiple results if no specific instance is requested.
Look at the HTTP requests for this API. If you ignore the requests with /me in the URL,
there are two other ways to call this API.
HTTP
The paths match to the nouns. For the first form, you start with users , then messages , so
the command is Get-MgUserMessage . In the second form, you start with users , then
mailFolders , then messages, so the command is Get-MgUserMailFolderMessage .
Another way of looking at this command is asking what owns or contains what. The user
owns mail folders, and mail folders contain messages. Add the prefix and you get Get-
MgUserMailFolderMessage .
Listing parameters
After you've found the right command, you can examine all the available parameters by
using the Get-Help command. For example, the following command lists all the
available parameters for the Get-MgUser command.
PowerShell
PowerShell
Next steps
Discover Microsoft Graph PowerShell cmdlets Using Find-MgGraphCommand
cmdlet.
Use app-only authentication with the
Microsoft Graph PowerShell SDK
Article • 04/26/2023
The PowerShell SDK supports two types of authentication: delegated access, and app-
only access. This guide will focus on the configuration needed to enable app-only
access.
) Important
Let's configure app-only access for a simple script to list users and groups in your
Microsoft 365 tenant.
Prerequisites
Before you can use app-only access with the Microsoft Graph PowerShell SDK, make
sure you have the required prerequisites:
Microsoft Graph PowerShell SDK is installed. Follow the Install the Microsoft Graph
PowerShell SDK guide to install the SDK.
A certificate to use as a credential for the application. This certificate can be a self-
signed certificate or a certificate from an authority. Refer to the See also section for
guidance on how to create a self-signed certificate.
1. Have an X.509 certificate installed in your user's trusted store on the machine
where you'll run the script.
2. Export the certificate's public key in .cer, .pem, or .crt format.
3. Get the value of the certificate subject or its thumbprint.
Register an application in Azure AD, configure it with the permission scopes your
scenario requires, and share the public key for your certificate.
Portal
1. Open a browser and navigate to the Azure Active Directory admin center
and sign in using a Microsoft 365 tenant organization admin.
2. Select Azure Active Directory in the left-hand navigation, then select App
registrations under Manage.
3. Select New registration. On the Register an application page, set the values
as follows.
5. On the Graph PowerShell Script page, copy the values of the Application
(client) ID and Directory (tenant) ID and save them.
9. Select the Grant admin consent for... button, then select Yes to grant admin
consent for the configured application permissions. The Status column in the
Configured permissions table changes to Granted for ....
10. Select Certificates & secrets under Manage. Select Upload certificate under
Certificates. Browse to your certificate's public key file and select Add.
Authenticate
You should have three pieces of information after completing the configuration steps
above.
We'll use this information to test authentication. Open PowerShell and run the following
command, replacing the placeholders with your information.
PowerShell
If the command succeeds, you'll see Welcome To Microsoft Graph! . Run Get-MgContext
to verify that you've authenticated with app-only. The output should look like the
following.
PowerShell
ClientId : YOUR_APP_ID
TenantId : YOUR_TENANT_ID
CertificateThumbprint :
Scopes : {Group.Read.All, User.Read.All}
AuthType : AppOnly
CertificateName : YOUR_CERT_SUBJECT
Account :
AppName : Graph PowerShell Script
ContextScope : Process
Create the script
Create a new file named GraphAppOnly.ps1 and add the following code.
PowerShell
# Authenticate
Connect-MgGraph -ClientID YOUR_APP_ID -TenantId YOUR_TENANT_ID -
CertificateName YOUR_CERT_SUBJECT
Write-Host "USERS:"
Write-Host "======================================================"
# List first 50 users
Get-MgUser -Property "id,displayName" -PageSize 50 | Format-Table
DisplayName, Id
Write-Host "GROUPS:"
Write-Host "======================================================"
# List first 50 groups
Get-MgGroup -Property "id,displayName" -PageSize 50 | Format-Table
DisplayName, Id
# Disconnect
Disconnect-MgGraph
Replace the placeholders in the Connect-MgGraph command with your information. Save
the file, then open PowerShell in the directory where you created the file. Run the script
with the following command.
PowerShell
.\GraphAppOnly.ps1
The script outputs a list of users and groups similar to the output below (truncated for
brevity).
PowerShell
DisplayName Id
----------- --
Conf Room Adams 88d1ba68-8ff5-4de2-90ed-768c00abcfae
Adele Vance 3103c7b9-cfe6-4cd3-a696-f88909b9a609
MOD Administrator da3a885e-2d97-41de-9347-5271ef321b58
...
GROUPS:
======================================================
DisplayName Id
----------- --
App Development 06dce3e5-d310-4add-ab2c-be728fb9076e
All Employees 1a1cd42d-9801-4e9d-9b77-5215886174ef
Mark 8 Project Team 2bf1b0d0-81f6-4e80-b971-d1db69f8d651
...
See also
How to: Create a self-signed public certificate to authenticate your application.
Microsoft Graph Toolkit overview
Article • 07/01/2022
Microsoft Graph Toolkit makes it easy to use Microsoft Graph in your application. In the
following example, a signed-in user and their calendar events are displayed with just
two lines of code by using the Login and Agenda components.
html js css
1 <mgt-login></mgt-login>
2 <mgt-agenda></mgt-agenda>
3
Components
Microsoft Graph Toolkit includes a collection of web components for the most
commonly built experiences powered by Microsoft Graph APIs.
Component Description
Component Description
Login A button and a flyout control to authenticate a user with the Microsoft Identity
platform and display the user's profile information when they sign in.
Person Displays a person or contact by their photo, name, and/or email address.
People Provides the ability to search for people and renders the list of results.
picker
Person card A flyout used on the person component to display more profile information about
a user.
File Represents a file or folder with an icon, a file name, an author, and more.
Get Lets you make a GET query to any Microsoft Graph API directly in your HTML.
Channel Provides the ability to search for Microsoft Teams channels to select a channel
picker from a rendered list of results.
Tasks Displays and enables adding, removing, completing, or editing of tasks from
Microsoft Planner or Microsoft To Do.
Providers
Providers enable authentication, provide the implementation for acquiring access tokens
on various platforms, and expose a Microsoft Graph client for calling the Microsoft
Graph APIs. The components work best when used with a provider, but the providers
can be used on their own.
Providers Description
MSAL Uses msal.js to sign in users and acquire tokens to use with Microsoft Graph.
MSAL2 Uses msal-browser to sign in users and acquire tokens to use with Microsoft Graph.
Teams Uses msal.js to sign in users and acquire tokens on the client on Microsoft Teams
tabs.
Teams Uses msal-browser to sign in users and acquire tokens on Microsoft Teams tabs.
MSAL2 Supports single sign-on (SSO) with a custom backend.
Proxy Allows the use of backend authentication by routing all calls to Microsoft Graph
through your backend.
Custom Creates a custom provider to enable authentication and access to Microsoft Graph
by using your application's existing authentication code.
Cuts development time. The work to connect to Microsoft Graph APIs and render
the data in a UI that looks and feels like a Microsoft 365 experience is done for
you, with no customization required.
Works everywhere. All components are based on web standards and work
seamlessly with any modern browser and web framework (such as React, Angular,
or Vue).
Is beautiful but flexible. The components are designed to look and feel like
Microsoft 365 experiences but are also customizable by using CSS custom
properties and templating.
Web app
Microsoft Teams tab
Progressive Web App (PWA)
Electron app
SharePoint web part
Where can I use it?
Microsoft Graph Toolkit is supported in the following browsers:
Next steps
Try out the components in the playground .
Get started with Microsoft Graph Toolkit.
Check out Microsoft Graph Toolkit on GitHub .
Get started with Microsoft Graph Toolkit
Article • 11/05/2022
Microsoft Graph Toolkit components can easily be added to your web application,
SharePoint web part, or Microsoft Teams tabs. The components are based on web
standards and can be used in both plain JavaScript projects or with popular web
frameworks such as Reach, Angular, and Vue.js.
For a step-by-step tutorial, see the Get started with Microsoft Graph Toolkit module.
A text editor or IDE. You can use the editor or IDE of your choice, or you can install
and use Visual Studio Code for free.
A modern web browser such as Microsoft Edge, Google Chrome, or Firefox.
An LTS version of Node.js, which you can install from nodejs.org .
unpkg
To use the toolkit via mgt-loader , add the reference in a script to your code:
HTML
<script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-
loader.js"></script>
<mgt-msal2-provider client-id="<YOUR_CLIENT_ID>"></mgt-msal2-provider>
<mgt-login></mgt-login>
NPM packages
Microsoft Graph Toolkit is made up of several NPM packages, allowing you to only
include the code that you need for your applications.
@microsoft/mgt-element
The @microsoft/mgt-element is the core package that contains only the base classes
used for building components and providers. This package exposes all the necessary
classes and interfaces that you need to build your own components, and exports the
IProvider interface and SimpleProvider class for building custom providers.
@microsoft/mgt-components
Providers
Providers are available via a single package and can be installed as needed. The
following provider packages are available:
@microsoft/mgt-msal-provider
component. The MSAL provider uses msal.js for authenticating in web apps and
Progressive Web Apps (PWAs).
@microsoft/mgt-msal2-provider
@microsoft/mgt-teams-provider
@microsoft/mgt-teams-msal2-provider
@microsoft/mgt-sharepoint-provider
@microsoft/mgt-proxy-provider
@microsoft/mgt
The @microsoft/mgt package is the main package that includes all the preceding
packages and re-exports them so they are available via a single package that you can
install.
@microsoft/mgt-react
@microsoft/mgt-spfx
Next steps
You're now ready to start developing with Microsoft Graph Toolkit! The following guides
are available to help you get started:
The Microsoft Graph Toolkit React components ( mgt-react ) allow React developers to
use the Microsoft Graph Toolkit in their React applications. The library wraps all
Microsoft Graph Toolkit components and exports them as React components.
The names of the React components are in PascalCase and do not include the Mgt
prefix. For example, the mgt-person component is available as Person , and the mgt-
people-picker component is available as PeoplePicker .
Installation
To install, use one of the following commands.
Bash
or
Bash
Usage
All components are available via the npm package and are named using PascalCase. To
use a component, first import it at the top.
tsx
tsx
All properties and events map exactly as they are defined in the component
documentation.
jsx
jsx
return
<div>
<PeoplePicker selectionChanged={handleSelectionChanged} />
Selected People: <People people={people} />
</div>;
};
Templates
Most Microsoft Graph Toolkit components support templating and mgt-react allows
you to use React to write templates.
For example, to create a template to be used for rendering events in the mgt-agenda
component, first define a component to be used for rendering an event:
tsx
Then use it as a child of the wrapped component and set the template prop to event .
tsx
The template prop allows you to specify which template to overwrite. In this case, the
MyEvent component will be repeated for every event, and the event object will be
See also
Get started with the Microsoft Graph Toolkit in React
Learn about authentication providers
SharePoint Framework library for
Microsoft Graph Toolkit
Article • 01/07/2023
Use the SharePoint Framework library for Microsoft Graph Toolkit to use Microsoft
Graph Toolkit in SharePoint Framework solutions.
To prevent multiple components from registering their own set of Microsoft Graph
Toolkit components on the page, you should deploy this library to your tenant and
reference Microsoft Graph Toolkit components that you use in your solution from this
library.
U Caution
The SharePoint Framework library for Microsoft Graph Toolkit is meant to be used
with SharePoint Framework extensions and non-isolated web parts. If you're
building isolated web parts, don't use the SharePoint Framework library for
Microsoft Graph Toolkit. Instead, load Microsoft Graph Toolkit directly from the
@microsoft/mgt (or @microsoft/mgt-react if you use React) package. SharePoint
Framework doesn't support referencing library components from isolated web
parts and doing so will cause runtime errors in the isolated web part.
Prerequisites
Before you deploy your SharePoint Framework package to your tenant, you will need to
deploy the @microsoft/mgt-spfx SharePoint Framework package to your tenant. You can
download the package that corresponds to the version of @microsoft/mgt-spfx that you
used in your project from the Releases section on GitHub. This package needs to be
uploaded to the App Catalog and deplyoed to all sites.
) Important
Because only one version of the SharePoint Framework library for Microsoft Graph
Toolkit can be installed in the tenant, before you use the Microsoft Graph Toolkit in
your solution, determine whether your organization or customer already has a
version of the SharePoint Framework library deployed and use the same version.
Installation
To load Microsoft Graph Toolkit components from the library, add the @microsoft/mgt-
spfx package as a runtime dependency to your SharePoint Framework project:
Bash
or
Bash
Usage
When building SharePoint Framework web parts and extensions, reference the Microsoft
Graph Toolkit Provider and SharePointProvider from the @microsoft/mgt-spfx package.
This will ensure that your solution will use Microsoft Graph Toolkit components that are
already registered on the page, rather than instantiating its own. The instantiation
process is the same for all web parts no matter which JavaScript framework they use.
ts
When building web parts using a framework other than React, you can load components
directly in your web part:
ts
export default class MgtNoFrameworkWebPart extends
BaseClientSideWebPart<IMgtNoFrameworkWebPartProps> {
protected async onInit() {
if (!Providers.globalProvider) {
Providers.globalProvider = new SharePointProvider(this.context);
}
}
React
If you're building a web part using React, you can use the @microsoft/mgt-react
package. However, make sure to import all React components from the @microsoft/mgt-
react/dist/es6/spfx path. This will ensure that your solution will only use Microsoft
Graph Toolkit components that are already registered on the page, rather than
instantiating its own.
tsx
) Important
Make sure all Microsoft Graph Toolkit imports in your solution are from either:
@microsoft/mgt-spfx or
@microsoft/mgt-react/dist/es6/spfx
Do not import from any other Microsoft Graph Toolkit packages ( @microsoft/mgt-* )
to avoid packaging your own copy of the toolkit and colliding with the shared
library.
See also
Build a SharePoint web part with the Microsoft Graph Toolkit
Learn about authentication providers
Create an Azure Active Directory app to
use with the Microsoft Graph Toolkit
Article • 03/31/2022
Microsoft Graph, the API that you use to connect to Microsoft 365, is secured with
OAuth 2.0. In order to connect your app to Microsoft 365, you will need to create an app
in Azure Active Directory (Azure AD) and grant this app permissions to access specific
resources on behalf of the person using your app. This topic describes how to register
and configure a web application to use with Microsoft Graph Toolkit.
Next steps
Build a web application (vanilla JavaScript)
Build a Microsoft Teams tab
Use the Toolkit with React
Use the Toolkit with Angular
Build a web application with the
Microsoft Graph Toolkit
Article • 11/05/2022
This topic describes how to get started with the Microsoft Graph Toolkit in a web
application written in vanilla JavaScript. For a step-by-step tutorial, try the Get started
with Microsoft Graph Toolkit module. If you would like to learn how to use the Toolkit
with a web framework, see Build a web app (React) or Build a web app (Angular).
Getting started with the Microsoft Graph Toolkit involves the following steps:
unpkg
To use the Toolkit via mgt-loader, add the reference in a script to your code:
HTML
<script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-
loader.js"></script>
You can choose to initialize the provider in either your HTML or your JavaScript code.
HTML
Add the mgt-msal2-provider component to your HTML page and set the client-id
to your application client-id.
HTML
<mgt-msal2-provider client-id="<YOUR_CLIENT_ID>"></mgt-msal2-provider>
The client ID is the only property required to initialize the provider, but you can set
additional options. For the full list, see MSAL2 Provider.
Creating an app/client ID
In order to get a client ID, you need to register your application in Azure AD.
Add components
After you initialize the MSAL2 provider, you can start using any of the Toolkit
components.
HTML
The following is a full working example using mgt-loader, the MSAL2 Provider
initialized in HTML, and the Login component:
HTML
<script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-
loader.js"></script>
<mgt-msal2-provider client-id="<YOUR_CLIENT_ID>"></mgt-msal2-provider>
<mgt-login></mgt-login>
This is an example using the ES6 modules, the MSAL2 Provider initialized in HTML,
and the Login component:
HTML
<script type="module"
src="node_modules/@microsoft/mgt/dist/es6/index.js"></script>
<mgt-msal2-provider client-id="<YOUR_CLIENT_ID>"></mgt-msal2-provider>
<mgt-login></mgt-login>
If you're just getting started and want to play around, you can use Live Server in
Visual Studio Code or any similar lightweight development server. Download the
extension and open your HTML file using live server.
Note: Make sure the redirect URI in your app registration is set to the localhost port
your application is hosted on. Go to your app registration in the Azure portal , click
Authentication under manage, and add the correct redirect URI.
To properly inspect the user's sign in state, add an event handler to the providerUpdated
event using the Providers.onProviderUpdated function. In the handler, check the
provider state stored on the Providers.globalProvider.state property.
HTML
If you're using the mgt-loader library, you can access the Provider and
ProviderState from the global mgt property.
HTML
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-
loader.js"></script>
</head>
<body>
<mgt-msal2-provider client-id="<YOUR_CLIENT_ID>"></mgt-msal2-provider>
<div id="main">
<mgt-login></mgt-login>
</div>
<script>
const loadAgenda = () => {
if (mgt.Providers.globalProvider.state ===
mgt.ProviderState.SignedIn) {
document.getElementById('main').innerHTML = '<mgt-agenda></mgt-
agenda>';
}
}
mgt.Providers.onProviderUpdated(loadAgenda);
</script>
</body>
</html>
Next Steps
Check out the Get started with Microsoft Graph Toolkit step-by-step tutorial.
Try out the components in the playground .
Ask a question on Stack Overflow .
Report bugs or leave a feature request on GitHub .
Use the Microsoft Graph Toolkit with
React
Article • 03/31/2022
If you're building apps with React, you can use the @microsoft/mgt-react package,
which wraps Microsoft Graph Toolkit web components in React components and makes
it easier to pass complex data.
This article describes the step-by-step process of using the Microsoft Graph Toolkit to
create a React app and connect it to Microsoft 365. After completing the steps, you'll
have a React app that shows the upcoming appointments of the currently signed in user
from Microsoft 365.
Tip
You can also follow this tutorial as an interactive code tour. For details, see the
GitHub repo with the starter project .
Prerequisites
To follow the steps in this article, you'll need a Microsoft 365 development environment
and a few tools. For details, see getting started.
Command
cd my-m365-app
Next, install the mgt-react npm package, which contains the Microsoft Graph Toolkit
React components.
Command
npm i @microsoft/mgt-react
Install the mgt-msal2-provider and mgt-element npm package as well, which contains
the MSAL2 auth provider.
Command
Command
npm start
You should be able to open your app in the browser via http://localhost:3000 .
Follow the steps in the Create an Azure Active Directory app article to create a new
Azure AD app.
7 Note
If you are currently using the MSAL Provider and would like to update to the
MSAL2 Provider, follow the steps in the MSAL2 Provider article.
1. In the code editor, open the src/index.tsx file, and to the list of imports, add:
TypeScript
2. After the last import statement, initialize the Microsoft Graph Toolkit with MSAL
provider.
TypeScript
Replace the value of the clientId property with the value of the Application
(client) ID property you copied previously in the Azure Portal.
With these changes, the src/index.tsx file will look like the following.
tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
1. In the code editor, open the src/App.tsx file, and to the list of imports add:
TypeScript
2. In the App function, replace the contents of the return clause with the basic
structure including the Microsoft Graph Toolkit Login component:
TypeScript
<div className="App">
<header>
<Login />
</header>
</div>
With these changes, the src/App.tsx file will look like the following.
TypeScript
function App() {
return (
<div className="App">
<header>
<Login />
</header>
</div>
);
}
1. Go back to the browser where your React app is running. You should now see a
Sign in button.
2. When you click the Sign in button, you will be prompted to sign in with your
Microsoft account (you can use the same account as the one you accessed the
Azure Portal with).
3. Because this is the first time you're using this Azure AD application, you need to
consent its use in your organization.
4. After signing in, you will be redirected to your React app. Notice that the Sign in
button changed to show your user's name
.
Load data from Microsoft 365
Microsoft Graph Toolkit not only simplifies authentication to Microsoft 365, but also
loading its data. In this example, you'll show the signed in person's calendar.
1. In the code editor, open the src/index.tsx file, and update the provider
initialization code.
TypeScript
To track the user's sign in state in your application, you will use the React useState and
useEffect hooks in combination with provider event handlers.
1. In the code editor, open the src/App.tsx file and extend the existing React import
statement.
TypeScript
import React, { useState, useEffect } from 'react';
TypeScript
3. Add a custom function named useIsSignedIn that enables tracking the user's sign
in state in your application.
TypeScript
useEffect(() => {
const updateState = () => {
const provider = Providers.globalProvider;
setIsSignedIn(provider && provider.state ===
ProviderState.SignedIn);
};
Providers.onProviderUpdated(updateState);
updateState();
return () => {
Providers.removeProviderUpdatedListener(updateState);
}
}, []);
return [isSignedIn];
}
This function does two things. First, using the React useState hook, it enables tracking
state inside your component. Whenever the state changes, React will re-render your
component. Second, using the React useEffect hook, it extends the component's
lifecycle by tracking changes in the Microsoft Graph Toolkit provider and updating the
component if necessary.
TypeScript
TypeScript
This defines a Boolean isSignedIn constant, which you can use to determine
whether the user is currently signed in to your application.
3. Extend the contents of the return clause with an additional div and the Microsoft
Graph Toolkit Agenda component.
TypeScript
<div>
{isSignedIn &&
<Agenda />}
</div>
With these changes, the src/App.tsx file should look like the following.
TypeScript
useEffect(() => {
const updateState = () => {
const provider = Providers.globalProvider;
setIsSignedIn(provider && provider.state === ProviderState.SignedIn);
};
Providers.onProviderUpdated(updateState);
updateState();
return () => {
Providers.removeProviderUpdatedListener(updateState);
}
}, []);
return [isSignedIn];
}
function App() {
const [isSignedIn] = useIsSignedIn();
return (
<div className="App">
<header>
<Login />
</header>
<div>
{isSignedIn &&
<Agenda />}
</div>
</div>
);
}
1. To see the changes, close the browser and open it again, and go to
http://localhost:3000 . You do this because you changed the value of the scopes
property, which affects the access token that you request from Azure AD.
2. Choose the Sign In button and sign in using your Microsoft account. Notice the
additions to the list of permissions requested in the consent prompt. This is
because you included additional permissions in the scope property.
3. After consenting to the use of the application, you should see information about
the current user and their calendar.
Next steps
See what's in the Microsoft Graph Toolkit.
Try out the components in the playground .
Ask a question on Stack Overflow .
Report bugs or leave a feature request on GitHub .
Use the Microsoft Graph Toolkit with
Angular
Article • 03/31/2022
Microsoft Graph Toolkit components work great with web frameworks like Angular in
addition to vanilla JavaScript and HTML. This topic describes how to use the Microsoft
Graph Toolkit with Angular. For a step-by-step walkthrough that describes how to create
a new Angular application and use the Microsoft Graph Toolkit, see Using Microsoft
Graph Toolkit with Angular.
TypeScript
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
Next, add the Microsoft Graph Toolkit to your project by installing the npm package
with:
Command
Initialize a provider
The Microsoft Graph Toolkit providers enable authentication and access to Microsoft
Graph for the components. To learn more, see Using the providers. The provider you use
depends on the context in which your solution will be used.
The following example shows how to add the MSAL2 Provider, but you can follow the
same model with any of the providers.
7 Note
If you are currently using the MSAL Provider and would like to update to the
MSAL2 Provider, follow the steps in the MSAL2 Provider article.
Import the provider and set it to initialize when the application initializes. Replace
<YOUR-CLIENT-ID> with the client ID for your application.
TypeScript
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
ngOnInit()
{
Providers.globalProvider = new Msal2Provider({
clientId: '<YOUR-CLIENT-ID>'
});
}
}
Create an app/client ID
In order to get a client ID, you need to register your application in Azure AD.
Add components
Now, you can use any of the Microsoft Graph Toolkit components as you normally
would in your HTML templates. For example, to add the Person component, add the
following to your template:
HTML
HTML
<!-- Double braces are used for data binding in Angular. This will throw an
error. -->
<mgt-agenda>
<template data-type="event">
<div>{{event.subject}}</div>
</template>
</mgt-agenda>
In Angular, however, double braces are used for data binding and the Angular compiler
will throw an error if you try to use the double brace syntax.
You can avoid these errors by changing the default characters used by the Toolkit to
something other than double braces by using the TemplateHelper . It is best to do this in
your top-level App component so that it applies globally.
Import the TemplateHelper and use the .setBindingSyntax() method to set your
custom binding syntax.
TypeScript
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
ngOnInit()
{
Providers.globalProvider = new Msal2Provider({ clientId: '<YOUR-
CLIENT-ID>'})
TemplateHelper.setBindingSyntax('[[',']]');
}
}
Now, you can use your custom binding syntax to define custom templates.
HTML
<mgt-agenda>
<template data-type="event">
<div>[[event.subject]]</div>
</template>
</mgt-agenda>
Next steps
Check out this step-by-step tutorial on building an Angular app.
Try out the components in the playground .
Ask a question on Stack Overflow .
Report bugs or leave a feature request on GitHub .
Build a SharePoint web part with the
Microsoft Graph Toolkit
Article • 03/31/2022
This topic covers how to use Microsoft Graph Toolkit components in a SharePoint client-
side web part. Getting started involves the following steps:
Install the Microsoft Graph Toolkit SharePoint Framework npm package using the
following command:
Bash
First, add the provider to your web part. Locate the src\webparts\<your-project>\<your-
web-part>.ts file in your project folder, and add the following line to the top of your file,
right below the existing import statements:
ts
Next, you need to initialize the provider with the authenticated context inside the
onInit() method of your web part. In the same file, add the following code right before
ts
Add components
Now, you can start adding components to your web part. Simply add the components
to the HTML inside of the render() method, and the components will use the
SharePoint context to access Microsoft Graph. For example, to add the Person
component, your code will look like:
ts
public render(): void {
this.domElement.innerHTML = `
<mgt-person person-query="me" view="twolines"></mgt-person>
`;
}
7 Note
If you're building a web part using React, see the @microsoft/mgt-spfx docs to
learn how to use @microsoft/mgt-react .
Configure permissions
To call Microsoft Graph from your SharePoint Framework application, you need to
request the needed permissions in your solution package and a Microsoft 365 tenant
administrator needs to approve the requested permissions.
To add the permissions to your solution package, locate and open the config\package-
solution.json file and set:
JSON
"isDomainIsolated": false,
JSON
"webApiPermissionRequests":[],
Determine which Microsoft Graph API permissions you need depending on the
components you're using. Each component's documentation page provides a list of the
permissions that component requires. You will need to add each permission required to
webApiPermissionRequests . For example, if you're using the Person component and the
Agenda component, your webApiPermissionRequests might look like:
JSON
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "User.Read"
},
{
"resource": "Microsoft Graph",
"scope": "Calendars.Read"
}
]
) Important
Because only one version of the SharePoint Framework library for Microsoft Graph
Toolkit can be installed in the tenant, before you use the Microsoft Graph Toolkit in
your solution, determine whether your organization or customer already has a
version of the SharePoint Framework library deployed and use the same version.
After downloading the Microsoft Graph Toolkit SharePoint Framework .sppkg package,
upload it to your SharePoint Online App Catalog. Go to the More features page of your
SharePoint admin center . Select Open under Apps, then click App Catalog, and
Distribute apps for SharePoint. Upload your .sppkg file, and click Deploy.
Bash
gulp build
gulp bundle
gulp package-solution
In the sharepoint/solution folder, there will be a new .sppkg file. You will need to
upload this file to your SharePoint Online App Catalog. Go to the More features page of
your SharePoint admin center . Select Open under Apps, then click App Catalog, and
Distribute apps for SharePoint. Upload your .sppkg file, and click Deploy.
Go to your SharePoint Admin center. In the left-hand navigation, select Advanced and
then API Access. You should see pending requests for each of the permissions you
added in your config\package-solution.json file. Select and approve each permission.
Open the config\serve.json file in your project and replace the value of initialPage
with the url for your hosted workbench:
JSON
"initialPage":
"https://<YOUR_TENANT>.sharepoint.com/_layouts/15/workbench.aspx",
Save the file and then run the following command in the console to build and preview
your web part:
Bash
gulp serve
Your hosted workbench will automatically open in your browser. Add your web part to
the page and you should see your web part with the Microsoft Graph Toolkit
components in action! As long as the gulp serve command is still running in your
console, you can continue to make edits to your code and then just refresh your
browser to see your changes.
Next Steps
Check out this step-by-step tutorial on building a SharePoint web part.
Try out the components in the playground .
Ask a question on Stack Overflow .
Report bugs or leave a feature request on GitHub .
Build a Microsoft Teams tab with the
Microsoft Graph Toolkit
Article • 11/05/2022
This topic covers how to get started using the Microsoft Graph Toolkit in a Microsoft
Teams solution. This guide is for a single page app without single sign-on (SSO) and
does not require a backend. If you're implementing SSO with a custom backend, see
Build a Microsoft Teams tab (SSO).
unpkg
To use the Toolkit and the Teams SDK via the loaders, add the reference in a script
to your code:
HTML
<!-- Microsoft Teams sdk must be referenced before the toolkit -->
<script src="https://unpkg.com/@microsoft/teams-
js@2/dist/MicrosoftTeams.min.js" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-
loader.js"></script>
The following is an example of basic page that handles the auth flow in the popup.
unpkg
HTML
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/@microsoft/teams-
js@2/dist/MicrosoftTeams.min.js" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-
loader.js"></script>
</head>
<body>
<script>
mgt.TeamsMsal2Provider.handleAuth();
</script>
</body>
</html>
Creating an app/client ID
To get a client ID, you need to register an Azure Active Directory application. Follow the
steps in the Create an Azure Active Directory app article.
Make sure to set the redirect URI in your app registration to point to the auth page
you created in the previous step. For example, https://localhost:3000/tabauth.
Note: Make sure to set the redirect URI as a Single Page Application (SPA) .
Teams MSAL2 Provider makes use of MSAL2 Provider behind the scenes.
You can choose to initialize the provider in either your HTML or your JavaScript code.
html
HTML
<mgt-teams-msal2-provider
client-id="<YOUR_CLIENT_ID>"
auth-popup-url="/tabauth"
scopes="User.Read,Mail.ReadBasic"
></mgt-teams-msal2-provider>
Replace <YOUR_CLIENT_ID> with the client ID for your application, and replace the
auth-popup-url with the full or relative path to your auth page.
Add components
Now, you're ready to add any of the Microsoft Graph Toolkit components. The first
component you will likely need to add is the Login component.
HTML
<mgt-login></mgt-login>
The Login component renders a "Sign In" button that guides the user through the sign
in process and integrates with any of the providers to handle the authentication. After
the user has signed in, all other toolkit components will be able to call Microsoft Graph
automatically. The providers also expose an authenticated Microsoft Graph client for
making API calls or getting access tokens. For details, see Using the providers.
If you're using React, we recommend using the React components instead from the mgt-
react library. To learn more, see Using Microsoft Graph Toolkit with React
Next Steps
Try out the components in the playground .
Ask a question on Microsoft Q&A.
Report bugs or leave a feature request on GitHub .
Check out the Microsoft Teams samples .
Build a Microsoft Teams SSO tab with
the Microsoft Graph Toolkit
Article • 11/05/2022
This topic describes how to use the Microsoft Graph Toolkit in a Microsoft Teams
solution. This guide is for a single-page app with single sign-on (SSO) and does require
a backend. If you're implementing a Teams tab with interactive sign in, see Build a
Microsoft Teams Tab.
unpkg
To use the Toolkit and the Teams SDK via the loaders, add the reference in a script
to your code:
HTML
<!-- Microsoft Teams sdk must be referenced before the toolkit -->
<script src="https://unpkg.com/@microsoft/teams-
js@2/dist/MicrosoftTeams.min.js" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-
loader.js"></script>
The following is an example of a basic page that handles the auth flow in the popup.
unpkg
HTML
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/@microsoft/teams-
js@2/dist/MicrosoftTeams.min.js" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-
loader.js"></script>
</head>
<body>
<script>
mgt.TeamsMsal2Provider.handleAuth();
</script>
</body>
</html>
Creating an app/client ID
Your tab needs to run as a registered Azure AD application to get an access token from
Azure AD. Register the app in your tenant and give Microsoft Teams permission to get
access tokens on its behalf:
1. Open a browser and go to the Azure Active Directory admin center . Sign in
using a personal account (Microsoft Account) or Work or School Account.
2. On the left pane, select Azure Active Directory, then select App registrations
under Manage.
3. Select New registration. On the Register an application page, set the values as
follows:
Set Name to Node.js Teams SSO (or a name of your choice).
Set Supported account types to Accounts in any organizational directory
and personal Microsoft accounts.
Under Redirect URI, set the first dropdown to Single Page Application and
set the value to the auth page URL you created in the previous step; for
example, https://myapp.ngrok.io/tabauth .
4. From the app overview page, copy the value of the Application (client) ID for later.
You will need this value when you create a new provider and in your backend.
5. Under Manage, go to Certificates & secrets. Select the New client secret button.
Enter a value in Description and select one of the options for Expires and select
Add.
6. Copy the client secret value before you leave this page. You will need this for your
backend service.
) Important
This client secret is never shown again, so make sure you copy it now.
8. (OPTIONAL) If you want to pre-consent to any other scopes, you can add more
permissions. If you use different components or plan to use other Microsoft Graph
APIs, you might require additional permissions. For details about required
permissions, see the documentation for each component.
9. Under Manage, go to Expose an API. On the top of the page, next to Application
ID URI , select Set. This generates an API in the form of: api://{AppID} . Update it
10. On the same page, select Add a scope. Fill in the fields as follows, and select Add
scope:
State: Enabled
11. Next, add two client applications. This is for the Teams desktop/mobile clients and
the web client. Under the Authorized client applications section, select Add a
client application. Fill in the Client ID and select the scope you created. Then select
Add application. Do this for the followings IDs:
5e3ce6c0-2b1f-4285-8d4b-75ee78787346
1fec8e78-bce4-4aaf-ab1b-5451cc387264
TypeScript
/**
* Validates a JWT
* @param {Request} req - The incoming request
* @param {Response} res - The outgoing response
* @returns {Promise<string | null>} - Returns the token if valid, returns
null if invalid
*/
function validateJwt(req: Request, res: Response, next: NextFunction): void
{
const authHeader = req.headers.authorization!;
const ssoToken = authHeader.split(' ')[1];
if (ssoToken) {
const validationOptions = {
audience: process.env.CLIENT_ID,
};
jwt.verify(ssoToken, getSigningKey, validationOptions, (err, payload) =>
{
if (err) {
return res.sendStatus(403);
}
next();
});
} else {
res.sendStatus(401);
}
}
/**
* Parses the JWT header and retrieves the appropriate public key
* @param {JwtHeader} header - The JWT header
* @param {SigningKeyCallback} callback - Callback function
*/
function getSigningKey(header: JwtHeader, callback: SigningKeyCallback):
void {
const client = jwksClient({
jwksUri: 'https://login.microsoftonline.com/common/discovery/keys'
});
client.getSigningKey(header.kid!, (err, key) => {
if (err) {
callback(err, undefined);
} else {
callback(null, key.getPublicKey());
}
});
}
/**
* Gets an access token for the user using the on-behalf-of flow
* @param authHeader - The Authorization header value containing a JWT
bearer token
* @returns {Promise<string | null>} - Returns the access token if
successful, null if not
*/
async function getAccessTokenOnBehalfOf(req: Request, res: Response):
Promise<void> {
// The token has already been validated, just grab it
const authHeader = req.headers.authorization!;
const ssoToken = authHeader.split(' ')[1];
// Create an MSAL client
const msalClient = new msal.ConfidentialClientApplication({
auth: {
clientId: req.body.clientid,
clientSecret: process.env.APP_SECRET
}
});
try {
const result = await msalClient.acquireTokenOnBehalfOf({
authority: `https://login.microsoftonline.com/${jwt_decode<any>
(ssoToken).tid}`,
oboAssertion: ssoToken,
scopes: req.body.scopes,
skipCache: true
});
res.json({ access_token: result?.accessToken });
} catch (error) {
if (error.errorCode === 'invalid_grant' || error.errorCode ===
'interaction_required') {
// This is expected if it's the user's first time running the app (
user must consent ) or the admin requires MFA
res.status(403).json({ error: 'consent_required' }); // This error
triggers the consent flow in the client.
} else {
// Unknown error
res.status(500).json({ error: error.message });
}
}
}
////////////////////////
// create and run server
////////////////////////
// An example for using POST and with token validation using middleware
app.post('/api/token', validateJwt, async (req, res) => {
await getAccessTokenOnBehalfOf(req, res);
});
app.listen(PORT, () => {
console.log(`⚡️[server]: Server is running at http://localhost:${PORT}`);
});
For SSO-mode, make sure to provide sso-url / ssoUrl and have it point to your
backend API.
HTML
HTML
<mgt-teams-msal2-provider
client-id="<YOUR_CLIENT_ID>"
auth-popup-url="/tabauth"
scopes="User.Read,Mail.ReadBasic"
sso-url="http://localhost:8000/api/token"
http-method="POST"
></mgt-teams-msal2-provider>
Replace <YOUR_CLIENT_ID> with the client ID for your application, replace the auth-
popup-url with the full or relative path to your auth page, and replace sso-url with
Add components
Now, you're ready to add any of the Microsoft Graph Toolkit components.
You can add components to your HTML as you normally would. For example, to add the
Person component, add the following code to your HTML.
HTML
<mgt-person person-query="me"></mgt-person>
If you're using React, we recommend using the React components instead from the mgt-
react library. To learn more, see Using Microsoft Graph Toolkit with React.
If everything has been configured correctly, you will see the Person component
rendered without the need to log in.
) Important
Next Steps
Try out the components in the playground .
Ask a question on Microsoft Q&A.
Report bugs or leave a feature request on GitHub .
Use the Microsoft Graph Toolkit with
Electron
Article • 03/31/2022
This article describes the step-by-step process of using the Microsoft Graph Toolkit to
create an Electron app and connect it to Microsoft 365. After completing the steps,
you'll have a Electron app that shows the upcoming appointments of the currently
signed in user from Microsoft 365.
Change the working directory to the newly created app and install all dependencies.
cd electron-quick-start-typescript
npm install
Install the '@microsoft/mgt-components' package that contains all the Microsoft Graph-
connected web components.
npm i @microsoft/mgt-components
npm start
Create an app/client ID
ts
ts
Next, add these lines of code in the createWindow() function to initialize the
ElectronAuthenticator, right after where mainWindow is declared. Replace
<your_client_id> with the client ID from your app registration.
ts
a Uncaught ReferenceError: require is not defined error. To keep this simple, remove
any preloading scripts.
ts
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Sample Electron-MGT App</title>
</head>
<body>
<mgt-login></mgt-login>
<mgt-agenda group-by-day></mgt-agenda>
<script type="module" src="./dist/renderer.js"></script>
</body>
</html>
Note: Remove any Content-Security-Policy response headers or meta tags if you are
copying this onto an existing file.
Install webpack
webpack.config.js
Create a new webpack.config.js file in the root folder of your project, and paste the
following configuration.
JavaScript
As you can see, the front end (renderer process) and the back-end (main process), are
bundled separately. This is because in Electron, the renderer process runs in the browser
context and the main process runs in the node context.
JSON
"scripts": {
"webpack": "webpack",
"start": "npm run webpack && electron dist/main.js"
}
npm start
Add token caching capabilities to your app and enable
silent sign ins (advanced)
MSAL Node supports an in-memory cache by default and provides the ICachePlugin
interface to perform cache serialization, but does not provide a default way of storing
the token cache to disk. If you need persistent cache storage to enable silent sign ins or
cross-platform caching, we recommend using the default implementation provided by
MSAL Node as an extension . You can import this plugin, and pass the instance of the
cache plugin while initializing ElectronAuthenticator .
ts
For more details about how to implement this, see the microsoft-authentication-library-
for-js sample.
Next Steps
Try out the components in the playground .
Ask a question on Microsoft Q&A.
Report bugs or leave a feature request on GitHub .
Microsoft Graph Toolkit providers
Article • 11/05/2022
The Microsoft Graph Toolkit providers enable your application to authenticate with
Microsoft Identity and access Microsoft Graph in only few lines of code. Each provider
handles user authentication and acquiring the access tokens to call Microsoft Graph
APIs, so that you don't have to write this code yourself.
You can use the providers on their own, without components, to quickly implement
authentication for your app and make calls to Microsoft Graph via the JavaScript client
SDK.
The providers are required when using the Microsoft Graph Toolkit components as the
components use them to access Microsoft Graph. If you already have your own
authentication and want to use the components, you can use a custom provider instead.
Providers Description
MSAL Uses msal.js to sign in users and acquire tokens to use with Microsoft Graph in a
web application.
MSAL2 Uses msal-browser to sign in users and acquire tokens to use with Microsoft Graph
in a web application.
Teams Uses msal.js to sign in users and acquire tokens on the client in Microsoft Teams
tabs.
Teams Uses msal-browser to sign in users and acquire tokens in Microsoft Teams tabs.
MSAL2 Supports Single Sign-On with custom backend.
TeamsFx Use the TeamsFx provider inside your Microsoft Teams applications to provide
Microsoft Graph Toolkit components access to Microsoft Graph.
Proxy Allows the use of backend authentication by routing all calls to Microsoft Graph
through your backend.
Custom Create a custom provider to enable authentication and access to Microsoft Graph
with your application's existing authentication code.
Initializing a provider
To use a provider in your app, you need to initialize a new provider and then set it as the
global provider in the Providers namespace. We recommend doing this before you start
using any of the components. You can do this one of two ways:
You can use the component version of the provider directly in your HTML. Behind the
scenes, a new provider is initialized and set as the global provider. The following
example shows how to use the MSAL2 provider.
HTML
<script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-loader.js">
</script>
<mgt-msal2-provider client-id="YOUR_CLIENT_ID"></mgt-msal2-provider>
Initializing your provider in your JavaScript code enables you to provide more options.
To do this, create a new provider instance and set the value of the
Providers.globalProvider property to the provider you'd like to use. The following
JavaScript
Note: For details about how to register your app and get a client ID, see Create an
Azure Active Directory app.
Permission Scopes
We recommend adding all the permission scopes your application needs to the scopes
attribute or property when initializing your provider (this does not apply to the
SharePoint provider). This is optional, but will improve your user experience by
presenting a single consent screen to the user with an aggregated list of permissions
requested by all components in your app, rather than presenting separate screens for
each component. The following examples show how to do this with the MSAL2 Provider.
HTML
<script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-loader.js">
</script>
<mgt-msal2-provider client-id="YOUR_CLIENT_ID"
scopes="user.read,people.read"
></mgt-msal2-provider>
If you're initializing the provider in code, provide the permission scopes in an array in
the scopes property.
JavaScript
You can find the list of permission scopes required by each component in the Microsoft
Graph permissions section of each component's documentation page.
Provider state
The provider keeps track of the user's authentication state and communicates it to the
components. For example, when a user successfully signs in, the ProviderState is
updated to SignedIn , signaling to the components that they are now able to make calls
to Microsoft Graph. The ProviderState enum defines three states, as shown.
ts
In some scenarios, you will want to show certain functionality or perform an action only
after a user has successfully signed in. You can access and check the provider state, as
shown in the following example.
JavaScript
You can also use the Providers.onProviderUpdated method to get notified whenever the
state of the provider changes.
JavaScript
JavaScript
JavaScript
There might be cases where you need to pass additional permissions, depending on the
API you're calling. The following example shows how to do this.
JavaScript
graphClient
.api('me')
.middlewareOptions(prepScopes('user.read', 'calendar.read'))
.get();
HTML
<mgt-teams-msal2-provider
client-id="[CLIENT-ID]"
auth-popup-url="auth.html" ></mgt-teams-msal2-provider>
<mgt-msal2-provider
client-id="[CLIENT-ID]"
depends-on="mgt-teams-provider" ></mgt-msal2-provider>
In this scenario, the MSAL2 provider will only be used if your app is running as a web
application and the Teams MSAL2 provider is not available in the current environment.
To accomplish the same in code, you can use the isAvailable property on the provider,
as shown.
ts
if (TeamsProvider.isAvailable) {
Providers.globalProvider = new TeamsProvider(teamsConfig);
} else {
Providers.globalProvider = new Msal2Provider(msalConfig)
}
User Login/Logout
When you have the right providers initialized for your application, you can add the
Toolkit's Login component to easily and quickly implement user login and logout. The
component works with the provider to handle all of the authentication logic and
login/logout functionality. The following example uses the MSAL2 provider and the
Login component.
HTML
<script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-loader.js">
</script>
<mgt-msal2-provider client-id="YOUR_CLIENT_ID"></mgt-msal2-provider>
<mgt-login></mgt-login>
In scenarios where you want to implement this yourself, rather than using the Toolkit's
Login component, you can do so by using the login and logout methods of the
provider.
The MSAL Provider uses msal.js to sign in users and acquire tokens to use with
Microsoft Graph.
All new applications should use MSAL2 Provider whenever possible. For migration
information, see MSAL2 Provider.
Get started
You can initialize the MSAL provider in HTML or JavaScript.
HTML
<mgt-msal-provider client-id="<YOUR_CLIENT_ID>"
login-type="redirect/popup"
scopes="user.read,people.read"
redirect-uri="https://my.redirect/uri"
authority=""
domainHint="mydomain.com"
prompt="consent"></mgt-msal-provider>
Attribute Description
login- Enumeration between redirect and popup - default value is redirect . Optional.
type
scopes Comma separated strings for scopes the user must consent to on sign in. Optional.
authority Authority string - default is the common authority. For single-tenant apps, use your
tenant ID or tenant name. For example, https://login.microsoftonline.com/[your-
tenant-name].onmicrosoft.com or https://login.microsoftonline.com/[your-tenant-
id] . Optional.
redirect- Redirect URI string - by default the current window URI is used. Optional.
uri
depends- Element selector string of another higher priority provider component. Optional.
on
domain- Query string of domain location for forwarding sign in experience. Optional.
hint
prompt Selection for type of user interaction required to login. Valid options include:
login forces the user to enter credentials on request
none for no interactive prompt
select_account to send the user to an account picker
consent to send the user to a OAuth consent dialog
For more prompt information, see the prompt behavior in MSAL.js article. Optional.
Initialize in JavaScript
You can provide more options by initializing the provider in JavaScript.
ts
You can configure the MsalProvider constructor parameter in two ways, as described in
the following sections.
Provide a clientId to create a new UserAgentApplication
This option makes sense when Graph Toolkit is responsible for all authentication in your
application.
ts
interface MsalConfig {
clientId: string;
scopes?: string[];
authority?: string;
redirectUri?: string;
loginType?: LoginType; // LoginType.Popup or LoginType.Redirect (redirect
is default)
loginHint?: string
options?: Configuration; // msal js Configuration object
domainHint?: string;
prompt?: string; // "login", "none", "select_account", "consent"
}
Be sure to understand opportunities for collisions when using this option. By its very
nature, there is a risk that the MsalProvider can change the state of a session, for
example by having the user sign in or consent to additional scopes. Make sure that your
app and other frameworks respond gracefully to these changes in state, or consider
using a custom provider instead.
ts
interface MsalConfig {
userAgentApplication: UserAgentApplication;
scopes?: string[];
loginType?: LoginType; // LoginType.Popup or LoginType.Redirect (redirect
is default)
loginHint?: string;
}
To learn more about MSAL.js and for additional options you can use when initializing the
MSAL library, see the MSAL documentation.
Creating an app/client ID
For details about how to register an app and get a client ID, see Create an Azure Active
Directory app.
MSAL2 Provider
Article • 12/28/2022
The MSAL2 Provider uses msal-browser to sign in users and acquire tokens to use
with Microsoft Graph.
Get started
You can initialize the MSAL2 Provider in HTML or JavaScript.
HTML
<mgt-msal2-provider client-id="<YOUR_CLIENT_ID>"
login-type="redirect/popup"
scopes="user.read,people.read"
redirect-uri="https://my.redirect/uri"
authority="">
</mgt-msal2-provider>
Attribute Description
login-type Enumeration between redirect and popup - default value is redirect . Optional.
scopes Comma separated strings for scopes the user must consent to on sign in. Optional.
authority Authority string - default is the common authority. For single-tenant apps, use
your tenant ID or tenant name. For example,
https://login.microsoftonline.com/[your-tenant-name].onmicrosoft.com or
https://login.microsoftonline.com/[your-tenant-id] . Optional.
redirect-uri Redirect URI string - by default the current window URI is used. Optional.
prompt Type of prompt to use for login, between SELECT_ACCOUNT , CONSENT and LOGIN .
Default is SELECT_ACCOUNT . Optional.
Initialize in JavaScript
You can provide more options by initializing the provider in JavaScript.
ts
You can configure the Msal2Provider constructor parameter in two ways, as described in
the following sections.
ts
interface Msal2Config {
clientId: string;
scopes?: string[];
authority?: string;
redirectUri?: string;
loginType?: LoginType; // LoginType.Popup or LoginType.Redirect (redirect
is default)
prompt?: PromptType; // PromptType.CONSENT, PromptType.LOGIN or
PromptType.SELECT_ACCOUNT
sid?: string; // Session ID
loginHint?: string;
domainHint?: string;
isIncrementalConsentDisabled?: boolean, //Disable incremental consent,
true by default
options?: Configuration // msal-browser Configuration object
}
Use this when your app uses MSAL functionality beyond what's exposed by the
Msal2Provider and other Microsoft Graph Toolkit features. This is particularly
Be sure to understand opportunities for collisions when using this option. By its very
nature, there is a risk that the Msal2Provider can change the state of a session; for
example, by having the user sign in or consent to additional scopes. Make sure that your
app and other frameworks respond gracefully to these changes in state, or consider
using a custom provider instead.
ts
interface Msal2PublicClientApplicationConfig {
publicClientApplication: PublicClientApplication;
scopes?: string[];
authority?: string;
redirectUri?: string;
loginType?: LoginType; // LoginType.Popup or LoginType.Redirect (redirect
is default)
prompt?: PromptType; // PromptType.CONSENT, PromptType.LOGIN or
PromptType.SELECT_ACCOUNT
sid?: string; // Session ID
loginHint?: string;
domainHint?: string;
isIncrementalConsentDisabled?: boolean, //Disable incremental consent,
true by default
options?: Configuration // msal-browser Configuration object
}
Creating an app/client ID
For details about how to register an app and get a client ID, see Create an Azure Active
Directory app.
4. Select the app registration of the app that you're currently using.
7. Remove all the redirect URIs that you have currently registered under Web, and
instead add them under Single-page application.
If you are initializing your provider in the JS/TS code, follow these steps:
ts
ts
Providers.globalProvider = new Msal2Provider({
clientId: 'REPLACE_WITH_CLIENTID'
...
})
HTML
with
HTML
Use the SharePoint provider inside your SharePoint web parts to power the components
with Microsoft Graph access.
Get started
Initialize the provider inside the onInit() method of your web part. This example uses
the @microsoft/mgt-spfx package.
ts
// add the onInit() method if not already there in your web part class
protected async onInit() {
Providers.globalProvider = new SharePointProvider(this.context);
}
Now you can add any component in your render() method and it will use the
SharePoint context to access Microsoft Graph.
ts
Note: The Microsoft Graph Toolkit requires Typescript 3.7 or newer. Make sure
you're using a supported version of Typescript by installing the right compiler .
Sample
For details about how to initialize the SharePoint provider, see the Build a SharePoint
web part getting started guide.
Test in the workbench
If you're just getting started with SharePoint web parts, you can follow the Build your
first web part guidance.
After you've created a web part, and you're ready to use the components, you will need
to make sure that your web part has the right permissions to access Microsoft Graph.
For details, see Consume Microsoft Graph in the SharePoint Framework.
In short, it's important to add the right permission to your package-solution.json . You
will need to upload a package of your web part to SharePoint and have an administrator
approve the requested permissions.
Tip
The Build a SharePoint web part getting started guide provides step-by-step
instructions for configuring and approving permissions.
Note: if you're not sure what permissions to add, the documentation for each
component includes all the permissions it needs.
Microsoft Teams provider
Article • 11/05/2022
Use the TeamsProvider inside your Microsoft Teams tab to facilitate authentication and
Microsoft Graph access to all components.
Tip: For details about how to get started with creating a Microsoft Teams application
with the Teams Provider, see the Build a Microsoft Teams tab getting started guide.
All new applications should use the Teams MSAL2 Provider whenever possible. See
Teams MSAL2 Provider for migration documentation.
Get started
Before using the Teams provider, you will need to make sure you have referenced the
Microsoft Teams SDK in your page.
npm
Make sure to install both the toolkit and the Microsoft Teams SDK.
ts
import * as microsoftTeams from "@microsoft/teams-js";
import {Providers, TeamsProvider} from '@microsoft/mgt';
TeamsProvider.microsoftTeamsLib = microsoftTeams;
Providers.globalProvider = new TeamsProvider(config);
where config is
ts
npm
ts
TeamsProvider.microsoftTeamsLib = microsoftTeams;
TeamsProvider.handleAuth();
You can also use the Teams Toolkit in Visual Studio Code to quickly create and deploy
your Teams app.
Creating an app/client ID
In order to get a client ID, you need to register your application in Azure AD.
Note: MSAL only supports the Implicit Flow for OAuth. Make sure to enable Implicit
Flow in your application in the Azure Portal (it is not enabled by default). Under
Authentication, find the Implicit grant section and select the checkboxes for Access
tokens and ID tokens.
See also
Microsoft Teams tab sample
Build a Microsoft Teams tab
Microsoft Teams MSAL2 provider
Article • 03/03/2023
Use the Microsoft Teams MSAL2 provider inside your Microsoft Teams tab to facilitate
authentication and Microsoft Graph access to all components. The provider can be used
for single sign-on (SSO) or interactive sign in.
Tip: For details about how to create a Microsoft Teams application with the Teams
MSAL2 provider, see Build a Microsoft Teams tab and Build a Microsoft Teams tab
with SSO.
All new applications should use Teams MSAL2 provider whenever possible.
Get started
The provider can be used in interactive client side auth mode or SSO mode.
Client-side authentication
In client-side authentication (or interactive authentication), the user will be asked to
authenticate when they first launch the app. The user will need to use a sign in button to
initiate the authentication flow. This can be done on the client and does not require a
backend service.
SSO authentication
To avoid asking the user to authenticate to the app, Microsoft Teams tabs can also use
SSO to automatically authenticate users. However, this process requires a backend
service that is used to exchange the Microsoft Teams-provided token with an access
token that can be used to access Microsoft Graph.
Teams MSAL2 provider supports SSO mode, which is enabled when ssoUrl \ sso-url
are set to a backend service that is capable of exchanging the tokens. The backend
service is required to expose an API (such as api/token ) that will receive an
authentication token from Microsoft Teams and use the on-behalf-of flow to exchange
the token for an access token that can access Microsoft Graph. For a reference
implementation of a node backend service, see the Microsoft Teams Node SSO
sample .
npm
When initializing the Teams MSAL2 provider in JavaScript, make sure to install both
the toolkit and the Microsoft Teams SDK.
ts
TeamsMsal2Provider.microsoftTeamsLib = MicrosoftTeams;
where config is
ts
export interface TeamsMsal2Config {
clientId: string;
authPopupUrl: string; // see below for creating the popup page
scopes?: string[];
msalOptions?: Configuration;
ssoUrl?: string; // ex: '/api/token',
autoConsent?: boolean,
httpMethod: HttpMethod; //ex HttpMethod.POST
}
npm
ts
TeamsMsal2Provider.microsoftTeamsLib = MicrosoftTeams;
TeamsMsal2Provider.handleAuth();
You can also use the Teams Toolkit in Visual Studio Code to quickly create and deploy
your Teams app.
Creating an app/client ID
For details about how to register an app and get a client ID for interactive
authentication, see Create an Azure Active Directory app.
For details about how to register an app and get a client ID and secret for SSO, see Build
a Microsoft Teams tab with Single Sign-On.
4. Select the app registration of the app that you're currently using.
7. Remove all the redirect URIs that you have currently registered under Web, and
instead add them under Single-page application.
If you are initializing your provider in the JS/TS code, follow these steps:
ts
ts
with
HTML
See also
Microsoft Teams Node SSO sample
Build a Microsoft Teams tab
Build a Microsoft Teams tab with SSO
TeamsFx provider
Article • 11/18/2022
Use the TeamsFx provider inside your Microsoft Teams applications to provide Microsoft
Graph Toolkit components access to Microsoft Graph.
Get started
1. Initialize the provider and login to get the required access token
ts
ts
ts
ts
2. Now you can add any component in your HTML page or in your render() method
when using React and it will use the TeamsFx context to access Microsoft Graph.
HTML
ts
// Using React
public render(): void {
return (
<div>
<Person personQuery="me" view={PersonViewType.threelines}>
</Person>
</div>
);
}
For a sample that shows you how to initialize the TeamsFx provider, see the Contacts
Exporter sample .
See also
Get started with Microsoft Teams and Teams Toolkit development
TeamsFx SDK
One Productivity Hub workshop
Electron provider
Article • 03/31/2022
The Electron provider uses msal-node to sign in users and acquire tokens to use with
Microsoft Graph in an Electron application.
Get started
You need to initialize ElectronProvider in the renderer process (front end), and
ElectronAuthenticator in the main process (back end).
ts
ts
ElectronAuthenticator.initialize(config);
Attribute Description
scopes Comma-separated strings for scopes the user must consent to on sign in.
Recommended.
authority Authority string - default is the common authority. For single-tenant apps, use
your tenant ID or tenant name. For example,
https://login.microsoftonline.com/[your-tenant-name].onmicrosoft.com or
https://login.microsoftonline.com/[your-tenant-id] . Optional.
cachePlugin Cache plugin you would like to use for persistent storage of tokens. See Microsoft
Authentication Extensions for Node . Optional.
Note: Currently, the provider does not support incremental support. As a best
practice, be sure to consent to all the scopes that the components require.
Create an app/client ID
Next steps
Check out the step-by-step tutorial for building an electron app.
Take a look at a sample Electron application that shows how to use the Electron
provider.
Proxy provider
Article • 03/31/2022
When you use the proxy provider, you can use your backend authentication (such as
Auth2.0 On-Behalf-Of flow) to power the Microsoft Graph Toolkit by routing all calls to
Microsoft Graph through your own backend.
Your backend service must expose an API that will be called for every call to Microsoft
Graph. For example, when a component attempts to get a resource, the ProxyProvider
will instead call your base API and append that resource.
https://graph.microsoft.com/v1.0/me =>
https://myurl.com/api/GraphProxy/v1.0/me
Your API implementation should then call Microsoft Graph on behalf of the user and
return the results to the component.
Get started
You can initialize the proxy provider in HTML or JavaScript. You should do this only once
per page.
HTML
<mgt-proxy-provider graph-proxy-url="https://myurl.com/api/GraphProxy">
</mgt-proxy-provider>
Attribute Description
ts
Providers.globalProvider = new
ProxyProvider("https://myurl.com/api/GraphProxy");
Optionally, you can send additional headers with each request to your proxy api by
using an optional function as the second parameter in the constructor.
ts
Providers.globalProvider = new
ProxyProvider("https://myurl.com/api/GraphProxy", async () => {
return {
header: 'value',
header2: 'value2'
};
});
This is useful when you need to pass tokens or other headers to your backend.
If you will be using the mgt-login component, you should also specify the login and
logout functions for the provider:
ts
Providers.globalProvider = provider;
Custom provider
Article • 03/31/2022
If you have existing authentication code in your application, you can create a custom
provider to enable authentication and access to Microsoft Graph for Microsoft Graph
Toolkit components. There are two ways to create custom providers:
SimpleProvider
Instantiate the SimpleProvider class by passing in a function that will return an access
token for passed-in scopes.
ts
In addition, you can also provide an optional login and logout functions that can
handle the sign in and sign out calls from the Login component.
) Important
To indicate to the components that they can start calling the Microsoft Graph APIs
after a user successfully signs in, you need to call
Providers.setState(ProviderState.SignedIn) . An example of this is shown in the
login function below.
ts
function login() {
//login code
Providers.globalProvider.setState(ProviderState.SignedIn)
}
function logout() {
// logout code
}
Manage state
For the components to be aware of the state of the provider, you will need to call the
provider.setState(state: ProviderState) method whenever the state changes. For
ts
IProvider
You can extend the IProvider abstract class to create your own provider.
State
A provider must keep track of the authentication state and update the components
when the state changes. The IProvider class already implements the
onStateChanged(eventHandler) handler and the state: ProviderState property. You just
Login/Logout
If your provider provides login or logout functionality, implement the login():
Promise<void> and logout(): Promise<void> methods. These methods are optional.
Access token
You must implement the getAccessToken({'scopes': scopes[]}) : Promise<string>
method. This method is used to get a valid token before every call to Microsoft Graph.
Graph
The components use the Microsoft Graph Javascript SDK for all calls to Microsoft Graph.
Your provider must make the SDK available through the graph property. In your
constructor, create a new Graph instance, as shown.
JavaScript
The Graph class is a light wrapper on top of the Microsoft Graph SDK.
Example
All the providers extend the IProvider abstract class. For examples, take a look at the
source code for any of the existing providers .
ts
Providers.globalProvider = myProvider;
All the components will be notified of the new provider and start using it.
Login component in Microsoft Graph
Toolkit
Article • 12/28/2022
When user is not signed in, the control is a simple button to initiate the sign in
process.
When user is signed in, the control displays the current signed in user name,
profile image, and email. When clicked, a flyout is opened with a command to sign
out.
Example
The following example shows the mgt-login component with a signed-in user.
Sign In
html js css
1 <mgt-login></mgt-login>
2
user-details userDetails Set the user object that will be displayed on the control.
JavaScript
Use the loginInitiated and logoutInitiated events to handle signing in and out.
css
mgt-login {
--font-size: 14px;
--font-weight: 600;
--weith: '100%';
--height: '100%';
--margin: 0;
--padding: 12px 20px;
--button-color: #201f1e;
--button-color--hover: var(--theme-primary-color);
--button-background-color: transparent;
--button-background-color--hover: #edebe9;
--popup-background-color: white;
--popup-command-font-size: 12px;
--popup-color: #201f1e;
}
Events
The following events are fired from the control.
Templates
The mgt-login component supports several templates that allow you to replace certain
parts of the component. To specify a template, include a <template> element inside of a
component and set the data-type value to one of the values listed in the following
table.
signed-in- personDetails: person object, The template used to render the content in
button- personImage : person image string the button when the user is signed in.
content
flyout- handleSignOut: sign out function The template used to render the commands
commands in the flyout
Data type Data context Description
flyout- personDetails: person object, The template used to render the person
person- personImage: person image details in the flyout.
details string
Authentication
The login control uses the global authentication provider described in the
authentication documentation.
Cache
This component uses the Person component to display the user and inherits all cache
configuration from it.
Method Description
renderSignedInButtonContent Render the button content when the user is signed in.
renderSignedOutButtonContent Render the button content when the user is not signed in.
Method Description
In this case, ensure the login component continues to work as expected by overriding
the protected flyout display methods to update the visibility of your alternative flyout.
Method Description
You can use mgt-get to make any GET query from Microsoft Graph directly in your
HTML. The component does not provide a default UI and requires that you write a
template.
Example
The following example shows the use of the mgt-get component to display a user's
emails. You can use the code editor to see how properties and attributes change the
behavior of the component.
html js css
resource resource The resource to get from Microsoft Graph (for example,
/me ).
version version Optional API version to use when making the GET
request. Default is v1.0 .
N/A error Read-only error from Microsoft Graph if request was not
successful.
Methods
Method Description
refresh(force?:boolean) Call the method to refresh the data. By default, the UI will only update if
the data changes. Pass true to force the component to update.
Events
Event When is it Custom data Cancelable Bubbles Works
emitted with
custom
template
Tip
For more information about the data returned in the response property see the API
reference of the API that you used in the resource property of the Get component.
Templates
The mgt-get component supports several templates that you can use to define the look
and feel. To specify a template, include a <template> element inside a component and
set the data-type value to one of the following.
default The The default template is required to render the data coming from Microsoft
response Graph.
from
Microsoft
Graph.
Data Data Description
type context
value Data Use the value template instead of the default template when expecting
item the response from the graph to contain an array of items - such as
from the messages, files, or users. The value template will automatically be
returned repeated for each item returned by the resource. The value template will
value also start rendering the items as soon as they are ready (unlike the default
array template).
error The error This template will be used if there is an error making the request.
from
Microsoft
Graph.
loading N/A This template is used while the request is being made.
no- N/A This template is used when the request returned no data.
data
Authentication
The control uses the global authentication provider described in the authentication
documentation to fetch the required data.
Cache
To enable and configure the cache, use the cacheEnabled and cacheInvalidationPeriod
properties. By default, the mgt-get component does not cache any responses.
response Complete response retrieved from Microsoft Graph for the query specified
in the resource property of mgt-get
The person component is used to display a person or contact by using their photo,
name, email address, or any other person details.
The person component also uses the mgt-person-card to display a flyout card with
additional information about the user. For details, see the Person Card section.
Example
The following example displays a person using the mgt-person component. You can use
the code editor to see how properties change the behavior of the component.
html js css
Set the user-id attribute or userId property to fetch the user from Microsoft
Graph by using their ID.
JavaScript
By default, the person component will only request the standard Microsoft Graph
user set of properties. In order to request additional properties, declare them as
any part of the line(x)Property .
Properties
You can use several properties to customize the component.
user-id userId Set to a user ID to fetch that user's details and image from
Microsoft Graph.
person- personDetails Set to an object representing a person. Works with object from
details the people, users, contacts, or group, resources.
disable- disableImageFetch Set flag to disable fetching of person image. Can be used to
image- avoid unnecessary fetching from Microsoft Graph when
fetch specifying personImage property.
avatar- avatarType Set to initials or photo to render either display state - default
type is photo.
avatar- avatarSize Set to small , large , or auto to determine the size of avatar.
size This helps to set the correct size for the presence badge. Default
is auto.
view view Set to control how the person is rendered. Default is avatar
avatar - show only avatar
oneline - show avatar and first line ( displayName by default)
twolines - show avatar and two lines of text ( displayName and
mail by default)
threelines - show avatar and three lines of text ( displayName ,
mail and jobTitle by default)
line1- line1Property Sets the property of the personDetails to use for the first line of
property text. Default is displayName .
line2- line2Property Sets the property of the personDetails to use for the second line
property of text. Default is mail .
line3- line3Property Sets the property of the personDetails to use for the third line of
property text. Default is jobTitle .
usage usage Specify where the component is being used in order to add
customized personalization for it. Currently only supports
people as used in the people component.
mgt-person {
--avatar-size: 48px;
--avatar-border: 0;
--avatar-border-radius: 50%;
--avatar-cursor: default;
--initials-color: white;
--initials-background-color: magenta;
--presence-background-color: #ffffff;
--presence-icon-color: #ffffff;
--line2-font-size: 12px;
--line2-font-weight: 400;
--line2-color: black;
--line2-text-transform: none;
--line3-font-size: 12px;
--line3-font-weight: 400;
--line3-color: black;
--line3-text-transform: none;
--details-spacing: 12px;
}
Events
The following events are fired from the component.
Templates
The mgt-person component supports several templates that allow you to replace certain
parts of the component. To specify a template, include a <template> element inside a
component and set the data-type value to one of the following:
default person: The person details object The default template replaces the entire
personImage : The URL of the image component with your own.
personPresence : The presence
details object for person
person- person: The person details object The template to update the mgt-person-card
card personImage : The URL of the image displayed on hover or click.
line1 person: The person details object The template for the first line of person
metadata.
line2 person: The person details object The template for the second line of person
metadata.
line3 person: The person details object The template for the third line of person
metadata.
HTML
Person card
The mgt-person component can show an mgt-person-card on either hover or click.
For more information about templating, styling, and attributes, see Person Card
component.
ts
MgtPerson.config.useContactApis = false;
Property Description
useContactApis boolean - Indicates whether the person component can use Microsoft Graph
personal contacts API to search for contact details and photos. Default value is
true .
Microsoft Graph permissions
This control uses the following Microsoft Graph APIs and permissions.
personCardInteraction set to a value other than See person card See person card API
PersonCardInteraction.none permissions calls
Authentication
The control uses the global authentication provider described in the authentication
documentation to fetch the required data.
Cache
Object Cached data Remarks
store
photos Person's photo Used, when avatarType is set to photo and fetchImage is
set to true
Method Description
You can use the mgt-people web component to display a group of people or contacts by
using their photos or initials. By default, it will display the most frequent contacts for the
signed in user.
This component uses multiple mgt-person controls, but it can be bound to a set of
people descriptors. If there are more people to display than the show-max value, a
number will be added to indicate the number of additional contacts.
Example
The following example shows a group of people displayed using the mgt-people
component. You can use the code editor to see how properties change the behavior of
the component.
html js css
1 <mgt-people show-max="5"></mgt-people>
2
Properties
By default, the mgt-people component fetches events from the /me/people endpoint
with the personType/class eq 'Person' filter to display frequently contacted users. You
can use several properties to change this behavior.
Attribute Property Description
show- showMax Indicates the maximum number of people to show. Default value is
max 3.
people people An array of people to get or set the list of people rendered by the
component. Use this property to access the people loaded by the
component. Set this value to load your own people.
group-id groupId Retrieves people from a specific Microsoft Graph from the
respective ID.
user-ids userIds Given an array of Microsoft Graph user ids , the component will
render these users.
people- peopleQueries Given an array of person queries (names, upns, emails), the
queries component will render these users.
resource resource The resource to get from Microsoft Graph (for example,
/me/people ).
scopes scopes Optional array of strings if using the property or a comma delimited
scope if using the attribute. The component will use these scopes
(with a supported provider) to ensure that the user has consented
to the right permission.
version version Optional API version to use when making the GET request. Default is
v1.0 .
HTML
<mgt-people
show-max="4">
</mgt-people>
css
mgt-people {
--list-margin: 8px 4px 8px 8px; /* Margin for component */
--avatar-margin: 0 4px 0 0; /* Margin for each person */
--color: #000000 /* Text color */
}
Templates
The mgt-people supports several templates that you can use to replace certain parts of
the component. To specify a template, include a <template> element inside a
component and set the data-type value to one of the following.
default people : list of The default template replaces the entire component with your
person objects own.
overflow people : list of The template used to render the number beyond the max to
person objects the right of the list of people.
max : number of
shown people
extra : number of
extra people
loading No data context is The template used while the component loads state.
passed
HTML
<mgt-people>
<template>
<ul><li data-for="person in people">
<mgt-person person-query="{{ person.userPrincipalName }}"></mgt-
person>
<h3>{{ person.displayName }}</h3>
<p>{{ person.jobTitle }}</p>
<p>{{ person.department }}</p>
</li></ul>
</template>
</mgt-people>
When using the default templates, additional APIs and permissions are required. The
default template for this component uses a mgt-person component. See its
documentation for the list of required permissions.
Authentication
The control uses the global authentication provider described in the authentication
documentation.
Cache
Object Cached data Remarks
store
presence Presence for the specified set of Used when showPresence set to true
people
7 Note
Method Description
Example
The following example shows the use of the mgt-person-card component with a mgt-
person component. Hover over the person to see the Person Card and use the code
editor to see how properties change the behavior of the component.
html js css
1 <mgt-person-card person-query="me"></mgt-person-card>
2
ts
MgtPersonCard.config.useContactApis = false;
MgtPersonCard.config.sections.profile = false;
Property Description
useContactApis boolean - Indicates whether the person card component can use Microsoft
Graph Contact API to search for contact details and photos. Default value is
true .
sections object - Configures what sections are shown in the person card.
Contact - Contact information such as email, phone, position, location, and more.
Organization - Organizational graph with managers, direct reports, and relevant
people.
Messages - Most relevant email messages with the current signed in user.
Files - Most relevant shared files with the current signed in user.
Profile - Profile information such as projects, skills, languages, and more.
Sections are loaded by default, but they can be disabled globally via the
MgtPersonCard.config.sections object property. The following properties are available.
Property Description
organization boolean - Indicates whether the person card organization section is shown.
Default value is true .
mailMessages boolean - Indicates whether the person card messages section is shown. Default
value is true .
files boolean - Indicates whether the person card files section is shown. Default value
is true .
Property Description
profile boolean - Indicates whether the person card profile section is shown. Default
value is true .
lock-tab- boolean - Allows the locking of navigation using tabs so that it does not flow out
navigation of the card section. Default value is false .
To disable a section, simply set the property to false in your app initialization code:
ts
MgtPersonCard.config.sections.profile = false;
If the Person-Card component is unable to detect the Teams lib, the component will
attempt to open the Teams web client instead.
ts
TeamsHelper.microsoftTeamsLib = microsoftTeams;
For more information about the TeamsProvider provider, see Microsoft Teams provider.
Properties
By default, the mgt-person component will pass the person details to the mgt-person-
card component. However, you can use these attributes to change this when templating
person- string Image uri related to the person displayed in the card.
image
Templates
The Person-Card component uses templates that allow you to add or replace portions of
the component. To specify a template, include a <template> element inside of a
component and set the data-type value to one of the following.
default person : The person The default template replaces the entire component
details object with your own.
personImage : The URL of
the image
person- person : The person The template used to render the top part of the person
details details object card.
additional- person : The person The template used to add custom content to the
details details object additional details container.
personImage : the URL of
the image
For example, you can use a template to customize the component attached to the mgt-
person component and a template to add additional details in the card.
HTML
Events
The following events are fired from the component.
expanded The user has opened the None No Yes Yes, unless
expanded details section of the you override
card the default
template
css
mgt-person {
--person-card-display-name-font-size: 40px;
--person-card-display-name-color: #ffffff;
--person-card-title-font-size: 20px;
--person-card-title-color: #ffffff;
--person-card-subtitle-font-size: 10px;
--person-card-subtitle-color: #ffffff;
--person-card-details-title-font-size: 10px;
--person-card-details-title-color: #b3bf0a;
--person-card-details-item-font-size: 20px;
--person-card-details-item-color: #3abf0a;
--person-card-background-color: #000000;
--person-card-contact-link-color: #ff0000;
--person-card-contact-link-hover-color: #00ff00;
--person-card-show-more-color: #ff0000;
--person-card-show-more-hover-color: #00ff00;
--person-card-base-links-color: #ff0000;
--person-card-base-links-hover-color: #00ff00;
--person-card-tab-nav-color: #ff0000;
--person-card-active-org-member-color: #ff0000;
--person-card-nav-back-arrow-hover-color: #00ff00;
--person-card-nav-back-arrow-color: #ff0000;
}
The MgtPersonCard class also exposes a getScopes static method that returns an array of
scopes required for the person card to function based on the global person card
configuration.
ts
Authentication
The Person-Card control uses the global authentication provider described in the
authentication documentation.
Cache
) Important
The mgt-person-card component retrieves the basic person data from the parent
mgt-person component without calling Microsoft Graph. When mgt-person-card is
used separately, it will retrieve the necessary data itself and cache it. The data
displayed in card's sections is retrieved separately and is not cached.
people Person's information Used when personQuery is specified and its value is
different than me
users Person's user Used when userId is specified or the personQuery is set to
information me
You can use the mgt-people-picker web component to search for people and/or groups.
By default, the component will search for all people and users in the organization, but
you can change the behavior to also search for groups, or only groups. You can also
filter the search to a specific group. Additionally, you can allow the user to enter and
select any email address.
Example
The following example shows the mgt-people-picker component. Start searching for a
name to see the results render and use the code editor to see how properties change
the behavior of the component.
html js css
1 <mgt-people-picker></mgt-people-picker>
2
Properties
By default, the mgt-people-picker component fetches people from the /me/people and
/users endpoints. Use the following attributes to change this behavior.
type type The type of entities to search for. Available options are:
person , group , any . Default value is person . This
attribute has no effect if group-id property is set.
user-type userType The type of user to search for. Available options are:
any , user for organizational users, or contact for
contacts. Default value is any .
group-type groupType The group type to search for. Available options are:
unified , security , mailenabledsecurity , distribution ,
any . Default value is any . This attribute has no effect if
the type property is set to person .
placeholder placeholder The default text that appears to explain how to use the
component. Default value is Start typing a name .
allow-any- allowAnyEmail Indicates whether the people picker can accept email
email addresses without selecting a person. Default value is
false . When you finish typing an email address, you
can press comma ( , ), semicolon ( ; ), tab or enter keys
to add it.
user-filters userFilters Specifies the filter criteria to use when querying the
users endpoint. It requires the user-type to be set to
user or contact . By default, the user-type is any and
this leads the querying to take place in the people
endpoint block. Example: user-
filters="startsWith(displayName,'a')" . This attribute is
optional. Learn more about the support for filter on user
properties of Azure AD directory objects.
group- groupFilters Specifies the filter criteria to use when querying the
filters groups endpoint. It requires the type to be set to
group . Example: group-
filters="startsWith(displayName,'a')" . This attribute is
optional.
people- peopleFilters Specifies the filter criteria to use when querying the
filters people endpoint. It is used as it is. Example: people-
filters="jobTitle eq 'Web Marketing Manager'" . This
attribute is optional. Learn more about filtering and the
supported capabilities on the people resource.
Attribute Property Description
HTML
Selected people
The selected people section of the component renders each person chosen by the
developer or user.
You can populate selected people data by doing one of the following:
JavaScript
JavaScript
JavaScript
Events
The following events are fired from the component.
css
mgt-people-picker {
--input-border: 2px rgba(255, 255, 255, 0.5) solid; /* sets all input
area border */
Templates
mgt-people-picker supports several templates that you can use to replace certain parts
default null: no data The template used to override the rendering of the entire
component.
Data type Data context Description
loading null: no data The template used to render the state of picker while
request to graph is being made.
error null: no data The template used if user search returns no users.
no-data null: no data An alternative template used if user search returns no users.
person person: The person The template to render people in the dropdown.
details object
HTML
<mgt-people-picker>
<template data-type="error">
<p>Sorry, no people were found</p>
</template>
</mgt-people-picker>
Authentication
The control uses the global authentication provider described in the authentication
documentation.
Cache
Object store Cached data Remarks
Method Description
renderNoData Renders the state when no results are found for the search query.
Example
The following example shows the mgt-teams-channel-picker component. Start searching
for a channel or team to see the results render.
Select a channel
html js css
1 <mgt-teams-channel-picker></mgt-teams-channel-picker>
2
Selecting a channel
Use the selectChannelById(channelId: string) method to programmatically select a
channel.
Note: the Teams channel picker only supports single channel selection.
JavaScript
Note: The provided channel (and subsequent ID) must belong to a team that the
authenticated user has joined.
css
mgt-teams-channel-picker {
--input-border: 2px rgba(255, 255, 255, 0.5) solid; /* sets all input
area border */
Events
Event When is it Custom data Cancelable Bubbles Works
emitted with
custom
template
Templates
mgt-teams-channel-picker supports several templates that you can use to replace
loading null: no The template used to render the state of the picker while the request to
data Microsoft Graph is being made.
HTML
<mgt-teams-channel-picker>
<template data-type="error">
<p>Sorry, no Teams or Channels were found</p>
</template>
</mgt-teams-channel-picker>
API Permission
/me/joinedTeams User.Read.All
/teams/${id}/channels Group.Read.All
In version 2.2, the required permissions have been updated to the less restrictive Teams-
based permissions. To avoid a breaking change, you need to opt in to the new
permissions via a global config.
ts
MgtTeamsChannelPicker.config.useTeamsBasedScopes = true;
With useTeamsBasedScopes set to true , the Teams Channel Picker will use the following
scopes.
API Permission
/me/joinedTeams Team.ReadBasic.All
/teams/${id}/channels Channel.ReadBasic.All
Authentication
The control uses the global authentication provider described in the authentication
documentation.
Cache
The mgt-teams-channel-picker component doesn't cache any data.
Method Description
renderSelected Renders the selected team and channel in the input box.
Example
The following example shows the signed-in user's calendar events displayed using the
mgt-agenda component. You can use the code editor to see how properties change the
behavior of the component.
html js css
1 <mgt-agenda></mgt-agenda>
2
Properties
By default, the mgt-agenda component fetches events from the /me/calendarview
endpoint and displays events for the current day. There are several properties you can
use to change this behavior.
date date A string that represents the start date of the events to fetch
from Microsoft Graph. Value should be in a format that can be
parsed by the Date constructor - value has no effect if event-
query attribute is set.
group-id groupId A string ID for a group calendar to use instead of the current
signed in user's calendar.
events events An array of events to get or set the list of events rendered by
the component - use this property to access the events loaded
by the component. Set this value to load your own events - if
value is set by developer, the date , days , or event-query
attributes have no effect.
group-by- groupByDay A Boolean value to group events by day - by default events are
day not grouped.
preferred- preferredTimezone Name of the preferred time zone to use when retrieving events
timezone from Microsoft Graph; for example, Pacific Standard Time . By
default, this attribute uses the UTC time zone. The preferred
time zone for the current user can be retrieved by calling the
me/mailboxSettings endpoint and reading the value of the
timeZone property.
The following example changes the behavior of the component to fetch data for a
specific date and up to three days.
HTML
<mgt-agenda
group-by-day
date="May 7, 2019"
days="3"
></mgt-agenda>
The following example changes the behavior of the component to fetch data from a
specific query.
HTML
<mgt-agenda
event-query="/me/events?orderby=start/dateTime"
></mgt-agenda>
Methods
Method Description
reload() Call the method to reload the component with potential new data based on its
properties.
css
mgt-agenda {
--event-box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.092);
--event-margin: 0px 10px 14px 10px;
--event-padding: 8px 0px;
--event-background-color: #ffffff;
--event-border: solid 2px rgba(0, 0, 0, 0);
--event-time-font-size: 12px;
--event-time-color: #000000;
--event-subject-font-size: 19px;
--event-subject-color: #333333;
--event-location-font-size: 12px;
--event-location-color: #000000;
}
To learn more, see styling components.
Templates
The mgt-agenda component supports several templates that allow you to replace certain
parts of the component. To specify a template, include a <template> element inside of a
component and set the data-type value to one of the following:
default events : list of event The default template replaces the entire component with
objects your own.
event event : event object The template used to render each event.
event- event : event object The template used to render additional content for each
other event.
header header : string The template used to render the header for each day.
no-data No data context is The template used when no events are available.
passed
HTML
<mgt-agenda>
<template data-type="event">
<button class="eventButton">
<div class="event-subject">{{ event.subject }}</div>
<div data-for="attendee in event.attendees">
<mgt-person
person-query="{{ attendee.emailAddress.name }}"
view="twolines">
</mgt-person>
</div>
</button>
</template>
<template data-type="no-data">
There are no events found!
</template>
</mgt-agenda>
The component allows you to specify a different Microsoft Graph query to call (such as
/groups/{id}/calendar/calendarView ). In this case, append the permission to the end of
When using the default template and default renderAttendees template, additional APIs
and permissions are required. The default template for this component uses a mgt-
people component for events that have attendees, and inherits all permissions.
Authentication
The login control uses the global authentication provider described in the
authentication documentation.
Cache
The mgt-agenda component doesn't cache any data.
renderGroups Sorts event data into groups and renders them with group headers.
The Tasks component enables the user to view, add, remove, complete, or edit tasks
from Microsoft Planner.
In addition, a user is able to assign a single or multiple Microsoft Graph users to a task.
For more details about Microsoft Graph assignments, see plannerAssignments.
Example
The following example displays the signed-in user's Microsoft Planner tasks using the
mgt-tasks component. You can use the code editor to see how properties change the
html js css
1 <mgt-tasks></mgt-tasks>
2
Properties
Attribute Property Description
The following example shows only tasks from Planner with ID 12345 and does not allow
the user to create new tasks.
HTML
The following example shows how to filter tasks that only have category3 set.
JavaScript
mgt-tasks {
--tasks-header-padding
--tasks-header-margin
--tasks-title-padding
--tasks-plan-title-font-size
--tasks-plan-title-padding
--tasks-new-button-width
--tasks-new-button-height
--tasks-new-button-color
--tasks-new-button-background
--tasks-new-button-border
--tasks-new-button-hover-background
--tasks-new-button-active-background
--tasks-new-task-name-margin
--task-margin
--task-box-shadow
--task-background
--task-border
--task-header-color
--task-header-margin
--task-detail-icon-margin
--task-new-margin
--task-new-border
--task-new-line-margin
--tasks-new-line-border
--task-new-input-margin
--task-new-input-padding
--task-new-input-font-size
--task-new-input-active-border
--task-new-select-border
--task-new-add-button-background
--task-new-add-button-disabled-background
--task-new-cancel-button-color
--task-complete-background
--task-complete-border
--task-complete-header-color
--task-complete-detail-color
--task-complete-detail-icon-color
--task-icon-background-completed
--task-icon-background
--task-icon-border-completed
--task-icon-border
--task-icon-color
--task-icon-color-completed
--task-icon-border-radius
Events
Event When is it emitted Custom data Cancelable Bubbles Works
with
custom
template
Templates
The tasks component supports several templates that allow you to replace certain parts
of the component. To specify a template, include a <template> element inside a
component and set the data-type value to one of the following:
task task: a planner task object replaces the whole default task.
task-details task: a planner task object template replaces the details section of the task.
HTML
<mgt-tasks>
<template data-type="task-details">
<div>
Owner: {{task.owner}}
</div>
<div>
Importance Level: {{task.importance}}
</div>
</template>
</mgt-tasks>
For the Microsoft Planner data source, fetching and reading tasks requires the
Groups.Read.All permission. Adding, updating, or removing tasks requires the
Groups.ReadWrite.All permission.
Authentication
The tasks component uses the global authentication provider described in the
authentication documentation.
Cache
The mgt-tasks component doesn't cache any data.
To Do component in Microsoft Graph
Toolkit
Article • 12/28/2022
The To Do component is used to enable the signed-in user to view, add, remove,
complete, and/or edit tasks from Microsoft To Do using the To Do API in Microsoft
Graph.
Example
The following example displays the signed-in user's Microsoft To Do tasks using the
mgt-todo component. You can use the code editor to see how properties change the
behavior of the component.
html js css
1 <mgt-todo></mgt-todo>
2
Properties
You can use the following attributes and properties to customize the component.
Attribute Property Description
read-only readOnly A Boolean to set the task interface to be read only (no adding
or removing tasks). Default is false .
initial- initialId A string ID to set the initially displayed folder to the provided
id="folder_id" ID.
target- targetId A string ID to lock the tasks interface to the provided folder
id="folder_id" ID.
N/A taskFilter An optional function to filter which tasks are shown to the
user.
The following example shows only tasks from the folder with ID 12345 and does not
allow the user to create new tasks.
HTML
css
mgt-todo {
--tasks-background-color
--tasks-header-padding
--tasks-title-padding
--tasks-plan-title-font-size
--tasks-plan-title-padding
--tasks-new-button-width
--tasks-new-button-height
--tasks-new-button-color
--tasks-new-button-background
--tasks-new-button-border
--tasks-new-button-hover-background
--tasks-new-button-active-background
--task-margin
--task-background
--task-border
--task-header-color
--task-header-margin
--task-new-margin
--task-new-border
--task-new-input-margin
--task-new-input-padding
--task-new-input-font-size
--task-new-select-border
--task-new-add-button-background
--task-new-add-button-disabled-background
--task-new-cancel-button-color
--task-complete-background
--task-complete-border
Events
The following events are fired from the component.
Templates
The tasks component supports several templates that allow you to replace certain parts
of the component. To specify a template, include a <template> element inside a
component and set the data-type value to one of the following.
task task: a to-do task object Replaces the whole default task.
task-details task: a to-do task object Template replaces the details section of the task.
HTML
<mgt-todo>
<template data-type="task-details">
<div>
Importance Level: {{task.importance}}
</div>
</template>
</mgt-todo>
Authentication
The tasks component uses the global authentication provider described in the
authentication documentation.
Cache
The mgt-todo component doesn't cache any data.
File component in Microsoft Graph
Toolkit
Article • 12/28/2022
Example
The following example displays a file using the mgt-file component. You can use the
code editor to see how properties change the behavior of the component.
html js css
1 <mgt-file file-query="/me/drive/items/01BYE5RZZFWGWWVNHHKVHYXE3OUJ
2
Properties
You can use several properties to customize the component.
drive-id driveId The ID of the drive the file belongs to. Must also provide either item-
id or item-path .
Attribute Property Description
group-id groupId ID of the group the file belongs to. Must also provide either item-id
or item-path .
site-id siteId ID of the site the file belongs to. Must also provide either {item-id}
or {item-path} . Provide the {list-id} too if you’re referencing a file
from a specific list.
list-id listId ID of the list the file belongs to. Must also provide {site-id} and
{item-id} .
item- itemPath Item path of the file. Default query is /me/drive/root . Provide
path {drive-id} , {group-id} , {site-id} , or {user-id} to query a specific
location.
insight- insightType Type of insight the file is retrieved from. Can be trending , used , or
type shared .
view view Set to control how the file is rendered. The default is oneline .
image - show only the icon
oneline - show the icon and one line of text (default is file name )
twolines - show the icon and two lines of text ( name and
lastModifiedDateTime by default)
threelines - show the icon and three lines of text ( name ,
lastModifiedDateTime , and displayName of the author by default)
line1- line1Property Sets the property of fileDetails to use for the first line of text.
property Default is name of the file.
line2- line2Property Sets the property of fileDetails to use for the second line of text.
property Default is lastModifiedDateTime .
line3- line3Property Sets the property of fileDetails to use for the third line of text.
property Default is size of the file.
The following example changes the behavior of the component to fetch data from a
specific query.
HTML
<mgt-file file-query="/me/drive/items/01BYE5RZZFWGWWVNHHKVHYXE3OUJHGWCT2">
</mgt-file>
The following example changes the behavior of the component to fetch data from a
specific query, show three lines of information - file name, last modified date time, and
file size by default - and set the file icon.
HTML
<mgt-file file-query="/me/drive/items/01BYE5RZZFWGWWVNHHKVHYXE3OUJHGWCT2"
view="threeLines" file-icon="ICON_PATH"></mgt-file>
The following example changes the behavior of the component to fetch data from a
specific drive.
HTML
<mgt-file drive-id="b!-RIj2DuyvEyV1T4NlOaMHk8XkS_I8MdFlUCq1BlcjgmhRfAj3-
Z8RY2VpuvV_tpd" item-id="01BYE5RZ5MYLM2SMX75ZBIPQZIHT6OAYPB"></mgt-file>
The following example changes the behabior of the component to fetch data from a
SharePoint site and path.
HTML
<mgt-file site-id="m365x214355.sharepoint.com,5a58bb09-1fba-41c1-8125-
69da264370a0,9f2ec1da-0be4-4a74-9254-973f0add78fd" item-
Path="/DemoDocs/AdminDemo"></mgt-file>
The following example changes the behavior of the component to fetch data by insight
type.
HTML
css
mgt-file {
--file-type-icon-size: 28px;
--file-border: none;
--file-box-shadow: none;
--file-background-color: #ffffff;
--line2-font-size: 12px;
--line2-font-weight: 400;
--line2-color: #797775;
--line2-text-transform: none;
--line3-font-size: 12px;
--line3-font-weight: 400;
--line3-color: #797775;
--line3-text-transform: none;
}
Templates
The mgt-file component supports several templates that allow you to replace certain
parts of the component. To specify a template, include a <template> element inside of a
component and set the data-type value to one of the following:
default file: the file details The default template replaces the entire component with
object your own.
Authentication
The control uses the global authentication provider described in the authentication
documentation to fetch the required data.
Cache
Object store Cached data Remarks
insightFiles List of files by insights Used when insightType and insightId are provided
The File List component displays a list of multiple folders and files by using the
file/folder name, an icon, and other properties that you specify. This component uses
the mgt-file component. You can specify a specific drive or site, display a list of files
based on insight type (trending, used, or shared), or provide queries to a custom list of
files. The component also provides the option to allow users to upload files to a
specified location in One Drive or SharePoint.
Example
The following example displays a file using the mgt-file-list component. You can use
the code editor to see how properties change the behavior of the component.
html js css
1 <mgt-file-list></mgt-file-list>
2
Properties
You can use several properties to customize the component.
file-list- fileListQuery The full query or path to the drive or site that contains the
query list of files to render.
none files An array of files to get or set the list of files rendered by
the component. Use this to access the files loaded by the
component. Set this value to load your own files.
insight- insightType Set to show the user’s trending, used, or shared files.
type
drive-id driveId ID of the drive the folder belongs to. Must also provide
either item-id or item-path .
group-id groupId ID of the group the folder belongs to. Must also provide
either item-id or item-path .
site-id siteId ID of the site the folder belongs to. Must also provide
either {item-id} or {item-path} . Provide {list-id} if
you’re referencing a file from a specific list.
item-path itemPath Item path of the folder (relative to the root). Default query
is /me/drive/root . Provide {drive-id} , {group-id} , {site-
id} , or {user-id} to query a specific location.
max-file- maxFileSize A number representing the maximum file upload size (KB).
size Must also set the enable-file-upload attribute to true .
Attribute Property Description
The following example changes the behavior of the component to fetch a file list from a
specific query.
HTML
<mgt-file-list file-list-
query="/me/drive/items/01BYE5RZYJ43UXGBP23BBIFPISHHMCDTOY/children"></mgt-
file-list>
The following example changes the behavior of the component to fetch a file list from a
folder by providing the folder id.
HTML
<mgt-file-list item-id="01BYE5RZYJ43UXGBP23BBIFPISHHMCDTOY"></mgt-file-list>
The following example changes the behavior of the component to fetch file list from a
group by providing the group id and folder path.
HTML
The following example changes the behavior of the component to fetch file list from a
user by providing the user id and folder id.
HTML
The following example changes the behavior of the component to fetch file list by
providing the insight type.
HTML
<mgt-file-list insight-type="shared"></mgt-file-list>
The following example enables the file upload feature.
HTML
<mgt-file-list enable-file-upload></mgt-file-list>
The following example limits the maximum number of files that can be uploaded to 5.
HTML
The following example limits the maximum file size that can be uploaded to 10000 KB.
HTML
The following example excludes upload of files with file extensions ".doc,.pdf".
HTML
Methods
Method Description
reload(clearCache Call the method to reload the component with potential new data based on
= false) its properties. Pass true to clear the cache before reloading.
css
mgt-file-list {
--font-family: 'Segoe UI';
--font-size: 14px;
--file-list-background-color: #ffffff;
--file-list-border: none;
--file-list-box-shadow: none;
--file-list-padding: 4px 0;
--file-list-margin: 0;
--file-item-border-top: none;
--file-item-border-left: none;
--file-item-border-right: none;
--file-item-border-bottom: none;
--show-more-button-background-color: #f3f2f1;
--show-more-button-background-color--hover: rgba(0, 0, 0, 0.1);
--show-more-button-font-size: 12px;
--show-more-button-padding: 6px;
--show-more-button-border-bottom-right-radius: 4px;
--show-more-button-border-bottom-left-radius: 4px;
Events
Event When is it emitted Custom Cancelable Bubbles Works with
data custom template
Event When is it emitted Custom Cancelable Bubbles Works with
data custom template
Templates
The mgt-file-list component supports several templates that allow you to replace
certain parts of the component. To specify a template, include a <template> element
inside of a component and set the data-type value to one of the data types listed in the
following table.
default files : list of file The default template replaces the entire component with
objects your own.
file file : file object The template used to render each file.
loading No data context is The template used while the component loads state.
passed
Authentication
The control uses the global authentication provider described in the authentication
documentation to fetch the required data.
Cache
Object store Cached data Remarks
fileLists List of file lists Default cache list to store file lists.
7 Note
The mgt-file-list component also uses the fileQueries object store in mgt-file
IndexedDB to cache files when fileQueries is provided.
Each Microsoft Graph Toolkit component documents a set of CSS custom properties
that you can use to change the look and feel of certain elements. You can find the
available custom CSS properties in each component docs. For example:
css
mgt-person {
--avatar-size: 34px;
}
You can't style internal elements of a component unless you provide a CSS custom
property. The component child elements are hosted in a shadow dom .
Apply themes
Two themes are available - light and dark. By default, all components are styled with
light theme. To switch to dark theme, you can simply apply class="mgt-dark" to the
section of your HTML page. The components inside that section will have dark theme
applied. The following examples show how themes will apply based on how you
structure your HTML.
HTML
<body class="mgt-light">
<!-- light theme will apply to all components in this section -->
<header><mgt-login></mgt-login></header>
<article><mgt-agenda></mgt-agend></article>
<footer></footer>
</body>
HTML
<mgt-person-card class="mgt-dark"></mgt-person-card>
HTML
<div class="mgt-light">
<header class="mgt-dark">
// login component will have dark theme
<mgt-login></mgt-login>
</header>
<article>
// agenda component will have light theme
<mgt-agenda></mgt-agenda>
</article>
</div>
HTML
css
mgt-people-picker.custom-class {
--input-background-color: $custom-background-color;
--input-border: $custom-input-border;
}
Templates in the Microsoft Graph
Toolkit
Article • 03/31/2022
Most Microsoft Graph Toolkit components support the use of custom templates to
modify the content of a component.
All web components support templates based on the <template> element. For example,
to override the template of a component, add a <template> element inside a
component.
HTML
<mgt-agenda>
<template data-type="event">
<div>{{event.subject}}</div>
<div data-for='attendee in event.attendees'>
<mgt-person person-query="{{attendee.emailAddress.name}}">
<template>
<div data-if="person.image">
<img src="{{person.image}}" />
</div>
<div data-else>
{{person.displayName}}
</div>
</template>
</mgt-person>
</div>
</template>
</mgt-agenda>
If you're using the Microsoft Graph Toolkit React components, you can use React for
authoring templates. For details, see Use the toolkit with React.
Data-type
Each component can have multiple parts that can be templated. For example, in the
mgt-agenda component, you can template individual events, individual section headers,
loading view, no data view, and more. To indicate the template, use the data-type
attribute on a template. For example, to template each event in the mgt-agenda , use the
event data-type, as shown.
HTML
<mgt-agenda>
<template data-type="event"> </template>
</mgt-agenda>
If no data-type is specified, the entire component will be replaced with the template.
You can also use data-type="default" for the same purpose.
Binding data
Many templates allow binding of data that is passed to the template as data context. For
example, the event template in the mgt-agenda component passes an {event} object
that can be used directly in the template. To expand an expression, such as
event.subject , use the double curly brackets.
HTML
<template data-type="event">
<div>{{event.subject}}</div>
</template>
HTML
<template data-type="event">
<a href="{{ event.onlineMeetingUrl }}" />
</template>
Note: You can also expand objects such as {{event}} or {{this}} and they will
render as JSON strings. This can be useful when you're developing the templates.
ts
TemplateHelper.setBindingSyntax('[[', ']]');
Data context helper properties
The following properties can also be used with the data context object in your
templates.
Property Description
$index Numerical index of item being rendered while being looped with data-for .
$parent If a template is rendered inside another template, this property allows you to access
the parent data context.
The following example shows how to use the $index property in a data-for loop.
HTML
<mgt-person>
<mgt-person-card>
<template data-type="additional-details">
<span data-for="language in languages">
{{ language.displayName }}<span data-if="$index < languages.length -
1">, </span>
</span>
</template>
</mgt-person-card>
</mgt-person>
{{this}}
To help debug the data context, you can use this in your binding expressions. The
simplest form is to add {{this}} anywhere in your template.
HTML
<template data-type="event">
<div>
{{this}}
</div>
</template>
Because you can use JavaScript in your binding expressions, you also have access to the
console object which allows you to use console.log(this) (or any other console API)
in your templates.
HTML
<template data-type="event">
<div>
{{console.log(this)}}
</div>
</template>
Conditional rendering
You might only want to render elements when a condition is true or false based on the
data context. The data-if and data-else attributes can evaluate an expression and
render only if true or false.
HTML
Looping
There will be cases where the data context object contains loop and you will need to
loop over the data. For this scenario, use the data-for attribute.
HTML
<template data-type="event">
<ul>
<li data-for='attendee in event.attendees'>
{{ attendee.displayName }}
</li>
</ul>
</template>
Template context
In scenarios where you need to convert data in your bindings, bind to events, or just use
external data in your templates bindings, the templates support binding to external data
context. You can add additional template context in two ways:
Each component defines the templateContext property, which you can use to pass
additional data to any template in the component.
ts
document.querySelector('mgt-agenda').templateContext = {
someObject: {},
formatDate: (date: Date) => { /* format date and return */ },
someEventHandler: (e) => { /* handleEvent */ }
ts
TemplateHelper.globalContext.someObject = {};
TemplateHelper.globalContext.formatDate = (date: Date) => { /* format
date and return */ };
TemplateHelper.globalContext.someEventHandler = (e) => { /* handleEvent
*/ }
Converters
In many cases, you might want to transform the data before presenting it in the
template. For example, you might want to properly format a date before it is rendered.
In these cases, you might want to use a template converter.
To use a template converter, you first need to define a function that will do the
conversion. For example, you might define a function to convert an event object to a
formatted time range.
ts
document.querySelector('mgt-agenda').templateContext = {
return timeRange;
}
To use the converter in your template, use it as if you would use a function in code
behind.
HTML
<template data-type="event">
<div>{{ getTimeRange(event) }}</div>
</template>
HTML
<template>
<button data-props="{{@click: myEvent, myProp: value}}"></button>
</template>
The data-props accepts a comma delimited string for each property or event handler
you might want to set.
To add an event handler, prefix the name of the event with @ . The event handler will
need to be available in the templateContext of the element.
ts
document.querySelector('mgt-agenda').templateContext = {
}
HTML
<template>
<button data-props="{{@click: someEventHandler}}"></button>
</template>
The event args, data context, and the root element of the template are passed to the
event handler as parameters.
In this scenario, you can use the templateRendered event, which fires after the template
has been rendered.
ts
The event details will contain a reference to the element that is being rendered, the data
context object, and the type of the template.
ts
Styling
The templates can be styled normally via CSS as they are rendered outside of the
shadow dom.
Handle events exposed by Microsoft
Graph Toolkit components
Article • 03/31/2022
Many Microsoft Graph Toolkit components emit custom events. Attaching event
handlers to these events allows you to respond to them and control the behavior of
your app.
) Important
Some events, like itemClick in the File list component, are emitted only when
using the default template. If you use a custom template, you overwrite the default
rendering that is responsible for emitting the event.
For example, to handle the itemClick event emitted by the File list component, add the
following to your code.
JavaScript
document.querySelector('mgt-file-list').addEventListener('itemClick', e => {
// your event handler code goes here
});
You can access the additional information exposed by an event through the details
property of the event object passed into your event handler, as shown in the following
example.
JavaScript
document.querySelector('mgt-file-list').addEventListener('itemClick', e => {
const clickedFile = e.details;
});
Microsoft Graph Toolkit caching
Article • 01/07/2023
The Microsoft Graph Toolkit supports caching of select Microsoft Graph API calls. Calls
are being cached per entity, such as people, contact, photo. This allows one component
to retrieve the data and other components to reuse it without calling Microsoft Graph.
Tip
For more information about which entities are cached by each component, see the
component's documentation.
Databases created by mgt for caching are prefixed with mgt- . The data for each entity is
stored in a separate object store. To inspect the cache, use the Application tab in the
developer panel (F12 tools) - under the Storage section, click on the IndexedDB tab.
Cache configuration
You can read and write the cache options through the static class CacheService.config
object. It is formatted as shown.
TypeScript
let config = {
defaultInvalidationPeriod: number,
isEnabled: boolean,
people: {
invalidationPeriod: number,
isEnabled: boolean
},
photos: {
invalidationPeriod: number,
isEnabled: boolean
},
users: {
invalidationPeriod: number,
isEnabled: boolean
},
presence: {
invalidationPeriod: number,
isEnabled: boolean
},
groups: {
invalidationPeriod: number,
isEnabled: boolean
},
response: {
invalidationPeriod: number,
isEnabled: boolean
},
files: {
invalidationPeriod: number,
isEnabled: boolean
},
fileLists: {
invalidationPeriod: number,
isEnabled: boolean
}
};
Individual cache invalidation periods are defaulted to null in the config object, and
default to the general defaultInvalidationPeriod value of 3,600,000 ms (60 minutes).
Any value passed into config.x.invalidationPeriod will override
defaultInvalidationPeriod .
The presence store is the only exception, and has a default value of 300000 ms, or 5
minutes.
Examples
To individual disable a store simply set the value of isEnabled in that store's config
properties to false:
JavaScript
CacheService.config.users.isEnabled = false;
Disabling the cache does not clear the cache.
JavaScript
CacheService.config.users.invalidationPeriod = 1800000;
The clear all the stores in the cache, the clearCaches() method of the CacheService
class will clear every store maintained by the CacheService.
JavaScript
CacheService.clearCaches();
JavaScript
Note: The storeName you reference in the call to getCache() must match one of the
stores listed in your CacheSchema object.
TypeScript
import { CacheSchema } from '@microsoft/mgt-element';
const cacheSchema: CacheSchema = {
name: string,
stores: {
store1: {},
store2: {},
...
},
version: number
};
TypeScript
// graph call
const graphRes = graph
.api('me')
.middlewareOptions(prepScopes('user.read'))
.get();
You can localize the Microsoft Graph Toolkit components to ensure that the UI reflects
the target language.
ts
LocalizationHelper.strings = {
noResultsFound: ""لم نجد أي قنوات,
_components: {
"login": {
signInLinkSubtitle: "login",
signOutLinkSubtitle: ""خروج,
},
"people-picker": {
inputPlaceholderText: ""ابدأ في كتابة االسم,
noResultsFound: ""لم نجد أي قنوات, // will overwrite globally defined
noResultsFound in people-picker component
loadingMessage: "..."جار التحميل,
},
"teams-channel-picker": {
inputPlaceholderText: ""حدد قناة,
noResultsFound: "local NoResultsFound Example",
// loadingMessage: is default string "Loading..." for this example
since not defined globally or locally
},
"tasks": {
removeTaskSubtitle: "delete",
cancelNewTaskSubtitle: "canceltest",
newTaskPlaceholder: "newTaskTest",
addTaskButtonSubtitle: "addme",
},
"person-card": {
sendEmailLinkSubtitle: ""ارسل بريد الكتروني,
startChatLinkSubtitle: ""ابدأ الدردشة,
showExpandedDetailsButton: 'Show expanded details',
showMoreSectionButton: ""أظهر المزيد, // global declaration
},
"person-card-contact": {
contactSectionTitle: ""اتصل,
},
"person-card-organization": {
reportsToSectionTitle: ""تقارير ل,
directReportsSectionTitle: ""تقارير مباشرة,
organizationSectionTitle: ""منظمة,
youWorkWithSubSectionTitle: ""انت تعمل مع,
userWorksWithSubSectionTitle: ""يعمل مع,
},
},
};
The strings can be set at a global level or per component (with the _components:
property).
Strings
Login
ts
"login": {
signInLinkSubtitle: "Sign In",
signOutLinkSubtitle: "Sign Out"
}
People-Picker
ts
"people-picker": {
inputPlaceholderText: "Start typing a name",
noResultsFound: `We didn't find any matches.`,
loadingMessage: "Loading..."
}
Teams-Channel-Picker
ts
"teams-channel-picker": {
inputPlaceholderText: "Select a channel",
noResultsFound: `We didn't find any matches.`,
loadingMessage: "Loading..."
}
Tasks
ts
"tasks": {
removeTaskSubtitle: "Delete Task",
cancelNewTaskSubtitle: "cancel",
newTaskPlaceholder: "Task...",
addTaskButtonSubtitle: "Add"
}
Tasks-Base
ts
"tasks-base": {
removeTaskSubtitle: "Delete Task",
cancelNewTaskSubtitle: "cancel",
newTaskPlaceholder: "Task...",
addTaskButtonSubtitle: "Add"
}
Todo
ts
"todo": {
removeTaskSubtitle: "Delete Task",
cancelNewTaskSubtitle: "cancel",
newTaskPlaceholder: "Task...",
addTaskButtonSubtitle: "Add"
}
Person-Card
ts
"person-card": {
sendEmailLinkSubtitle: "Send email",
startChatLinkSubtitle: "Start chat",
showMoreSectionButton: "Show more"
}
Person-Card-Contact
ts
"person-card-contact": {
contactSectionTitle: "Contact"
}
Person-Card-Organization
ts
"person-card-organization": {
reportsToSectionTitle: "Reports to",
directReportsSectionTitle: "Direct reports",
organizationSectionTitle: "Organization",
youWorkWithSubSectionTitle: "You work with",
userWorksWithSubSectionTitle: "works with"
}
Person-Card-Messages
ts
"person-card-messages": {
emailsSectionTitle: "Emails"
}
Person-Card-Files
ts
"person-card-files": {
filesSectionTitle: "Files",
sharedTextSubtitle: "Shared"
}
Person-Card-Profile
ts
"person-card-profile": {
SkillsAndExperienceSectionTitle: "Skills & Experience",
AboutCompactSectionTitle: "About",
SkillsSubSectionTitle: "Skills",
LanguagesSubSectionTitle: "Languages",
WorkExperienceSubSectionTitle: "Work Experience",
EducationSubSectionTitle: "Education",
professionalInterestsSubSectionTitle: "Professional Interests",
personalInterestsSubSectionTitle: "Personal Interests",
birthdaySubSectionTitle: "Birthday",
currentYearSubtitle: "Current"
}
File
ts
'file': {
modifiedSubtitle: 'Modified',
sizeSubtitle: 'Size'
};
File-List
ts
"file-list": {
showMoreSubtitle: 'Show more items'
}
Display Microsoft Graph Toolkit
components right-to-left (rtl)
Article • 03/31/2022
The Microsoft Graph Toolkit components support bidirectional markup for right-to-left
language scripts.
To change the direction of all components on the page, set the dir attribute on the
document html or body tag to rtl , as shown in the following examples.
HTML
<body dir="rtl"></body>
or
HTML
<html dir="rtl"></html>
Configure Microsoft 365 services with
the Microsoft Graph API in Visual Studio
Article • 05/24/2023
You can use Microsoft Graph to consume user information stored in Microsoft 365 in
custom applications. By using Connected Services in Visual Studio, you can grant your
application access to the following Microsoft 365 services:
This article describes how to configure Connected Services in Visual Studio to use
Microsoft Graph in an ASP.NET MVC application that displays events from the currently
signed in user's calendar.
Get set up
To use the Office 365 Connected Services with Microsoft Graph, you need to:
Download Visual Studio . If you already have it, update to the latest version.
Get a Microsoft 365 subscription. To get a free trial developer subscription, join the
Microsoft 365 Developer Program.
Go to your Azure Active Directory (Azure AD) admin center in the Azure Portal to
find your domain name. Sign in and select the Azure Active Directory > Overview
menu item. The field Primary domain in Basic information section contains your
domain name.
Select the Calendars tab and check the box Read your calendars to grant
your application the Calendar.Read permission.
Select the User tab and check the box Sign you in and read your profile to
grant your application the User.Read permission.
4. Choose Finish.
XML
<add key="ida:RedirectUri" value="https://localhost:PORT/" />
<add key="ida:AppScopes" value="User.Read Calendars.Read" />
Modify the PORT value for ida:RedirectUri to match the URL of your application.
Tip: You can find the PORT information in the project properties.
The home page displays your name that indicates that you're signed-in. On the
Calendar tab, a table of events displays accordingly to your account.
Select Sign Out on the avatar in the top-right corner to reset the session and return to
the home page.
Token cache
The TokenStorage\SessionTokenCache.cs implements a token store class to serialize
and store the MSAL token cache and the user's details in the user session. You can
replace this with your own custom token cache. For more information, see Cache access
tokens.
Views
The Views\Shared\_Layout.cshtml defines the global layout of the app. It adds
Bootstrap for simple styling and Font Awesome for icons, defines the layout of the
nav bar, and uses the Alert class to display alerts.
Need help?
If you need help, post your questions on Microsoft Q&A. Tag your post with {microsoft-
graph-identity}.
Best practices for working with
Microsoft Graph
Article • 11/08/2022
This article describes best practices that you can apply to help your applications get the
most out of Microsoft Graph—whether that involves learning about Microsoft Graph,
improving app performance, or making your application more reliable for end users.
Experiment with new APIs before you integrate them into your application.
Authentication
To access data through Microsoft Graph, your application will need to acquire an OAuth
2.0 access token, and present it to Microsoft Graph in either of the following options:
Use the Microsoft Authentication Library API, MSAL to acquire the access token to
Microsoft Graph.
Apply least privilege. Grant users and apps only the lowest privileged permission
they require to call the API. Check the permissions section in the method topics
(for example, see creating a user), and choose the least privileged permissions. For
example, if the app will read only the profile of the currently signed-in user, grant
User.Read instead of User.ReadBasic.All. If an app doesn't read the user's calendar,
do not grant it the Calendars.Read permission. For a full list of permissions, see
permissions reference.
Use the correct permission type based on scenarios. Avoid using both application
and delegated permissions in the same app. If you're building an interactive
application where a signed-in user is present, your application should use
delegated permissions. If, however, your application runs without a signed-in user,
such as a background service or daemon, your application should use application
permissions.
U Caution
Be thoughtful when configuring your app. This will directly affect end user and
admin experiences, along with application adoption and security. For example:
Your application's name, logo, domain, publisher verification status, privacy
statement, and terms of use will show up in consent and other experiences.
Configure these settings carefully so they are understood by your end users.
Consider who will be consenting to your application - either end users or
administrators - and configure your application to request permissions
appropriately.
Ensure that you understand the difference between static, dynamic, and
incremental consent.
Pagination
When querying a resource collection, you should expect that Microsoft Graph will return
the result set in multiple pages, due to server-side page size limits. When a result set
spans multiple pages, Microsoft Graph returns an @odata.nextLink property in the
response that contains a URL to the next page of results.
HTTP
GET https://graph.microsoft.com/v1.0/me/messages
JSON
"@odata.nextLink": "https://graph.microsoft.com/v1.0/me/messages?$skip=23"
7 Note
Your application should always handle the possibility that the responses are paged
in nature, and use the @odata.nextLink property to obtain the next paged set of
results, until all pages of the result set have been read. The final page will not
contain an @odata.nextLink property. You should include the entire URL in the
@odata.nextLink property in your request for the next page of results, treating the
User does 403 If your application is up and running, it could encounter this error even if it
not have has been granted the necessary permissions through a consent experience.
access In this case, it's most likely that the signed-in user does not have privileges
to access the resource requested. Your application should provide a generic
"Access denied" error back to the signed-in user.
Not found 404 In certain cases, a requested resource might not be found. For example a
resource might not exist, because it has not yet been provisioned (like a
user's photo) or because it has been deleted. Some deleted resources
might be fully restored within 30 days of deletion - such as user, group and
application resources, so your application should also take this into
account.
Throttling 429 APIs might throttle at any time for a variety of reasons, so your application
must always be prepared to handle 429 responses. This error response
includes the Retry-After field in the HTTP response header. Backing off
requests using the Retry-After delay is the fastest way to recover from
throttling. For more information, see throttling.
Service 503 This is likely because the services is busy. You should employ a back-off
unavailable strategy similar to 429. Additionally, you should always make new retry
requests over a new HTTP connection.
By default, a GET operation returns only known members for properties of evolvable
enum types and your application needs to handle only the known members. If you
design your application to handle unknown members as well, you can opt-in to receive
those members by using an HTTP Prefer request header:
HTTP
Prefer: include-unknown-enum-members
Optimizations
In general, for performance and even security or privacy reasons, you should only get
the data your application really needs, and nothing more.
Use projections
Choose only the properties your application really needs and no more, because this
saves unnecessary network traffic and data processing in your application (and in the
service).
7 Note
Use the $select query parameter to limit the properties returned by a query to
those needed by your application.
For example, when retrieving the messages of the signed-in user, you can specify that
only the from and subject properties be returned:
HTTP
GET https://graph.microsoft.com/v1.0/me/messages?$select=from,subject
7 Note
If your application is required to cache or store Microsoft Graph data locally, and keep
that data up to date, or track changes to data for any other reasons, you should use
delta query. This will avoid excessive computation by your application to retrieve data
your application already has, minimize network traffic, and reduce the likelihood of
reaching a throttling threshold.
Use webhook notifications as the trigger to make delta query calls. You should also
ensure that your application has a backstop polling threshold, in case no notifications
are triggered.
Batching
JSON batching allows you to optimize your application by combining multiple requests
into a single JSON object. Combining individual requests into a single batch request can
save the application significant network latency and can conserve connection resources.
Use batching where significant network latency can have a big impact on the
performance.
Use TLS 1.2 to support all capabilities of Microsoft Graph. For more information
about the Microsoft Graph TLS 1.0 and 1.1 deprecation, see Enable support for TLS
1.2 in your environment.
Honor DNS TTL and set connection TTL to match it. This ensures availability in case
of failovers.
Open connections to all advertised DNS answers.
Generate a unique GUID and send it on each Microsoft Graph REST request. This
will help Microsoft investigate any errors more easily if you need to report an issue
with Microsoft Graph.
On every request to Microsoft Graph, generate a unique GUID, send it in the
client-request-id HTTP request header, and also log it in your application's
logs.
Always log the request-id , Date and x-ms-ags-diagnostic from the HTTP
response headers. These, together with the client-request-id , are required
when reporting issues in Microsoft Q&A or to Microsoft Support.
Known issues with Microsoft Graph
Article • 03/11/2023
For information about the latest updates to the Microsoft Graph API, see the Microsoft
Graph changelog.
Applications
Current limitations:
Some application properties (such as appRoles and addIns) will not be available
until all changes are completed.
Only multi-tenant apps can be registered.
Updating apps is restricted to apps registered after the initial beta update.
Azure Active Directory users can register apps and add additional owners.
Support for OpenID Connect and OAuth protocols.
Policy assignments to an application fail.
Operations on ownedObjects that require appId fail (For example,
users/{id|userPrincipalName}/ownedObjects/{id}/...).
In development:
For apps using delegated permissions, when using the app for the first time with a
new customer tenant, you might receive this error after sign-in: AADSTS50000:
There was an error issuing a token .
For apps using application permissions, your app can acquire a token, but
unexpectedly gets an access denied message when calling Microsoft Graph.
We are working to fix this issue as soon as possible, so that pre-consent will work for all
your customer tenants.
In the meantime, to unblock development and testing, you can use the following
workaround.
7 Note
This is not a permanent solution and is only intended to unblock development. This
workaround will not be required after the issue is fixed. This workaround does not
need to be undone after the fix is in place.
PowerShell
PowerShell
HTTP
GET /users/{id}/calendars/{id}/events
You may get HTTP 500 with the error code ErrorInternalServerTransientError . The
error occurs because:
Historically, there are two ways that calendar sharing has been implemented,
which, for the purpose of differentiating them, are referred to as the "old"
approach and "new" approach.
The new approach is currently available for sharing calendars with view or edit
permissions, but not with delegate permissions.
You can use the calendar REST API to view or edit shared calendars only if the
calendars were shared using the new approach.
You cannot use the calendar REST API to view or edit such calendars (or their
events) if the calendars were shared using the old approach.
If a calendar was shared with view or edit permissions but using the old approach, you
can now work around the error and manually upgrade the calendar sharing to use the
new approach. Over time, Outlook will automatically upgrade all shared calendars to use
the new approach, including calendars shared with delegate permissions.
To manually upgrade a shared calendar to use the new approach, follow these steps:
1. The recipient removes the calendar that was previously shared to them.
2. The calendar owner re-shares the calendar in Outlook on the web, Outlook on iOS,
or Outlook on Android.
3. The recipient re-accepts the shared calendar using Outlook on the web. (It will be
possible to use other Outlook clients soon.)
4. The recipient verifies that the calendar has been re-shared successfully using the
new approach by being able to view the shared calendar in Outlook on iOS or
Outlook on Android.
A calendar shared with you in the new approach appears as just another calendar in
your mailbox. You can use the calendar REST API to view or edit events in the shared
calendar, as if it's your own calendar. As an example:
HTTP
GET /me/calendars/{id}/events
You can add an ICS-based calendar to a user mailbox through the UI, but not
through the Microsoft Graph API.
Listing the user's calendars lets you get the name, color and id properties of each
calendar in the user's default calendar group, or a specified calendar group,
including any ICS-based calendars. You cannot store or access the ICS URL in the
calendar resource.
You can also list the events of an ICS-based calendar.
The beta version offers a workaround, where you can use the onlineMeetingProvider
property of an event to verify that the provider is Microsoft Teams. Through the
onlineMeeting property of the event, you can access the joinUrl.
Change notifications
Contacts
A fix will be made available. Meanwhile, you can use the following list contacts query
and the parentFolderId property as a workaround to get the folder ID of the default
contacts folder:
HTTP
GET https://graph.microsoft.com/v1.0/me/contacts?
$top=1&$select=parentFolderId
In this request:
HTTP
GET /me/contactfolders/{id}/contacts/{id}
GET /users/{id | userPrincipalName}/contactfolders/{id}/contacts/{id}
HTTP
GET /me/contactFolders/{id}/childFolders/{id}/.../contacts/{id}
GET /users/{id |
userPrincipalName}/contactFolders/{id}/childFolders/{id}/contacts/{id}
The previous example shows one level of nesting, but a contact can be located in a child
of a child and so on.
As an alternative, you can simply get the contact by specifying its ID as shown, because
GET /contacts in the /beta version applies to all the contacts in the user's mailbox:
HTTP
GET /me/contacts/{id}
GET /users/{id | userPrincipalName}/contacts/{id}
Customer booking
JSON
{
"error": {
"code": "ErrorExceededFindCountLimit",
"message":
"The GetBookingMailboxes request returned too many results. Please
specify a query to limit the results.",
}
}
As a workaround, you can limit the set of businesses returned by the request by
including a query parameter, for example:
HTTP
GET https://graph.microsoft.com/beta/bookingBusinesses?query=Fabrikam
Delta query
Extensions
Files (OneDrive)
Groups
methods, as follows:
JSON batching
Depending on the APIs part of the batch request, the underlying services impose
their own throttling limits that affect applications that use Microsoft Graph to
access them.
Requests in a batch are evaluated individually against throttling limits and if any
request exceeds the limits, it fails with a status of 429.
Mail (Outlook)
Query parameters
$filter
HTTP
GET /tenants/{tenant-id}/teams/{team-id}/channels/{channel-id}
{
"error": {
"code": "BadRequest",
"message": "TenantId in the optional tenants/{tenantId} segment
should match the tenantId(tid) in the token used to call Graph.",
"innerError": {
"date": "2022-03-08T07:33:50",
"request-id": "dff19596-b5b2-421d-97d3-8d4b023263f3",
"client-request-id": "32ee2cbd-27f8-2441-e3be-477dbe0cedfa"
}
}
}
To solve this issue, remove the /tenants/{tenant-id} part from the URL before you call
the API to access the cross-tenant shared channel.
Users
response. To filter by the userPrincipalName, encode the # character using its UTF-8
equivalent ( %23 ), for example, GET /users?$filter=userPrincipalName eq
'AdeleV_contoso.com%23EXT%[email protected]' .
HTML
{
"error": {
"code": "ErrorNonExistentMailbox",
"message": "The SMTP address has no mailbox associated with it."
}
}
2. Any photos that may have been previously stored using the thumbnailPhoto
property (using the Azure AD Graph API (deprecated) or through AD Connect
synchronization) are no longer accessible through the Microsoft Graph photo
property of the user resource.
3. Managing users' photos through the profilePhoto resource of the Microsoft Graph
API is currently not supported in Azure AD B2C tenants.
Errors in Microsoft Graph are returned using standard HTTP status codes, as well as a
JSON error response object.
400 Bad Request Cannot process the request because it is malformed or incorrect.
401 Unauthorized Required authentication information is either missing or not valid for
the resource.
402 Payment The licensing and/or payment requirements for the API have not been
Required met.
403 Forbidden Access is denied to the requested resource. The user might not have
enough permission.
405 Method Not The HTTP method in the request is not allowed on the resource.
Allowed
406 Not This service doesn’t support the format requested in the Accept header.
Acceptable
409 Conflict The current state conflicts with what the request expects. For example,
the specified parent folder might not exist.
413 Request Entity The request size exceeds the maximum limit.
Too Large
415 Unsupported The content type of the request is a format that is not supported by the
Media Type service.
429 Too Many Client application has been throttled and should not attempt to repeat
Requests the request until an amount of time has elapsed.
500 Internal Server There was an internal server error while processing the request.
Error
504 Gateway The server, while acting as a proxy, did not receive a timely response
Timeout from the upstream server it needed to access in attempting to
complete the request. May occur together with 503.
509 Bandwidth Your app has been throttled for exceeding the maximum bandwidth
Limit cap. Your app can retry the request again after more time has elapsed.
Exceeded
The error response is a single JSON object that contains a single property named error.
This object includes all the details of the error. You can use the information returned
here instead of or in addition to the HTTP status code. The following is an example of a
full JSON error body.
JSON
{
"error": {
"code": "invalidRange",
"message": "Uploaded fragment overlaps with existing data.",
"innerError": {
"request-id": "request-id",
"date": "date-time"
}
}
}
Error responses follow the definition in the OData v4 specification for error responses.
JSON representation
The error resource is composed of these resources:
JSON
{
"error": { "@odata.type": "odata.error" }
}
JSON
{
"code": "string",
"message": "string",
"innererror": { "@odata.type": "odata.error" }
}
code string An error code string for the error that occurred
Property Value Description
name
message string A developer ready message about the error that occurred. This should not
be displayed to the user directly.
innererror error Optional. Additional error objects that may be more specific than the top
object level error.
Code property
The code property contains one of the following possible values. Your apps should be
prepared to handle any one of these errors.
Code Description
extensionError The mailbox is located on premises and the Exchange server does not
support federated Microsoft Graph requests, or an application policy
prevents the application from accessing the mailbox.
resourceModified The resource being updated has changed since the caller last read it,
usually an eTag mismatch.
resyncRequired The delta token is no longer valid, and the app must reset the sync state.
serviceNotAvailable The service is not available. Try the request again after a delay. There may
be a Retry-After header.
syncStateNotFound The sync state generation is not found. The delta token is expired and
data must be synchronized again.
Code Description
The innererror object might recursively contain more innererror objects with
additional, more specific error codes. When handling an error, apps should loop through
all the error codes available and use the most detailed one that they understand. Some
of the more detailed codes are listed at the bottom of this page.
To verify that an error object is an error you are expecting, you must loop over the
innererror objects, looking for the error codes you expect. For example:
C#
For an example that shows how to properly handle errors, see Error Code Handling .
The message property at the root contains an error message intended for the developer
to read. Error messages are not localized and shouldn't be displayed directly to the user.
When handling errors, your code should not branch based on message values because
they can change at any time, and they often contain dynamic information specific to the
failed request. You should only code against error codes returned in code properties.
The following are some additional errors that your app might encounter within the
nested innererror objects. Apps are not required to handle these, but can if they
choose. The service might add new error codes or stop returning old ones at any time,
so it is important that all apps be able to handle the basic error codes.
Code Description
Code Description
fragmentLengthMismatch Declared total size for this fragment is different from that of
the upload session.
resyncApplyDifferences Resync required. Replace any local items with the server's
version (including deletes) if you're sure that the service was
up to date with your local changes when you last sync'd.
Upload any local changes that the server doesn't know
about.
resyncUploadDifferences Resync required. Upload any local items that the service did
not return, and upload any files that differ from the server's
version (keeping both copies if you're not sure which one is
more up-to-date).
This article contains the usage constraints and other service limits for the Azure Active
Directory (Azure AD), part of Microsoft Entra, service. If you’re looking for the full set of
Microsoft Azure service limits, see Azure Subscription and Service Limits, Quotas, and
Constraints.
Here are the usage constraints and other service limits for the Azure AD service.
Category Limit
Domains You can add no more than 5,000 managed domain names.
If you set up all of your domains for federation with on-premises Active
Directory, you can add no more than 2,500 domain names in each tenant.
Applications A maximum of 100 users and service principals can be owners of a single
application.
A user, group, or service principal can have a maximum of 1,500 app role
assignments. The limitation is on the service principal, user, or group
across all app roles and not on the number of assignments on a single app
role.
An app configured for password-based single sign-on can have a
maximum of 48 groups assigned with credentials configured.
A user can have credentials configured for a maximum of 48 apps using
password-based single sign-on. This limit only applies for credentials
configured when the user is directly assigned the app, not when the user is
a member of a group which is assigned.
See additional limits in Validation differences by supported account types.
group membership that's over this limit, you must onboard the Azure AD
Connect Sync V2 endpoint API.
When you select a list of groups, you can assign a group expiration policy
to a maximum of 500 Microsoft 365 groups. There is no limit when the
policy is applied to all Microsoft 365 groups.
At this time, the following scenarios are supported with nested groups:
One group can be added as a member of another group, and you can
achieve group nesting.
Group membership claims. When an app is configured to receive group
membership claims in the token, nested groups in which the signed-in
user is a member are included.
Conditional access (when a conditional access policy has a group scope).
Restricting access to self-serve password reset.
Restricting which users can do Azure AD Join and device registration.
App role assignment, for both access and provisioning. Assigning groups
to an app is supported, but any groups nested within the directly assigned
group won't have access.
Group-based licensing (assigning a license automatically to all members of
a group).
Microsoft 365 Groups.
Access Panel There's no limit to the number of applications per user that can be displayed in
the Access Panel, regardless of the number of assigned licenses.
Reports A maximum of 1,000 rows can be viewed or downloaded in any report. Any
additional data is truncated.
Terms of use You can add no more than 40 terms to a single Azure AD organization (tenant).
Next steps
Sign up for Azure as an organization
How Azure subscriptions are associated with Azure AD
Microsoft Graph REST API v1.0 endpoint
reference
Article • 07/01/2022
Welcome to Microsoft Graph REST API reference for the v1.0 endpoint.
A number of these services are designed to enable rich scenarios around a user and
around a group.
HTTP
https://graph.microsoft.com/v1.0/{resource}?[query_parameters]
What's new
Find out about the latest new features and updates in the v1.0 endpoint.
Connect with us
Are there additional APIs or features you'd like to see in Microsoft Graph? Post new
feature requests on the Microsoft 365 Developer Platform ideas forum .
Have feedback for existing Microsoft Graph APIs? Connect with us on GitHub .
Microsoft Graph REST API beta
endpoint reference
Article • 07/01/2022
The reference content in this section documents the Microsoft Graph beta endpoint. The
beta endpoint includes APIs that are currently in preview and aren't yet generally
available. We invite you to try these APIs and provide your feedback via the following
channels:
7 Note
The APIs in the beta endpoint are subject to change. We don't recommend that you
use them in your production apps.
HTTP
https://graph.microsoft.com/beta/{resource}?[query_parameters]
What's new
Find out about the latest new features and updates in the beta endpoint.
See also
Overview of Microsoft Graph
Microsoft Graph Explorer
Microsoft Graph quick start