0% found this document useful (0 votes)
1K views

Graph

This document provides an overview of Microsoft Graph and how it can be used to build intelligent apps that leverage data and services in Microsoft 365. Microsoft Graph is the main gateway to access rich data across Microsoft services like Outlook, OneDrive, Teams etc. through a unified API endpoint. It also includes services for identity management, security etc. Developers can use the Microsoft Graph API and SDKs to build apps that integrate with Microsoft 365 workflows and derive insights. Connectors bring external data into Microsoft Graph to enhance Microsoft 365 experiences. The Microsoft Graph API, connectors and Data Connect together power the Microsoft 365 platform by enabling access to a wide range of data.

Uploaded by

TechDream
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1K views

Graph

This document provides an overview of Microsoft Graph and how it can be used to build intelligent apps that leverage data and services in Microsoft 365. Microsoft Graph is the main gateway to access rich data across Microsoft services like Outlook, OneDrive, Teams etc. through a unified API endpoint. It also includes services for identity management, security etc. Developers can use the Microsoft Graph API and SDKs to build apps that integrate with Microsoft 365 workflows and derive insights. Connectors bring external data into Microsoft Graph to enhance Microsoft 365 experiences. The Microsoft Graph API, connectors and Data Connect together power the Microsoft 365 platform by enabling access to a wide range of data.

Uploaded by

TechDream
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 2700

Tell us about your PDF experience.

Microsoft Graph documentation


Microsoft Graph is the gateway to data and intelligence in Microsoft 365. Use Microsoft Graph to
build intelligent apps, derive insights and analytics, and extend Microsoft 365 experiences.

OVERVIEW REFERENCE
What is Microsoft Graph? Microsoft Graph REST API

OVERVIEW OVERVIEW
Microsoft Graph Data Connect Microsoft Graph connectors

Services and features

Users Groups
e Access and manipulate user resources directly. e Enable user collaboration and integration
across services.

Identity and access management Security


e Use Azure AD methods to manage access and e Connect Microsoft security products, services,
authenticate users. and partners to streamline security operations.

Microsoft Teams teamwork and Outlook calendar and mail


communications
e Control calendars such as creating an event.
e Explore chat-based collaboration, meetings, e Access and manage messages and mail data.
calling, and enterprise voice features.
What's new? All services and features
h Discover new and updated Microsoft Graph p Explore services for productivity, collaboration,
APIs. people and workplace intelligence, education,
and more.

SDKs and tools

SDKs Quick start

Graph Explorer Microsoft Graph Toolkit

Resources

Learning paths and Community Support


tutorials
Microsoft Graph blog Microsoft Graph support
Microsoft Graph fundamentals Videos and podcasts Microsoft Graph Q&A
Microsoft learning paths community support
Monthly community calls
Tutorials Microsoft Graph feedback
portal
Known issues
Overview of Microsoft Graph
Article • 03/16/2023

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.

Data and services powering the Microsoft 365


platform
In the Microsoft 365 platform, three main components facilitate the access and flow of
data:

The Microsoft Graph API offers a single endpoint, https://graph.microsoft.com ,


to provide access to rich, people-centric data and insights in the Microsoft cloud,
including Microsoft 365, Windows, and Enterprise Mobility + Security. You can use
REST APIs or SDKs to access the endpoint and build apps that support Microsoft
365 scenarios, spanning across productivity, collaboration, education, people and
workplace intelligence, and more. Microsoft Graph also includes a powerful set of
services that manage user and device identity, access, compliance, and security and
help protect organizations from data leakage or loss.
Microsoft Graph connectors work in the incoming direction, delivering data
external to the Microsoft cloud into Microsoft Graph services and applications to
enhance Microsoft 365 experiences such as Microsoft Search. Connectors exist for
many commonly used data sources such as Box, Google Drive, Jira, and Salesforce.
Microsoft Graph Data Connect provides a set of tools to streamline secure and
scalable delivery of Microsoft Graph data to popular Azure data stores. The cached
data serves as data sources for Azure development tools that you can use to build
intelligent applications.

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.

What's in Microsoft Graph?


Microsoft Graph exposes REST APIs and client libraries to access data on the following
Microsoft cloud services:

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.

What can you do with Microsoft Graph?


https://www.youtube-nocookie.com/embed/PI9NO5rayiY

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:

1. Get the email addresses of the meeting event attendees.


2. Look them up individually as a user in Azure Active Directory to get their profile
information.

You can then navigate to other resources using relationships:

Connect to their manager through a manager relationship.


Get valuable insights and intelligence including the popular files trending around
the user.
Get the most relevant people around the user.
Extend the scenario to get to the user's groups through a memberOf relationship.
Reach other members in each group.
Tap into other scenarios enabled by groups, such as education and teamwork.

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 .

Popular API requests


Check out some of these common scenarios for working with the Microsoft Graph API.
The links take you to the Graph Explorer.

Operation URL

GET my https://graph.microsoft.com/v1.0/me
profile

GET my files https://graph.microsoft.com/v1.0/me/drive/root/children

GET my https://graph.microsoft.com/v1.0/me/photo/$value
photo

GET my mail https://graph.microsoft.com/v1.0/me/messages

GET my high https://graph.microsoft.com/v1.0/me/messages?$filter=importance%20eq%20'high'


importance
email

GET my https://graph.microsoft.com/v1.0/me/events
calendar
events

GET my https://graph.microsoft.com/v1.0/me/manager
manager

GET last https://graph.microsoft.com/v1.0/me/drive/root/children/foo.txt/lastModifiedByUser


user to
modify file
foo.txt

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 users in https://graph.microsoft.com/v1.0/users


my
organization
Operation URL

GET groups https://graph.microsoft.com/v1.0/groups


in my
organization

GET people https://graph.microsoft.com/v1.0/me/people


related to
me

GET items https://graph.microsoft.com/beta/me/insights/trending


trending
around me

GET my https://graph.microsoft.com/v1.0/me/onenote/notebooks
notes

Bring data from an external content source to


Microsoft Graph
Use Microsoft Graph connectors to bring data that is external to the Microsoft cloud
into Microsoft Graph. Examples of such data can be an organization's human resources
database or product catalog, hosted on-premises or in the public or private clouds.

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.

Access Microsoft Graph data at scale


Use Microsoft Graph Data Connect to access data on Microsoft Graph at scale, while
allowing administrators granular consent and full control over their Microsoft Graph
data. Data Connect streamlines the delivery of this data to Microsoft Azure.

Using Azure tools, you can then build intelligent apps that:

Find you the closest expert on a topic to you in your organization.


Automate knowledge base creation.
Analyze meeting requests to provide insights into conference room utilization.
Detect fraud with productivity and communication data.
When should I use Microsoft Graph API or Data
Connect?
Microsoft Graph Data Connect provides a new way for you to interact with the data
that's available through Microsoft Graph APIs. Data Connect provides a unique set of
tools that streamline the building of intelligent applications, all within the Microsoft
cloud.

Feature Microsoft Graph API Microsoft Graph Data Connect

Access Single user or entire tenant Many users or groups


scope

Access Real time Recurrent schedule


pattern

Data Operates on data master Operates on a cache of the data


operations

Data Data is protected while in Data protection is extended to the cache of data in
protection Microsoft 365 your Azure subscription

User Self None


consent Resource types

Admin Entire organization Select groups of users


consent Resource types Resource types and properties
Excludes users

Access RESTful web queries Azure Data Factory


tools

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.

Users and groups


At the core of Microsoft Graph are the concepts of the user and group.

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.

Feature Supporting services Description More


information

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

Connecting users' data, Microsoft 365 services,


and your apps
Starting with users and groups at the core, Microsoft Graph forms a network of
Microsoft 365 services and features that manage, protect, and extract data to support a
wide range of scenarios. Microsoft Graph lets you access this wealth of user data while
always respecting proper authorization.

Services and features


Some services in Microsoft Graph make their debut there, others have been well-known
as standalone services and are now converging in Microsoft Graph. Their API sets follow
a streamlined design as detailed in the Microsoft REST API guidelines , and are now
accessible through the single Microsoft Graph REST endpoint
https://graph.microsoft.com . The rest of this article lists the major services and features

by category.

Identity and access management


Feature Supporting Description More
services information

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

Mail Outlook Lets users communicate, organize messages, and Outlook


manage priorities in their workflows, on the web, and mail
on mobile and desktop devices. It is part of the overview
Outlook communication hub in Microsoft 365 that
also lets users manage contacts and schedule
meetings.

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.

Workbooks Excel Lets users use Excel spreadsheets to do complex Excel


and charts calculations, track, analyze, and visualize data, and workbooks
generate professional reports. and charts
overview

Collaboration and cultivating workforce


Feature Supporting Description More
services information
Feature Supporting Description More
services information

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

Employee Viva Empowers employees to make learning a natural Overview for


learning Learning part of the day by bringing learning into the flow of using
work within the tools and platforms of Microsoft Microsoft
365 that they already use. Discover, share, and track Teams,
learning across a variety of sources from a center of Shifts, and
learning in Microsoft Teams. Viva
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 and workplace intelligence


Feature Supporting Description More
services information

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

Analytics Viva Uses advanced analytics and machine-learning People and


(preview) Insights techniques to provide insights into how people workplace
spend their time and who they spend it with. This intelligence
data can help people plan their day, gain insights in Microsoft
into their different work patterns, and help them Graph
balance work and life.
Device and app management
Feature Supporting Description More
services information

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

Cloud PC Windows Windows 365 is a cloud-based service that Working with


(preview) 365 lets administrators easily set up and manage Windows 365
Windows 365 Cloud PCs for users in their Cloud PCs using
organization. Individual end users can the Microsoft
securely stream their rich, personalized Graph API
Windows experience from the Microsoft
cloud to any device, any time, with their
Cloud PC.

Device updates Windows Provides control over the approval, Windows


(preview) Update for scheduling, monitoring, and safeguarding of updates in
Business content delivered from Windows Update. Microsoft Graph
deployment
service

Multi-tenant Microsoft Lets Managed Service Providers (MSPs) Multi-tenant


management 365 remotely manage multiple customer tenants management
(preview) Lighthouse for compliance and threat detection, and using Microsoft
help get tenant devices in a healthy and 365 Lighthouse
secure state.
Feature Supporting Description More
services information

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

Security Azure AD Identity Protection, Provides a unified gateway to Security in


integration Azure Information Protection, security insights and actions Microsoft
Azure Security Center, Microsoft across Microsoft and Graph
Defender for Cloud Apps, ecosystem partners.
Windows Defender Advanced
Threat Protection, and more

eDiscovery Microsoft Purview eDiscovery Provides access to eDiscovery Security in


(Premium) capabilities used in the process Microsoft
of identifying and delivering Graph
electronic information that can
be used as evidence in legal
cases.

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

User notifications (deprecated)

) 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 .

Feature Supporting Description More information


services

User User Enables app experiences to build user- Enabling human-


notifications notifications centric and cross-platform notification centric notification
experiences including user-based fan-out, experiences using
universal dismiss, and accessing notification Microsoft Graph
history. notifications

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.

Industry Azure Data A multi-vertical, cross-industry, ETL (Extract-Transform- Industry


data ETL Lake, Load) platform that includes support for the education data
(preview) Education sector, enabling applications to manage and move user overview
and roster data from a student information system
(SIS).

Business applications
Feature Supporting Description More
services information

Customer Microsoft Targets organizations to enable their users and Microsoft


booking Bookings customers to book services directly on the web or Bookings
(preview) Facebook. Lets business providers manage customer API
preferences, services and pricing, staff lists and overview
schedules, and other common business information.

Financials Dynamics Enables management of financial data, automation and Business


(preview) 365 securing of the supply chain, sales management and Central API
Business improved customer service, management of projects, overview
Central and optimization of operations with the all-in-one
business management solution.

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.

May 2023: New and generally available

Identity and access | Directory management


As part of managing corporate devices, Intune can now set additional properties on a
device used for multi-factor authentication in conditional access policies for an
organization: deviceCategory, deviceOwnership, enrollmentProfileName, and
registrationDateTime.

Identity and access | Identity and sign-in


Specify whether to exclude or include guests or external users as part of the
condition set for conditional access.
Configure an authorization policy to allow user consent for risky apps.
Use a cross-tenant identity sync policy to synchronize users from a partner tenant.
The policy streamlines collaboration between users in a multi-tenant organization,
by automating creating, updating, and deleting users from one tenant to another.
Get the cross-tenant access default settings for automatic user consent from an
inbound/outbound policy configuration.

Reports | Microsoft 365 usage reports


Get a report of the number of teams of a particular type in an instance of Microsoft
Teams.
Get a report of the number of team activities across Microsoft Teams. Activities are
related to meetings and messages.
Get a report of the number of team activities across Microsoft Teams over a
selected period.
Get a report of details about Microsoft Teams activity by team. The activities for
both licensed and non-licensed users.

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.

Sites and lists


Get or update tenant-wide settings for SharePoint and OneDrive, which include a
number of settings such as the following:
The idle session sign-out policy settings for SharePoint.
Whether legacy authentication protocols are enabled for the tenant.
Whether guests must sign in using the same account to which sharing
invitations are sent.
Get all the sites across georgraphies in an organization.

Teamwork and communications | Calls and online


meetings
Identify the reasons for shared content or video from an online meeting participant
being restricted.

May 2023: New in preview only

Device and app management | Cloud PC


Get or set a template to name Cloud PCs provisioned by a Cloud PC provisioning
policy.
Get or set configuration settings for how a Cloud PC joins Azure Active Directory in
a Cloud PC provisioning policy.
Get the user resources that are targeted in the assignment of a Cloud PC
provisioning policy. This list of users is computed based on assignments, licenses,
group memberships, and policies.

Education
Get or update from class level assignment settings any grading category to weight
assignments differently when computing a class average grade.

Identity and access | Directory management


Get any service provisioning error published by a federated service describing a
non-transient, service-specific error for a user, group, or organization contact to let
an administrator follow up. The administrator can retry provisioning the service for
the user, group, or organization contact as applicable.
Fine-tune the on-premises directory synchronization process for an organization
by getting or updating the following additional configuration data: anchor
attribute, synchronization client application ID and version, data for the current
export run, and write-back configuration.

Identity and access | Governance


When getting a list of every decision for an instance of an access review, access
reviewers can expand to find the last user who modified any insight that a user has
low affiliation and is an outlier with other users within the group.
Use Privileged Identity Management (PIM) for groups to govern how principals are
assigned membership or ownership of security and Microsoft 365 groups, such as
the following capabilities:
Providing principals just-in-time membership or ownership of groups.
Assigning principals temporary membership or ownership of groups.

Identity and access | Identity and sign-in


Use a custom authentication extension to manage the configuration and get data
from a system external to Azure Active Directory, such as a database, so to
customize the Azure AD authentication experience for users.
To customize an authentication process, use an authentication event listener to
manage listeners and handlers that trigger the execution of custom logic during
the Azure AD authentication experience.
Use a self-service sign-up user flow for external identities within an Azure AD
workforce tenant or customer tenant, to let users sign up for an app and create a
new guest account. A user flow is basically a multi-event policy that defines a
series of steps for the user, listing each supported identity provider, and the user
attributes to collect from the user such as given name, surname, city, postal code.
For more information, see Add a self-service sign-up user flow to an app.
Get or update the permissions for the default user role in an authorization policy
to allow creating tenants in an Azure Active Directory organization.

Security | Attack simulation and training


Get the following additional data from attack simulation reports:

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.

Tasks and plans


Share a plan using a shared-with container that is separate from the original container
that the plan belongs to. Users can share a plan with multiple other containers, and
specify the maximum access level allowed by each of these containers, such as read,
readwrite, or full access.

Teamwork and communications | Calls and online


meetings
List each message history item of a chat message in a Teams chat or channel.

April 2023: New and generally available

Device and app management | Browser management


Administrators can use the Edge API in Microsoft Graph in an app to manage an
organization's browser site lists for Internet Explorer (IE) mode that reside in the cloud,
much like the way they can do it in the Microsoft 365 admin center . With proper
permissions, the app can create a browser site list, add a browser site and shared cookie,
and publish the site list for Microsoft Edge to download.

Identity and access | Identity and sign-in


Include an authentication strength policy as part of conditonal access grant
controls to be fulfilled to pass a conditional access policy. An authentication
strength policy defines specific combinations of authentication methods to be
used to authenticate in the corresponding scenario.
As part of the default user role of an authorization policy, specify whether the
registered owner of a device can read their own BitLocker recovery keys.

Search | Query
Qualify a search query string with a query template, which supports KQL and query
variables.

Teamwork and communications | Calls and online


meetings
Specify whether content for an online meeting, such as shared content or video feed,
should have watermark protection. To support watermarking content, client applications
must implement and apply the watermarking.

Teamwork and communications | Messaging


Subscribe to change notifications in a tenant where a specific Teams app is installed, for
the following resources:

Any message in any chat


Any chat
Membership of any chat

April 2023: New in preview only

Device and app management | Cloud PC


Start or stop a Windows 365 Frontline Cloud PC for a user.
IT administrators can power on or power off a Windows 365 Frontline Cloud PC.
After powering on a Cloud PC, an IT administrator can allocate and assign licenses
to a user.

Device and app management | Corporate management


Intune April updates for the beta version.

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.

Identity and access | Directory management


List or get local administrator credential information for all device objects in Azure
Active Directory that are enabled with Local Admin Password Solution (LAPS). For more
information on LAPS, see Windows Local Administrator Password Solution in Azure AD
(preview).

Identity and access | Governance


Use the new LifecycleWorkflows.ReadWrite.All delegated or application
permission to resume a task-processing result that's in progress.
Get the settings for verifiable credentials in an access package assignment policy,
that have been set up in the Microsoft Entra Verified ID verification solution. These
settings represent the verifiable credentials that a requestor of an access package
in this policy can present to be assigned the access package. The types of verifiable
credentials that a requestor presents include the type of the credential issued, such
as BusinessCardCredential , and list of accepted issuers.

Identity and access | Identity and sign-in


Get or update the permissions for the default user role in an authorization policy
to allow creating tenants in an Azure Active Directory organization.
Get or update the settings in an authentication methods policy for selected users
or groups to be included or excluded from being prompted with their preferred
multifactor authentication methods for their Azure Active Directory organization.
To support Windows Local Administrator Password Solution (LAPS) in Azure AD,
administrators can get or update local admin password settings in the device
registration policy for an organization.

Reports | Azure AD activity reports


List any managed identity used for a sign-in activity, including the identity type and
associated Azure Resource Manager (ARM) resource ID.

Reports | Microsoft 365 usage reports


For Microsoft Forms:

Get usage reports for activity counts by activity type.


Get usage reports for activity counts by user type.
Get usage reports for details of form activity by user.

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.

Teamwork and communications | Calls and online


meetings
Get the metadata content of a call transcript in a stream.
Get a log of users who are blocked or unblocked from making public switched
telephone network (PSTN) calls in Microsoft Teams.
Get an aggregated report of the usage and money spent for audio conferencing
dial-out service. The report includes the cost, number of dial-out calls, and total
time of use over a selected period.
Get a log of sent or received SMS messages.
In addition to existing data in a PSTN call log row, get the country code for the
second party in the PSTN call.
In addition to existing data in a direct routing call log row, get the country codes
of the two parties in the direct routing call.
Get the join URL for an appointment on the Virtual Appointments app for
Microsoft Teams. Existing customers who use the prior virtual appointment API in
their apps should update their apps to integrate with the Virtual Appointments
app before the API stops returning data on June 20, 2023. For more information,
see Virtual Appointments with Microsoft Teams.
Get or set the option to share the chat history of an online meeting with
participants.
Listing sessions in a call record can now identify those sessions that took place for
testing purpose.
Represent CPU capabilities of a caller or callee participant endpoint in a call or
online meeting.
Track the freeze duration data of a video stream in a media stream.
Communications servers can publish deltaParticipants notifications for the creation,
update, or deletion of a participant in a call. For more information, see JSON
payload examples of notifications with delta roster disabled or enabled.

Teamwork and communications | Employee learning


Track an activity that is part of a learning course in Viva Learning, for a user and for a
learning provider. Differentiate between an activity that's been assigned to the user, and
an activity that is initiated by the user.

Want to stay in the loop?


Here are some ways we can engage:

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 ).

2. Promoted to general availability (GA) status, if sufficient feedback indicates


viability. Any related REST API updates are added to the v1.0 endpoint
( https://graph.microsoft.com/v1.0 ).

Be an active member in the Microsoft Graph community! Join the weekly


Microsoft 365 platform community call.

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.

Use Graph Explorer to:

Try out Microsoft Graph APIs.


Learn about the permissions required for the different APIs.
Explore all the resources available on Microsoft Graph.
Explore Microsoft Graph Toolkit components, adaptive cards and code snippets for
your queries.

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.

Retrieve data in Graph Explorer


To run a GET request in Graph Explorer, you don't have to sign in. You can retrieve
sample data from the default sample tenant.

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.

Modify data in Graph Explorer


To try POST, PUT, PATCH, and DELETE requests, sign in to Graph Explorer by using a
Microsoft 365 account. This can be an organizational account for testing or
demonstration purposes. To get a free instant sandbox preconfigured with sample data
packs to test with, join the Microsoft 365 Developer Program.

) Important

If you choose to sign in by using your organizational account, running a non-GET


request might affect the data in the tenant.

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.

Delegated (user) authentication


In the delegated authentication tutorials, you create a basic command-line application
that has the following features:

Enables user authentication to get access on behalf of a user


Accesses the user's profile
Lists the user's mailbox
Sends an email from the user's mailbox

If you prefer to download a completed project, you can do so from one of the following
locations:

The project's corresponding GitHub repository. Instructions for registering an


application and configuring the sample are located in each repository.
A Microsoft Graph quick start. A quick start automates registering an application
for you and downloads the completed project already configured for user
authentication. A quick start is available for all tutorials except Power Automate.

Tutorial GitHub 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

Power Automate microsoftgraph/msgraph-training-powerautomate

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:

Enables app-only authentication to get access without a user


Lists users in Azure Active Directory

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.

Tutorial GitHub 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:

Microsoft Graph Fundamentals


Build apps with Microsoft Graph - Associate
Develop apps with Microsoft Graph Toolkit
Explore Microsoft Graph scenarios for JavaScript development

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.

Connect to personal services


Use Microsoft Graph to reach users with Microsoft personal accounts, such as
@outlook.com, @hotmail.com, or @live.com accounts. With their consent, you can use
Microsoft Graph to access users' profiles, their Office services like OneDrive and Outlook
mail, calendar, and contacts, and their Windows devices and activities.

Connect to work services


Use Microsoft Graph to reach users and organizations that have licenses to Microsoft
365 services for business, enterprise, or education. These Microsoft 365 services include:

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.

Worldwide, multigeo, and national clouds


The services in Microsoft Graph are part of the Microsoft worldwide cloud. In addition,
Microsoft offers:

Multigeo capabilities for multinational organizations with multiple geographic


regions and/or countries within their existing tenant.
National cloud deployments for US government, Germany, and Azure and
Microsoft 365 operated by 21Vianet in China.
With their consent, you can use Microsoft Graph to reach users and organizations whose
services are in the worldwide cloud, including organizations with multigeo services, and
you can also use Microsoft Graph to access users and organizations in national cloud
deployments, but special considerations are required for cloud sovereignty. To find out
more, see National cloud deployments.

Connect to school services


Use Microsoft Graph to reach students, teachers, and schools with licenses to Microsoft
365 services for education. With their consent, you can use education APIs in Microsoft
Graph that enhance Microsoft 365 resources and data with information that is relevant
for education scenarios, including schools, students, teachers, classes, enrollments, and
assignments. Learn more about integrating with the education API.

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.

Current national clouds include:

Microsoft Cloud for US Government


Microsoft Azure and Microsoft 365 operated by 21Vianet in China

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

App registration and token service root


endpoints
Before calling the Microsoft Graph APIs, you should first register your application and
acquire a token. The following table lists the base URLs for the Azure Active Directory
(Azure AD) endpoints to register your application and acquire tokens for each national
cloud.

National cloud Azure AD portal Azure AD endpoint


endpoint

Azure AD (global service) https://portal.azure.com https://login.microsoftonline.com

Azure AD for US Government https://portal.azure.us https://login.microsoftonline.us


National cloud Azure AD portal Azure AD endpoint
endpoint

Azure AD China operated by https://portal.azure.cn https://login.chinacloudapi.cn


21Vianet

To learn more about access tokens and Microsoft Graph, see authentication basics. For
Azure AD authentication scenarios, see Azure AD authentication basics.

Microsoft Graph and Graph Explorer service


root endpoints
The following table shows the service root endpoints for Microsoft Graph and Graph
Explorer for each national cloud.

National Microsoft Graph Graph Explorer


Cloud

Microsoft https://graph.microsoft.com https://developer.microsoft.com/graph/graph-


Graph explorer
global
service

Microsoft https://graph.microsoft.us Not supported.


Graph for
US
Government
L4

Microsoft https://dod-graph.microsoft.us Not supported.


Graph for
US
Government
L5 (DOD)

Microsoft https://microsoftgraph.chinacloudapi.cn Not supported.


Graph China
operated by
21Vianet

) Important

For an app in US Government:


If you're working in a Microsoft 365 GCC environment, continue using the
worldwide endpoints: https://graph.microsoft.com and
https://portal.azure.com .

If you're working in a Microsoft 365 GCC High environment, use


https://portal.azure.us and https://graph.microsoft.us .

If you're working in a Microsoft 365 DoD environment, use


https://portal.azure.us and https://dod-graph.microsoft.us .

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 ✔ ✔

Applications and service ✔ ✔


principals

Change notifications ✔ ✔
(subscriptions)

Change tracking (delta ✔ ✔


query)

Directory extensions ✔ ✔

Excel ✔ ➖

Groups ✔ ✔
Microsoft Graph features Microsoft Cloud for US Microsoft Cloud China operated
Government by 21Vianet

OneDrive ✔ ✔*

Open type extensions ✔ ✔

Organizational contacts ✔ ✔

Outlook Calendar ✔ ✔

Outlook Mail ✔ ✔

Personal Contacts ✔ ✔

Privileged identity ✔ ✔
management

Planner ✔ ✔

Reports (Azure AD activity ✔ ✔


reports)

Reports (Microsoft 365 ➖ ➖


reports)

Search (Microsoft Search) ✔ ✔

Security ✔ ✔

Service health and ✔ ✔


communications

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 .

To learn more about National clouds, see the following articles:

Microsoft National Clouds


Microsoft 365 for US Government
Microsoft 365 operated by 21Vianet
Azure Government
Azure China 21Vianet

Explore samples for authenticating and working with Azure and Microsoft 365 in
National cloud deployments:

Access national cloud deployments with the Microsoft Graph SDKs


Work with Azure through Microsoft Graph for US Government
Connect to US Government O365 environments (GCC, GCC High and GCC DoD)
using Microsoft Graph PowerShell
Use REST APIs to access mailboxes in
Exchange hybrid deployments
(deprecated)
Article • 06/15/2022

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.

API categories and metering


Microsoft Graph APIs fall into three categories, and metering may apply based on the
category of the API.

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.

Accessing metered APIs


To access metered APIs and services in Microsoft Graph, an application must be
associated with an active Microsoft Azure subscription. For details about how to
associate an app to a subscription, see Enable metered APIs and services in Microsoft
Graph.

Considerations for using metered APIs


Keep the following considerations in mind when you use metered APIs and services in
Microsoft Graph:

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.

The following table lists the metered APIs and services.

API Billing and license information Protected API form

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.

Support policy and deprecation information


Microsoft Graph follows the Microsoft Lifecycle Policy .

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.

API contract and non-backward compatible changes


Microsoft Graph has a log of changes across versions. These changes are listed in the
Microsoft Graph Changelog. As new functionality and data is added to Microsoft Graph,
we will increment the API version number for any non-backward compatible changes to
the API.

The following are examples of non-backward compatible changes:

Changes to the URL or fundamental request/response associated with a resource


Removal, rename, or change to the type of a declared property
Removal or rename of APIs or API parameters
Addition of a required request header

The following are examples of backward compatible changes:

Addition of properties that are nullable or have a default value


Addition of a member to an enumeration
Removal, rename, or change to the type of an open extension
Removal, rename, or change to the type of an annotation
Introduction of paging to existing collections
Changes to error codes
Changes to the order of properties
Changes to the length or format of opaque strings, such as resource IDs

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:

Available in only beta


Available in beta differently than in v1.0

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.

Deprecated and unsupported versions


There are currently no deprecated versions of Microsoft Graph.

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

Last Updated: May 2019 What's new?

Thank you for developing with Microsoft!

By accessing or using Microsoft APIs, including within a software application, website,


tool, service, or product you create or offer to Customers (your "Application"), you are
agreeing to these terms and to comply with any accompanying documentation that
applies to your use of the Microsoft APIs ("API Terms") with Microsoft Corporation
("Microsoft", "we", "us", or "our"). You represent and warrant to us that you have the
authority to accept these API Terms on behalf of yourself, a company, and/or other
entity, as applicable. We may change, amend or terminate these API Terms at any time.
Your use of the Microsoft APIs after any change or amendment means you agree to
the new API Terms. If you do not agree to the new API Terms or if we terminate these
API Terms, you must stop using the Microsoft APIs.

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.

d) The Microsoft APIs include:

1. the Microsoft Graph API (documented, for example, at


https://learn.microsoft.com/graph);
2. any other Microsoft APIs that enable access to data in Azure Active Directory;
3. any other Microsoft APIs that enable access to data in services that are part of
Office 365 (including, but not limited to, Office 365 Services, Office 365 Business,
Office 365 Business Premium, Office 365 Business Essentials, Office 365 Home, and
Office 365 Personal), including, for example, all APIs in the following services:
a. Office 365: Outlook/Exchange, SharePoint, OneDrive, Microsoft Teams, Excel,
OneNote, Project Online, Microsoft Planner, Microsoft Kaizala Pro, and Yammer;
and
b. Office 365 for Education;
4. Any other Microsoft APIs that enable access to data in services that are part of
Outlook.com, OneDrive.com, and Yammer;
5. Microsoft email protocols and APIs;
6. any other Microsoft APIs that enable access to data in Microsoft Intune®; and
7. any other Microsoft APIs that enable access to data from Project Rome services,
including, but not limited to: user activities, notifications, device relay and share
(documented, for example, at https://learn.microsoft.com/windows/project-rome/).

2. Scope and Application Registration


a) These API Terms govern your use of Microsoft APIs except:

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.

b) Registration for your Application may be required pursuant to documentation. If


registration is required, you must register your Application with Microsoft. Your
registration must be accurate and kept up-to-date by you at all times. Once you have
successfully registered an Application, you will be given access credentials for your
Application. "Access Credentials" means the necessary security keys, secrets, tokens,
and other credentials to access the Microsoft APIs. The Access Credentials enable us to
associate your Application with your use of the Microsoft APIs. All activities that occur
using your Access Credentials are your responsibility. Access Credentials are non-
transferable and non-assignable. Keep them secret. Do not try to circumvent them.

3. Microsoft APIs License and Guidelines


a) Microsoft APIs License Subject to your compliance with all of the API Terms,
Microsoft grants you a limited, non-exclusive, non-assignable, non-transferable,
revocable license to use the Microsoft APIs to develop, test, and support your
Application, and allow Customers to use your integration of the Microsoft APIs within
your Application. You may use the Microsoft APIs only as expressly permitted in these
API Terms. Violation of these API Terms may result in the suspension or termination of
your use of the Microsoft APIs.

b) Microsoft APIs Guidelines

You may NOT:

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:

1. syncing email messages, calendar events, and contacts, or


2. backing up email messages, calendar events, and contacts.

d) Accessing the Microsoft Intune Service through a Microsoft API

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:

1. In your Application and services' license terms, a statement that certain


functionalities are enabled by accessing Microsoft Intune® through the Microsoft
API and use of your Application and accompanying services does not remove the
need for users to have a valid license for their use of the Microsoft Intune®
service.
2. In your Application and services' marketing material and product documentation
that references functionality enabled by your Application or service's access to
Microsoft Intune® through the Microsoft API:
a. The attribution "Microsoft Intune® App Protection Policies" displayed in a
manner consistent with the Microsoft Trademark & Brand Guidelines , and
b. A statement that use of your Application and services does not remove the
need for users to maintain a valid license for their use of the Microsoft Intune®
service.
3. In your Application's user interface or console that displays commands for
functionality enabled by the Microsoft API for Intune, include the attribution
"Microsoft Intune® App Protection Policies" in a conspicuous place on the console
or UI. The attribution must be in a manner consistent with the Microsoft
Trademark & Brand Guidelines .

e) Accessing Microsoft OneDrive through a Microsoft API

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.

5. Your Compliance with Applicable Privacy and


Data Protection Laws
You must comply with all laws and regulations applicable to your use of the data
accessed through the Microsoft APIs, including without limitation laws related to
privacy, biometric data, data protection and confidentiality of communications. Your use
of the Microsoft APIs is conditioned upon implementing and maintaining appropriate
protections and measures for your service and Application, and that includes your
responsibility to the data obtained through the use of the Microsoft APIs. For the data
you obtained through the Microsoft APIs, you must:

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.

Nothing in the Agreement shall be construed as creating a joint controller or processor-


subprocessor relationship between you and Microsoft.

6. Changes to the Microsoft APIs and API Terms


WE MAY CHANGE OR DISCONTINUE THE AVAILABILITY OF SOME OR ALL OF THE
MICROSOFT APIs AT ANY TIME FOR ANY REASON WITH OR WITHOUT NOTICE. Such
changes may include, without limitation, removing or limiting access to specific API(s),
requiring fees or setting and enforcing limits on your use of additions to the Microsoft
APIs. We may also impose limits on certain features and services or restrict your access
to some or all of the Microsoft APIs. We may release subsequent versions of the
Microsoft APIs and require that you use those subsequent versions, at your sole cost
and expense.

Any version of the Microsoft APIs designated as "preview", "pre-release" or "beta"


("Preview API"), may not work in the same way as a final version. We may change or not
release a final or commercial version of a Preview API in our sole discretion.

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.

9. Disclaimer of Warranties, Limitation of


Liability and Indemnity
a) Disclaimer of Warranties

WE MAKE NO WARRANTIES, EXPRESS OR IMPLIED, GUARANTEES OR CONDITIONS


WITH RESPECT TO YOUR USE OF THE MICROSOFT APIs. YOU UNDERSTAND THAT
USE OF THE MICROSOFT APIs IS AT YOUR OWN RISK AND THAT WE PROVIDE THE
MICROSOFT APIs ON AN "AS IS" BASIS "WITH ALL FAULTS" AND "AS AVAILABLE" TO
THE EXTENT PERMITTED UNDER YOUR LOCAL LAW, WE EXCLUDE ANY IMPLIED
WARRANTIES, INCLUDING FOR MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS
FOR A PARTICULAR PURPOSE, WORKMANLIKE EFFORT, AND NON-INFRINGEMENT.
YOU MAY HAVE CERTAIN RIGHTS UNDER YOUR LOCAL LAW. NOTHING IN THESE API
TERMS ARE INTENDED TO AFFECT THOSE RIGHTS, IF THEY ARE APPLICABLE. WE DO
NOT GUARANTEE THE MICROSOFT APIs WILL FUNCTION WITHOUT INTERRUPTION
OR ERRORS IN FUNCTIONING. IN PARTICULAR, THE OPERATION OF THE MICROSOFT
APIs MAY BE INTERRUPTED DUE TO MAINTENANCE, UPDATES, OR SYSTEM OR
NETWORK FAILURES. WE DISCLAIM ALL LIABILITY FOR DAMAGES CAUSED BY ANY
SUCH INTERRUPTION, ERRORS IN FUNCTIONING, OR THAT DATA LOSS WILL NOT
OCCUR.

b) Limitation of Liability

IF YOU HAVE ANY BASIS FOR RECOVERING DAMAGES (INCLUDING BREACH OF


THESE API TERMS), YOU AGREE THAT YOUR EXCLUSIVE REMEDY IS TO RECOVER,
FROM MICROSOFT OR ANY AFFILIATES, RESELLERS, DISTRIBUTORS, SUPPLIERS (AND
RESPECTIVE EMPLOYEES, SHAREHOLDERS, OR DIRECTORS) AND VENDORS, ONLY
DIRECT DAMAGES UP TO USD $5.00 COLLECTIVELY. YOU CAN'T RECOVER ANY OTHER
DAMAGES OR LOSSES, INCLUDING, WITHOUT LIMITATION, DIRECT,
CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT, INCIDENTAL, OR PUNITIVE.
These limitations and exclusions apply even if this remedy doesn't fully compensate you
for any losses or fails of its essential purpose or if we knew or should have known about
the possibility of the damages. To the maximum extent permitted by law, these
limitations and exclusions apply to any claims related to these API Terms or your use of
the Microsoft APIs.

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.

11. General Terms


a) Applicable Law

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

Develop user-centric applications


You can use Microsoft Graph to access the relationships, documents, contacts, and
preferences that are contextually relevant to the signed-in user. The user resource
provides straightforward way for you to access and manipulate user resources without
having to perform additional calls, look up specific authentication information, and
directly issue queries against other Microsoft Graph resources.

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.

Manage your organization


Create new users in your organization or update the resources and relationships for
existing users. You can use Microsoft Graph to perform the following user management
tasks:

Create or delete users in your Azure AD organization.


List a user's group memberships and determine whether a user is a member of a
group.
List the users who report to a user and assign managers to a user.
Upload or retrieve a photo for the user.

Work with calendars and tasks


You can view, query, and update user calendar and calendar groups associated with a
user, including:

List and create events on a user's calendar.


View tasks assigned to a user.
Find free meeting times for a set of users.
Get a list of reminders set on a user's calendar.

Administer mail and handle contacts


You can configure user mail settings and contact lists and send mail on a user's behalf,
including:

List mail messages and send new mail.


Create and list user contacts and organize contacts in folders.
Retrieve and update mailbox folders and settings.

Enrich your app with user insights


Maximize relevance in your application by promoting recently used or trending
documents and contacts associated with a user. You can use Microsoft Graph to:

Return documents recently viewed and modified by a user.


Return documents and sites trending around a user's activity.
List documents shared with a user through email or OneDrive for Business.

API reference
Looking for the API reference for this service?

Users API in Microsoft Graph v1.0


Users API in Microsoft Graph beta

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 and guest users


The set of default permissions depends on whether the user is a native member of the
tenant (member user) or whether the user is brought over from another directory as a
business-to-business (B2B) collaboration guest (guest user). For more information about
adding guest users, see What is Azure AD B2B collaboration?. Here are the capabilities of
the default permissions:

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.

Compare member and guest default


permissions
Area Member user Default guest user Restricted guest user
permissions permissions permissions
Area Member user Default guest user Restricted guest user
permissions permissions permissions

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

Groups Create security Read properties of non- Read object ID


groups hidden groups, including for joined groups
Create membership and Read
Microsoft 365 ownership (even non- membership and
groups joined groups) ownership of
Enumerate the Read hidden Microsoft joined groups in
list of all 365 group memberships some Microsoft
groups for joined groups 365 apps (if
Read all Search for groups by allowed)
properties of display name or object
groups ID (if allowed)
Read non-
hidden group
memberships
Read hidden
Microsoft 365
group
memberships
for joined
groups
Manage
properties,
ownership, and
membership of
groups that the
user owns
Add guests to
owned groups
Manage
dynamic
membership
settings
Delete owned
groups
Restore owned
Microsoft 365
groups
Area Member user Default guest user Restricted guest user
permissions permissions permissions

Applications Register Read properties of Read properties


(create) new registered and enterprise of registered and
applications applications enterprise
Enumerate the List permissions granted applications
list of all to applications List permissions
applications granted to
Read applications
properties of
registered and
enterprise
applications
Manage
application
properties,
assignments,
and credentials
for owned
applications
Create or
delete
application
passwords for
users
Delete owned
applications
Restore owned
applications
List
permissions
granted to
applications

Devices Enumerate the No permissions No permissions


list of all
devices
Read all
properties of
devices
Manage all
properties of
owned devices
Area Member user Default guest user Restricted guest user
permissions permissions permissions

Organization Read all Read company display Read company


company name display name
information Read all domains Read all domains
Read all Read configuration of
domains certificate-based
Read authentication
configuration
of certificate-
based
authentication
Read all
partner
contracts

Roles and Read all No permissions No permissions


scopes administrative
roles and
memberships
Read all
properties and
membership of
administrative
units

Subscriptions Read all No permissions No permissions


licensing
subscriptions
Enable service
plan
memberships

Policies Read all No permissions No permissions


properties of
policies
Manage all
properties of
owned policies

Restrict member users' default permissions


It's possible to add restrictions to users' default permissions.
You can restrict default permissions for member users in the following ways:

U Caution

Using the Restrict access to Azure AD administration portal switch is NOT a


security measure. For more information on the functionality, see the table below.

Permission Setting explanation

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

Restrict access What does this switch do?


to Azure AD No lets non-administrators browse the Azure AD administration portal.
administration Yes Restricts non-administrators from browsing the Azure AD administration
portal portal. Non-administrators who are owners of groups or applications are
unable to use the Azure portal to manage their owned resources.

What does it not do?


It doesn't restrict access to Azure AD data using PowerShell, Microsoft
GraphAPI, or other clients such as Visual Studio.
It doesn't restrict access as long as a user is assigned a custom role (or any
role).

When should I use this switch?


Use this option to prevent users from misconfiguring the resources that they
own.

When should I not use this switch?


Don't use this switch as a security measure. Instead, create a Conditional Access
policy that targets Microsoft Azure Management that blocks non-
administrators access to Microsoft Azure Management.

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 access to the Entra administration portal


A Conditional Access policy that targets Microsoft Azure Management targets
access to all Azure management.

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.

What does this switch do?


Setting this option to Yes restricts creation of Azure AD tenants to the Global
Administrator or tenant creator roles. Setting this option to No allows non-
admin users to create Azure AD tenants. Tenant create will continue to be
recorded in the Audit log.

How do I grant only a specific non-administrator users the ability to create


new tenants?
Set this option to Yes, then assign them the tenant creator role.
Permission Setting explanation

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.

This setting is meant for special circumstances, so we don't recommend setting


the flag to $false .

The Restrict non-admin users from creating tenants option is shown below

Restrict guest users' default permissions


You can restrict default permissions for guest users in the following ways.

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.

Permission Setting explanation


Permission Setting explanation

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

Application registration owner permissions


When a user registers an application, they're automatically added as an owner for the
application. As an owner, they can manage the metadata of the application, such as the
name and permissions that the app requests. They can also manage the tenant-specific
configuration of the application, such as the single sign-on (SSO) configuration and user
assignments.

An owner can also add or remove other owners. Unlike global administrators, owners
can manage only the applications that they own.

Enterprise application owner permissions


When a user adds a new enterprise application, they're automatically added as an
owner. As an owner, they can manage the tenant-specific configuration of the
application, such as the SSO configuration, provisioning, and user assignments.

An owner can also add or remove other owners. Unlike global administrators, owners
can manage only the applications that they own.

Group owner permissions


When a user creates a group, they're automatically added as an owner for that group. As
an owner, they can manage properties of the group (such as the name) and manage
group membership.

An owner can also add or remove other owners. Unlike global administrators and user
administrators, owners can manage only the groups that they own.

To assign a group owner, see Managing owners for a group.

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.

Owned application registrations


Users can perform the following actions on owned application registrations:

Action Description

microsoft.directory/applications/audience/update Update the applications.audience


property in Azure AD.

microsoft.directory/applications/authentication/update Update the


applications.authentication property
in Azure AD.

microsoft.directory/applications/basic/update Update basic properties on applications


in Azure AD.

microsoft.directory/applications/credentials/update Update the applications.credentials


property in Azure AD.

microsoft.directory/applications/delete Delete applications in Azure AD.

microsoft.directory/applications/owners/update Update the applications.owners


property in Azure AD.

microsoft.directory/applications/permissions/update Update the applications.permissions


property in Azure AD.

microsoft.directory/applications/policies/update Update the applications.policies


property in Azure AD.

microsoft.directory/applications/restore Restore applications in Azure AD.


Owned enterprise applications
Users can perform the following actions on owned enterprise applications. An enterprise
application consists of a service principal, one or more application policies, and
sometimes an application object in the same tenant as the service principal.

Action Description

microsoft.directory/auditLogs/allProperties/read Read all properties (including


privileged properties) on audit logs in
Azure AD.

microsoft.directory/policies/basic/update Update basic properties on policies in


Azure AD.

microsoft.directory/policies/delete Delete policies in Azure AD.

microsoft.directory/policies/owners/update Update the policies.owners property


in Azure AD.

microsoft.directory/servicePrincipals/appRoleAssignedTo/update Update the


servicePrincipals.appRoleAssignedTo
property in Azure AD.

microsoft.directory/servicePrincipals/appRoleAssignments/update Update the


users.appRoleAssignments property in
Azure AD.

microsoft.directory/servicePrincipals/audience/update Update the


servicePrincipals.audience property
in Azure AD.

microsoft.directory/servicePrincipals/authentication/update Update the


servicePrincipals.authentication
property in Azure AD.

microsoft.directory/servicePrincipals/basic/update Update basic properties on service


principals in Azure AD.

microsoft.directory/servicePrincipals/credentials/update Update the


servicePrincipals.credentials
property in Azure AD.

microsoft.directory/servicePrincipals/delete Delete service principals in Azure AD.

microsoft.directory/servicePrincipals/owners/update Update the


servicePrincipals.owners property in
Azure AD.
Action Description

microsoft.directory/servicePrincipals/permissions/update Update the


servicePrincipals.permissions
property in Azure AD.

microsoft.directory/servicePrincipals/policies/update Update the


servicePrincipals.policies property
in Azure AD.

microsoft.directory/signInReports/allProperties/read Read all properties (including


privileged properties) on sign-in
reports in Azure AD.

Owned devices

Users can perform the following actions on owned devices:

Action Description

microsoft.directory/devices/bitLockerRecoveryKeys/read Read the


devices.bitLockerRecoveryKeys
property in Azure AD.

microsoft.directory/devices/disable Disable devices in Azure AD.

Owned groups

Users can perform the following actions on owned groups.

7 Note

Owners of dynamic groups must have a global administrator, group administrator,


Intune administrator, or user administrator role to edit group membership rules. For
more information, see Create or update a dynamic group in Azure Active
Directory.

Action Description

microsoft.directory/groups/appRoleAssignments/update Update the groups.appRoleAssignments


property in Azure AD.

microsoft.directory/groups/basic/update Update basic properties on groups in


Azure AD.
Action Description

microsoft.directory/groups/delete Delete groups in Azure AD.

microsoft.directory/groups/members/update Update the groups.members property in


Azure AD.

microsoft.directory/groups/owners/update Update the groups.owners property in


Azure AD.

microsoft.directory/groups/restore Restore groups in Azure AD.

microsoft.directory/groups/settings/update Update the groups.settings property


in Azure AD.

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

1. Groups can only be created through work or school accounts. Personal


Microsoft accounts don't support groups.
2. All group-related operations in Microsoft Graph require administrator
consent.

Group types in Azure AD and Microsoft Graph


Azure Active Directory (Azure AD) supports the following types of groups.

Microsoft 365 groups


Security groups
Mail-enabled security groups
Distribution groups

7 Note

Microsoft also supports dynamic distribution groups which cannot be managed or


retrieved through Microsoft Graph.

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

Microsoft 365 groups ["Unified"] true true or false Yes

Security groups [] false true Yes

Mail-enabled security [] true true No


groups

Distribution groups [] true false No

For more information about groups, see the sections below. For more information about
groups in Azure AD, see compare groups in Azure AD.

Microsoft 365 groups


The power of Microsoft 365 groups is in its collaborative nature, perfect for people who
work together on a project or a team. They're created with resources that members of
the group share, including:

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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.

Settings for Microsoft 365 groups


Apart from configuring the standard group properties, you can also configure the
following settings for Microsoft 365 groups.

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.

Security groups and mail-enabled security


groups
Security groups are for controlling user access to resources. By checking whether a user
is a member of a security group, your app can make authorization decisions when that
user is trying to access some secure resources in your app. Security groups can have
users, other security groups, devices, and service principals as members.

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.

Object type Member of security group Member of Microsoft 365 group

User

Security group

Microsoft 365 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 Property is defined following this syntax: object.property . For example


user.department or device.accountEnabled .

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.

The following example shows a complete rule.

"membershipRule": "user.department -eq \"Marketing\"" .

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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

Dynamic membership rules requires the tenant to have at least an Azure AD


Premium P1 license for each unique user that is a member of one or more dynamic
groups.
Other types of groups
Microsoft 365 groups in Yammer are used to facilitate user collaboration through
Yammer posts. This type of group can be returned through a read request, but their
posts can't be accessed through the API. When Yammer posts and conversation feeds
are enabled on a group, default Microsoft 365 group conversations are disabled. To
learn more, see Yammer developer API docs.

Group search limitations for guest users in


organizations
Group search capabilities allow the app to search for any groups in an organization's
directory by performing queries against the /groups resource (for example,
https://graph.microsoft.com/v1.0/groups ). Both administrators and users who are
members have this capability; however, guest users don't.

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?.

Common use cases


Using Microsoft Graph, you can perform the following common operations on groups.
Use cases REST See also
resources

Create groups, manage group characteristics

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

Manage group membership

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

Why integrate with Microsoft 365 groups?


Groups form the foundation that enables user collaboration and integration across
services to support rich scenarios in task planning, teamwork, education, and more.
When you integrate with Microsoft 365 groups, your application can support millions of
users as they transition across various experiences in the Microsoft 365 suite and
beyond.

Create groups to facilitate teamwork across services


You can use the Microsoft Graph API to create, manage, or delete groups throughout
the lifecycle of collaboration. For example, you can do the following:

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

Enable members to indicate that a group is one of their favorites, or remove it


from their favorites if they choose.
Create, get, or delete group conversations from your custom application.

Schedule calendar events on the group calendar.

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.

Microsoft 365 groups and conversations in Outlook in the web

Enable a group for Microsoft Teams to allow group members to engage in


persistent chat.

Delete groups. When a group is deleted, all associated content is also deleted,
which prevents orphaned sites, conversations, or plans.

Manage group membership seamlessly


Microsoft 365 groups are collections of users who share access to resources in Microsoft
services or within your app. Because group membership is managed centrally, any
changes to membership affect all services associated with the group. You can use
Microsoft Graph to perform the following group membership tasks:

Add and remove members from an existing group.


Get a list of owners or a list of members for a group. This helps communicate who
has access to group content, or who might need to perform administrative duties,
such as renewing the group or approving a join request.
Designate groups as Public, where group content is visible to anyone in the same
organization, or Private, where group content is only visible to members, via the
update group operation.
Remove owners who are no longer participating in the ownership responsibilities
for a particular group from the list of group owners.

Establish and maintain group policy settings


As the number of groups created within an organization begins to grow, Microsoft
Graph supports the ability to govern the usage and lifecycle of the group. You can
enforce group policies across all groups within an organization. You can use the
Microsoft Graph API to:

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?

Groups API in Microsoft Graph v1.0


Groups API in Microsoft Graph beta

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.

The group resource exposes two properties, resourceBehaviorOptions and


resourceProvisioningOptions, to customize the behaviors and resources to be
provisioned upon group creation.

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 ).

Supported values for Description Default if not set


resourceBehaviorOptions

AllowOnlyMembersToPost Only group members Any user in the


can post conversations organization can post
to the group. conversations to the
group.

CalendarMemberReadOnly Members can view the Members can view and


group calendar in edit the group
Outlook but cannot calendar in Outlook.
make changes.

ConnectorsDisabled Changes made to the Changes made to the


group in Exchange group in Exchange
Online are not synced Online are synced back
back to on-premises to on-premises Active
Active Directory. Directory.

HideGroupInOutlook This group is hidden in All groups are visible


Outlook experiences. and discoverable in
Outlook experiences.

SubscribeMembersToCalendarEventsDisabled Members are not Members are not


subscribed to the subscribed to the
group's calendar events group's calendar
in Outlook. events.
Supported values for Description Default if not set
resourceBehaviorOptions

SubscribeNewGroupMembers Group members are Group members do


subscribed to receive not receive group
group conversations. conversations.

WelcomeEmailDisabled Welcome emails are not A welcome email is


sent to new members. sent to a new member
on joining the group.

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.

Supported values for Description Default if not


resourceProvisioningOptions set

Team Provision this group as a team in Microsoft The group is a


Teams. Additionally, this value can also be regular
added on group update through a PATCH Microsoft 365
operation, in order to provision a team from group without
an existing Microsoft 365 group. Teams
capabilities.

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

defined by Azure AD and are read-only.

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.

Only one setting is available in this collection.

Unless otherwise indicated, these features require an Azure AD P1 license.


Setting name Type Description

AllowGuestsToAccessGroups Boolean Indicates whether a guest user can have access


to Microsoft 365 groups and their data. This
setting doesn't require an Azure AD P1 license.

AllowGuestsToBeGroupOwner Boolean Indicates whether a guest user can be a


Microsoft 365 group owner.

AllowToAddGuests Boolean Indicating whether a Microsoft 365 group can


have guest users as members. This setting may
be overridden and become read-only if
EnableMIPLabels is true and a guest policy is
associated with the sensitivity label assigned to
the group. If this setting is false at the tenant-
level, it overrides the corresponding group-level
setting when it's true . To enable guest access for
only a few Microsoft 365 groups, set
AllowToAddGuests to be true at the tenant-
level, and then selectively disable this setting for
individual Microsoft 365 groups to exclude.

ClassificationDescriptions String A comma-delimited list of classification


descriptions. The value of
ClassificationDescriptions is only valid in this
format: "Value:Description" where Value
matches an entry in the ClassificationList setting.
This setting doesn't apply when
EnableMIPLabels is true . Maximum character
limit is 300 and commas can't be escaped.

ClassificationList String A comma-delimited list of values that can be


applied to classify Microsoft 365 groups. This
setting doesn't apply when EnableMIPLabels is
true . For more information, see SharePoint
"modern" sites classification.

CustomBlockedWordsList String Comma-separated string of phrases that users


won't be permitted to use in group names or
aliases. For more information, see Enforce a
naming policy for Microsoft 365 groups.

DefaultClassification String The classification that's used as the default


classification for a Microsoft 365 group if none
was specified during group creation. This setting
doesn't apply when EnableMIPLabels is true .
For more information, see SharePoint "modern"
sites classification.
Setting name Type Description

EnableGroupCreation Boolean Indicates whether non-admin users can create


Microsoft 365 groups. The default setting is
true . This setting doesn't require an Azure AD
P1 license. This setting corresponds to the Users
can create Microsoft 365 groups in Azure portals,
API or PowerShell setting in the group settings
menu in the Azure portal.

Note: The Users can create security groups in


Azure portals, API or PowerShell setting is
configured through the
allowedToCreateSecurityGroups property of the
defaultUserRolePermissions object of the
authorizationPolicy resource type.

EnableMSStandardBlockedWords Boolean Deprecated and retired.

EnableMIPLabels Boolean Indicates whether Microsoft information


protection sensitivity labels published in the
Microsoft Purview compliance portal can be
applied to Microsoft 365 groups. For more
information, see Assign Sensitivity Labels for
Microsoft 365 groups.

GroupCreationAllowedGroupId GUID Identifier of the security group for which the


members are allowed to create Microsoft 365
groups even when EnableGroupCreation is
false .

GuestUsageGuidelinesUrl String The URL of a link to the guest usage guidelines.

NewUnifiedGroupWritebackDefault Boolean A tenant-wide setting that assigns the default


value to the writebackConfiguration/isEnabled
property of new groups, if the property isn't
specified during group creation. This setting is
applicable when group writeback is configured in
Azure AD Connect. The default value is true .

Updating this setting to false changes the


default writeback behavior for new Microsoft 365
groups, but won't change
writebackConfiguration/isEnabled property for
existing Microsoft 365 groups. For more
information about this setting and the group's
writebackConfiguration property, see group
resource type
Setting name Type Description

PrefixSuffixNamingRequirement String Defines the naming convention configured for


Microsoft 365 group names and mail nicknames.
Maximum character limit is 64. For more
information, see Enforce a naming policy for
Microsoft 365 groups.

UsageGuidelinesUrl String A link to the Group Usage Guidelines. The default


is an empty value.

Group.Unified.Guest
The settings in this object specify whether guests can be added to all or specific
Microsoft 365 groups in the tenant.

Only one setting is available in this collection.

Setting name Type Description

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

In order to delegate identity and access management functions to Azure AD, an


application must be registered with an Azure AD tenant. When you register your
application with Azure AD, you're creating an identity configuration for your application
that allows it to integrate with Azure AD.

Why use applications and associated resources?


The Microsoft Graph APIs enable you to manage these resources and actions related to
applications in Azure Active Directory:

Application management - Azure AD must be configured to integrate with an


application. In other words, it needs to know what applications are using it as an
identity system. The process of keeping Azure AD aware of these applications, and
how it should handle them, is known as application management.
On-premises publishing - On-premises agents (or connectors for Application
Proxy) installed by a tenant administrator can be configured to route requests to a
particular published resource.
Service principal management - The local representation, or application instance,
of a global application object in a single tenant or directory. A service principal is a
concrete instance created from the application object and inherits certain
properties from that application object.
Synchronization - Azure Active Directory (Azure AD) identity synchronization (also
called provisioning) allows you to automate the creation, maintenance, and
removal of identities in the cloud.

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

For more information about applications, see the following articles:

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:

What is application management?


Authentication flows and application scenarios

On-premises publishing (preview)


Create and manage on-premises publishing profiles, which includes the creation of on-
premises agents and agent groups. You can use the on-premises publishing APIs in
Microsoft Graph to manage on-premises publishing profiles programmatically.

For more information about on-premises publishing, see the following articles:

Remote access to on-premises applications through Azure Active Directory's


Application Proxy
Using Azure AD Application Proxy to publish on-premises apps for remote users

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

Service principal management


To access resources that are secured by an Azure AD tenant, the entity that requires
access must be represented by a security principal. You can use the service principal APIs
in Microsoft Graph to manage service principals programmatically.

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:

Create, start, and stop synchronization jobs


Make changes to the synchronization schema for jobs
Verify the current synchronization status

For more information about synchronization, see the following articles:

Automate user provisioning and deprovisioning to applications with Azure AD


How provisioning works

To learn about using the synchronization APIs, see the following tutorials and their
associated APIs:

Configure provisioning using Microsoft Graph APIs


applicationTemplate
synchronizationTemplate
synchronizationJob
Automate SAML-based SSO app configuration with Microsoft Graph API
applicationTemplate
application
claimsMappingPolicy
servicePrincipal

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:

A working Azure AD tenant.


Sign in to Graph Explorer as a user in an Application Administrator role or a user
allowed to create and manage applications in the tenant.

Register an application with Azure AD

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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": []
}
}

The signInAudience property is assigned a default value of


AzureADandPersonalMicrosoftAccount . This configuration allows any user who is signed

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.

Configure other basic properties for your app


Least privilege delegated permission: Application.ReadWrite.All

You'll configure the following basic properties for the app.


Add tags for categorization in the organization. Also, use the HideApp tag to hide
the app from My Apps and the Microsoft 365 Launcher.
Add basic information including the logo, terms of service, and privacy statement.
Store contact information about 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];"
}

Limit app sign-in to only assigned identities


Least privilege delegated permission: Application.ReadWrite.All

HTTP

HTTP
PATCH https://graph.microsoft.com/v1.0/servicePrincipals/89473e09-0737-
41a1-a0c3-1418d6908bcd

{
"appRoleAssignmentRequired": true
}

Assign permissions to an app


While you can assign permissions to an app through the Azure portal, you also assign
permissions through Microsoft Graph by updating the requiredResourceAccess
property of the app object. You must pass in both existing and new permissions. Passing
in only new permissions overwrites and removes the existing permissions that haven't
yet been consented to.

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.

Least privilege delegated permission: Application.ReadWrite.All

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

Create app roles on an application object

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

Identify ownerless service principals and service


principals with one owner
Least privilege delegated permission: Application.ReadWrite.All

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

Assign an owner to an app


Least privilege delegated permission: Application.ReadWrite.All

In the following request, 8afc02cb-4d62-4dba-b536-9f6d73e9be26 is the object ID for a


user or service principal.

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"
}

Assign an owner to a service principal


Least privilege delegated permission: Application.ReadWrite.All

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:

Supported account types (Register an application) signInAudience (Manifest)

Accounts in this organizational directory only (Single tenant) AzureADMyOrg

Accounts in any organizational directory (Any Azure AD directory AzureADMultipleOrgs


- Multitenant)

Accounts in any organizational directory (Any Azure AD directory AzureADandPersonalMicrosoftAccount


- Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)

Personal Microsoft accounts only PersonalMicrosoftAccount

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.

Property AzureADMyOrg AzureADMultipleOrgs AzureADandPersonalMicrosoftAccount


and PersonalMicrosoftAccount
Property AzureADMyOrg AzureADMultipleOrgs AzureADandPersonalMicrosoftAccount
and PersonalMicrosoftAccount

Application ID URI Must be unique in Must be globally Must be globally unique


( identifierURIs ) the tenant unique
urn:// schemes aren't supported
urn:// schemes urn:// schemes are
are supported supported Wildcards, fragments, and query
strings aren't supported
Wildcards aren't Wildcards aren't
supported supported Maximum length of 120 characters

Query strings and Query strings and Maximum of 50 identifierURIs


fragments are fragments are
supported supported

Maximum length Maximum length of


of 255 characters 255 characters

No limit* on No limit* on number


number of of identifierURIs
identifierURIs

National clouds Supported Supported Not supported

Certificates ( keyCredentials ) Symmetric signing Symmetric signing Encryption and asymmetric signing
key key key

Client secrets No limit* No limit* If liveSDK is enabled: Maximum of


( passwordCredentials ) two client secrets

Redirect URIs ( replyURLs ) See Redirect


URI/reply URL
restrictions and
limitations for
more info.

API permissions No more than 50 No more than 50 Maximum of 50 resources per


( requiredResourceAccess ) APIs (resource APIs (resource apps) application and 30 permissions per
apps) from the from the same resource (for example, Microsoft
same tenant as tenant as the Graph). Total limit of 200 per
the application, no application, no more application (resources x
more than 10 APIs than 10 APIs from permissions).
from other other tenants, and
tenants, and no no more than 400
more than 400 permissions total
permissions total across all APIs.
across all APIs.
Property AzureADMyOrg AzureADMultipleOrgs AzureADandPersonalMicrosoftAccount
and PersonalMicrosoftAccount

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

Authorized client No limit* No limit* Total maximum of 500


applications
( preAuthorizedApplications ) Maximum of 100 client apps defined

Maximum of 30 scopes defined per


client

appRoles Supported Supported Not supported


No limit* No limit*

Front-channel logout URL https://localhost https://localhost is https://localhost is allowed,


is allowed allowed http://localhost fails

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

Display name Maximum length Maximum length of Maximum length of 90 characters


of 120 characters 120 characters

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

Be careful! Permissions granted programmatically are not subject to review or


confirmation. They take effect immediately.

Prerequisites
To complete these instructions, you need the following resources and privileges:

A working Azure AD tenant.


You'll run the requests in this article as a user. You must complete the following
steps:
Sign in to an app such as Graph Explorer or Postman as a user with privileges to
create applications in the tenant.
In the app you've signed in to, consent to the Application.Read.All and
AppRoleAssignment.ReadWrite.All delegated permissions on behalf of the
signed-in user. You don't need to consent on behalf of your organization.
Get the object ID of the client service principal to which you'll grant app roles. In
this article, the client service principal is identified by ID b0d9b9e3-0ecf-4bfd-
8dab-9273dd055a94 .

U Caution

Apps that have been granted the AppRoleAssignment.ReadWrite.All permission


should only be accessed by appropriate users.
Step 1: Get the appRoles of the resource service
principal
Before you can grant app roles, you must first identify the app roles to grant and the
resource service principal that exposes the app roles. App roles are defined in the
appRoles object of a service principal. In this article, you'll use the Microsoft Graph
service principal in the tenant as your resource service principal.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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"
}
]
}
]
}

Step 2: Grant an app role to a client service


principal
In this step, you'll grant your app an app role that's exposed by Microsoft Graph,
thereby creating an app role assignment. From Step 1, the object ID of Microsoft Graph
is 7ea9e944-71ce-443d-811c-71e8047b557a and the app role User.Read.All is identified
by ID df021288-bdef-4463-88db-98f22de89214 .

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

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/$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"
}
]
}

Step 3: Revoke an app role assignment from a


client service principal

Request

HTTP

HTTP

DELETE https://graph.microsoft.com/v1.0/servicePrincipals/7ea9e944-71ce-
443d-811c-
71e8047b557a/appRoleAssignedTo/47nZsM8O_UuNq5Jz3QValCxBBiqJea9Drc9CMK4Ru
_M

Response
HTTP

HTTP/1.1 204 No Content


Conclusion
You've learned how to manage app role grants for a service principal. This method of
granting permissions using Microsoft Graph is an alternative interactive consent and
should be used with caution.

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:

An active Azure AD tenant.


An API client such as Graph Explorer . Sign in as a user in an Application
Administrator role or a user who is allowed to create and manage applications in
the tenant.
A signed certificate that you'll use to authenticate the app. This article uses a self-
signed certificate for demonstration purposes. To learn how to create a self-signed
certificate, see Create a self-signed public certificate to authenticate your
application.

U Caution

The use of certificates is highly recommended over secrets; however, we don't


recommend using self-signed certificates. They can reduce the security bar of your
application due to various factors like use of an outdated hash and cipher suites or
lack of validation. We recommend procuring certificates from a well known trusted
certificate authority.

Step 1: Read the certificate details


To add a certificate programmatically using Microsoft Graph, you need the certificate's
key. You can optionally add the certificate's thumbprint.

[Optional] Get the certificate thumbprint


It's optional to add the certificate thumbprint to the request payload. If you want to add
the thumbprint, you can run the following PowerShell request to read the certificate's
thumbprint. This request assumes that you generated and exported the certificate to
your local drive.

Request

PowerShell

Get-PfxCertificate -Filepath "C:\Users\admin\Desktop\20230112.cer" | Out-


File -FilePath "C:\Users\admin\Desktop\20230112.cer.thumbprint.txt" ##
Replace the file path with the source of your certificate

Response
The output that's saved in the .txt file can be similar to the following.

PowerShell

Thumbprint Subject
---------- -------
5A126608ED1A1366F714A4A62B7015F3262840F1 CN=20230112

Get the certificate key


To read the certificate's key using PowerShell, run the following request.

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==

Step 2: Add the certificate details using


Microsoft Graph

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

HTTP/1.1 204 No Content

Step 3: Test app-only authentication


You can test the app-only authentication using Microsoft Graph PowerShell, as shown in
the following example.

Request
PowerShell

## Authenticate using the certificate thumbprint


Connect-MgGraph -ClientID cf34b10f-50fd-4167-acf6-4f08ddd4561b -TenantId
38d49456-54d4-455d-a8d6-c383c71e0a6d -CertificateThumbprint
52ED9B5038A47B9E2E2190715CC238359D4F8F73

## Authenticate using the certificate subject name


Connect-MgGraph -ClientID 588028ea-22c2-490e-8c6b-80cd06985e8c -TenantId
38d49456-54d4-455d-a8d6-c383c71e0a6d -CertificateName CN=20230113
Response
PowerShell

Welcome To Microsoft Graph!

To confirm that you're running the Microsoft Graph PowerShell session without a
signed-in user, run the following request.

PowerShell

Get-MgContext

The response is similar to the following.

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 .

Step 1: Create the application


Azure AD has a gallery that contains thousands of pre-integrated applications that you
can use as a template for your application. The application template describes the
metadata for that application. Using this template, you can create an instance of the
application and service principal in your tenant for management.

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.

Retrieve the gallery application template identifier


In this tutorial, you retrieve the identifier of the application template for AWS IAM
Identity Center (successor to AWS Single Sign-On) . Record the value of the id
property to use later in this tutorial.

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."
}
]
}

Create the application


Using the id value that you recorded for the application template, create an instance of
the application and service principal in your tenant. Record the value of the id property
of the application and the value of the id property for the service principal to use later in
this tutorial.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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": []
}
}

Step 2: Configure single sign-on


In this tutorial, you set saml as the single sign-on mode in the service principal. 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

{
"preferredSingleSignOnMode": "saml"
}

Response

HTTP

HTTP/1.1 204 No Content

Set basic SAML URLs


Using the id for the application that you recorded earlier, set the identifier URI and
redirect URI for AWS in the application object.

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

HTTP/1.1 204 No Content

Add app roles (Optional)


If the application requires the role information in the token, add the definition of the
roles in the application object.

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

HTTP/1.1 204 No Content

Step 3: Configure claims mapping

Create a claims mapping policy


In addition to the basic claims, configure the following claims for Azure AD to emit in
the SAML token:

Claim name Source

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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

HTTP/1.1 204 No Content

Step 4: Configure a signing certificate


You need a self-signed certificate that Azure AD can use to sign a SAML response. You
can use your own certificate or you can use the following example.

Option 1: Create a signing certificate in Azure AD


Using the id of the service principal that you created, create a new certificate and add it
to the service principal.

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"
}

Option 2: Create a custom signing certificate


You can use the following PowerShell and C# scripts to get a self-signed certificate for
testing. You will then need to manipulate and pull the values you need manually using
other tools. Use the best security practice from your company to create a signing
certificate for production.

PowerShell script
PowerShell

Param(
[Parameter(Mandatory=$true)]
[string]$fqdn,
[Parameter(Mandatory=$true)]
[string]$pwd,
[Parameter(Mandatory=$true)]
[string]$location
)

if (!$PSBoundParameters.ContainsKey('location'))
{
$location = "."
}

$cert = New-SelfSignedCertificate -certstorelocation


cert:\currentuser\my -DnsName $fqdn
$pwdSecure = ConvertTo-SecureString -String $pwd -Force -AsPlainText
$path = 'cert:\currentuser\my\' + $cert.Thumbprint
$cerFile = $location + "\\" + $fqdn + ".cer"
$pfxFile = $location + "\\" + $fqdn + ".pfx"

Export-PfxCertificate -cert $path -FilePath $pfxFile -Password


$pwdSecure
Export-Certificate -cert $path -FilePath $cerFile

Add a custom signing key

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

HTTP/1.1 204 No Content

Activate the custom signing key


You need to set the preferredTokenSigningKeyThumbprint property of the service
principal to the thumbprint of the certificate that you want Azure AD to use to sign the
SAML response.

Request

HTTP

HTTP

PATCH https://graph.microsoft.com/v1.0/servicePrincipals/a750f6cf-2319-
464a-bcc3-456926736a91
Content-type: application/json

{
"preferredTokenSigningKeyThumbprint":
"A7D3C4626B8A84FDA868CCC67D274D402FFD0A10"
}

Response

HTTP

HTTP/1.1 204 No Content

Step 5: Assign users


Create a user account
For this tutorial, you create a user account that is added to the application. In the
request body, change contoso.com to the domain name of your tenant. You can find
tenant information on the Azure Active Directory overview page. Record the id of the
user to be used later in this tutorial.

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]"
}

Assign a user to the application


Assign the user that you created to the service principal and assign the Admin,WAAD app
role.
In the request body, provide these values:

principalId - The id of the user account that you created.


appRoleId - The id of the Admin,WAAD app role that you added.
resourceId - The id of the service principal.

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>

Step 7: Clean up resources


In this step, you remove the resources that you created.

Delete the application


Delete the application that you created.

Request

HTTP

HTTP
DELETE https://graph.microsoft.com/v1.0/applications/a9be408a-6c31-4141-
8cea-52fcd4a61be8

Response

HTTP

HTTP/1.1 204 No Content

Delete the user account


Delete the MyTestUser1 user account.

Request

HTTP

HTTP

DELETE https://graph.microsoft.com/v1.0/users/040f9599-7c0f-4f94-aa75-
8394c4c6ea9b

Response

HTTP

HTTP/1.1 204 No Content

Delete the claims mapping policy


Delete the claims mapping policy.

Request

HTTP
HTTP

DELETE
https://graph.microsoft.com/v1.0/policies/claimsMappingPolicies/a4b35718
-fd5e-4ca8-8248-a3c9934b1b78

Response

HTTP

HTTP/1.1 204 No Content

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

The response objects shown might be shortened for readability.

Step 1: Create a custom application


To configure Application Proxy for an app using the API, you first create a custom
application, and then update the application's onPremisesPublishing property to
configure the App Proxy settings. In this tutorial, you use an application template to
create an instance of a custom application and service principal in your tenant for
management. The template ID for a custom application is 8adf8e6e-67b2-4cf2-a259-
e3dc5476c621 .

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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

HTTP/1.1 204 No content

Update the following properties in the request body:

internalUrl - Set to the internal URL.


externalUrl - Set to the external URL.
All other values can be configured as needed. For details, see Add an on-premises
app to Azure AD.

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

HTTP/1.1 204 No content

Step 3: Assign a connector group to the


application

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
}

Assign a connector to the connectorGroup

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

HTTP/1.1 204 No content

Assign the application to the connectorGroup

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

HTTP/1.1 204 No content

Step 4: Configure single sign-on


This application uses Integrated Windows Authentication (IWA). To configure IWA, set
the single sign-on properties for onPremisesPublishing.

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

HTTP/1.1 204 No content

Step 5: Assign a user

Retrieve the appRole for the application


Get the app roles for the application using the id of the service principal. Record the id
of the User app role to be used in the next step.

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
},
]
}

Create a user account


For this tutorial, you create a user account that is assigned to the app role. In the
request body, change contoso.com to the domain name of your tenant. You can find
tenant information on the Azure Active Directory overview page. Record the id of the
user account to be used in the next step.

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]"
}

Assign the user to the application


In the following example, replace the values of these properties:

principalId with the id of the user


appRoleId with the id of the app role
resourceId with the id of the service principal

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"
}

Step 6: Test access to the application


Test the application by visiting the External URL configured for the app on your browser
and then sign in with your test user. You should be able to log into the app and access
the application.

Step 7: Clean up resources


The resources that you created in this tutorial are not intended to be used in a
production environment. In this step, you remove the resources that you created.

Delete the user account


Delete the MyTestUser1 user account.

Request
HTTP

HTTP

DELETE https://graph.microsoft.com/v1.0/users/4628e7df-dff3-407c-a08f-
75f08c0806dc

Response

HTTP

No Content - 204

Delete the application

Request

HTTP

HTTP

DELETE https://graph.microsoft.com/v1.0/applications/bf21f7e9-9d25-4da2-
82ab-7fdd85049f83

Response

HTTP

No Content - 204

Delete the connector group

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.

Overview of steps for using Microsoft Graph APIs to automate provisioning


configuration

Step Details

Step 1. Create the gallery application Sign-in to the API client


Retrieve the gallery application template
Create the gallery application

Step 2. Create provisioning job based on Retrieve the template for the provisioning
template connector
Create the provisioning job

Step 3. Authorize access Test the connection to the application


Save the credentials

Step 4. Start provisioning job Start the job

Step 5. Monitor provisioning Check the status of the provisioning job


Retrieve the provisioning logs

Step 1: Create the gallery application

Sign in to Microsoft Graph Explorer (recommended),


Postman, or any other API client you use
1. Start Microsoft Graph Explorer.
2. Select the "Sign-In with Microsoft" button and sign in using Azure AD global
administrator or App Admin credentials.
3. Upon successful sign-in, you'll see the user account details in the left-hand pane.
Retrieve the gallery application template identifier
Applications in the Azure AD application gallery each have an application template that
describes the metadata for that application. Using this template, you can create an
instance of the application and service principal in your tenant for management.
Retrieve the identifier of the application template for AWS Single-Account Access and
from the response, record the value of the id property to use later in this tutorial.

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"
],
}
}

Step 2: Create the provisioning job based on


the template

Retrieve the template for the provisioning connector


Applications in the gallery that are enabled for provisioning have templates to
streamline configuration. Use the request below to retrieve the template for the
provisioning configuration. Note that you will need to provide the ID. The ID refers to
the preceding resource, which in this case is the servicePrincipal resource.

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

Test the connection to the application


Test the connection with the third-party application. The following example is for an
application that requires a client secret and secret token. Each application has its own
requirements. Applications often use a base address in place of a client secret. To
determine what credentials your app requires, go to the provisioning configuration page
for your application, and in developer mode, click test connection. The network traffic
will show the parameters used for credentials. For a full list of credentials, see
synchronizationJob: validateCredentials. Most applications, such as Azure Databricks,
rely on a BaseAddress and SecretToken. The BaseAddress is referred to as a tenant URL
in the Azure portal.

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

HTTP/1.1 204 No Content

Save your credentials


Configuring provisioning requires establishing a trust between Azure AD and the
application. Authorize access to the third-party application. The following example is for
an application that requires a client secret and a secret token. Each application has its
own requirements. Review the API documentation to see the available options.

Request

HTTP

PUT
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/secr
ets

{
"value": [
{
"key": "ClientSecret", "value": "xxxxxxxxxxxxxxxxxxxxx"
},
{
"key": "SecretToken", "value": "xxxxxxxxxxxxxxxxxxxxx"
}
]
}

Response

HTTP

HTTP/1.1 204 No Content

Step 4: Start the provisioning job


Now that the provisioning job is configured, use the following command to start the
job.

Request

HTTP

POST
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/jobs
/{jobId}/start
Response

HTTP

HTTP/1.1 204 No Content

Step 5: Monitor provisioning

Monitor the provisioning job status


Now that the provisioning job is running, use the following command to track the
progress of the current provisioning cycle as well as statistics to date such as the
number of users and groups that have been created in the target system.

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"
}
]
}

Monitor provisioning events using the provisioning logs


In addition to monitoring the status of the provisioning job, you can use the
provisioning logs to query for all the events that are occurring. For example, query for a
particular user and determine if they were successfully provisioned.

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 token should contain the following claims:

aud - Audience needs to be 00000003-0000-0000-c000-000000000000 which is the

appId of the Microsoft Graph service principal.


iss - Issuer needs to be the object ID of the application that's making the call (not

the appId).
nbf - Not before time.

exp - Expiration time should be "nbf" + 10 mins.

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>";

// Get signing certificate


X509Certificate2 signingCert = new
X509Certificate2(pfxFilePath, password);

// audience
string aud = $"00000003-0000-0000-c000-000000000000";

// aud and iss are the only required claims.


var claims = new Dictionary<string, object>()
{
{ "aud", aud },
{ "iss", objectId }
};

// token validity should not be more than 10 minutes


var now = DateTime.UtcNow;
var securityTokenDescriptor = new SecurityTokenDescriptor
{
Claims = claims,
NotBefore = now,
Expires = now.AddMinutes(10),
SigningCredentials = new
X509SigningCredentials(signingCert)
};

var handler = new JsonWebTokenHandler();


var x = handler.CreateToken(securityTokenDescriptor);
Console.WriteLine(x);
}
}
}

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:

Add a key or remove a key from your application.


Add a key or remove a key from your service principal.
Configure synchronization with custom
target attributes
Article • 03/09/2023

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.

Find the service principal object by display


name
The following example shows how to find a service principal object with the display
name Salesforce.

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"
}
]
}

The {servicePrincipalId} is 167e33e9-f80e-490e-b4d8-698d4a80fb3e .

List synchronization jobs in the context of the


service principal
The following example shows you how to get the jobId that you need to work with.
Generally, the response returns only one job.

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": {}
}
]
}

The {jobId} is SfSandboxOutDelta.e4bbf44533ea4eabb17027f3a92e92aa .

Get the synchronization schema


The following example shows how to get the synchronization schema.

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"
}
]
}
]
}

Add a definition for the officeCode attribute


and a mapping between attributes
Use a plain text editor of your choice (for example, Notepad++ or JSON Editor
Online ) to:

1. Add an attribute definition for the officeCode attribute.

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.

2. Add an attribute mapping between officeCode and extensionAttribute10 .


Under synchronizationRules, find the rule that specifies Azure AD as the
source directory, and Salesforce.com as the target directory
( "sourceDirectoryName": "Azure Active Directory", "targetDirectoryName":
"salesforce.com" ).
In the objectMappings of the rule, find the mapping between users
( "sourceObjectName": "User", "targetObjectName": "User" ).
In the attributeMappings array of the objectMapping, add a new entry, 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"
}
]
}

Save the modified synchronization schema


When you save the updated synchronization schema, make sure that you include the
entire schema, including the unmodified parts. This request will replace the existing
schema with the one that you provide.

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.

Find the service principal object by display


name
The following example shows how to find a service principal object with the display
name "Salesforce Sandbox".

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"
}
]
}

The {servicePrincipalId} is 60443998-8cf7-4e61-b05c-a53b658cb5e1 .

List synchronization jobs in the context of the


service principal
The following example shows you how to get the jobId that you need to work with.
Generally, the response returns only one job.

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": {}
}
]
}

The {jobId} is SfSandboxOutDelta.e4bbf44533ea4eabb17027f3a92e92aa .

Find the name of the directory extension


attribute you need
You'll need the full name of the extension attribute. If you don't know the full name
(which should look similar to extension_9d98asdfl15980a_Nickname), see the following
information about directory extension attributes and how to inspect them:

Extending the Azure AD directory schema with custom properties


Directory schema extensions | Graph API concepts

Get the synchronization schema


The following example shows how to get the synchronization schema.

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"
}
]
}
]
}

Add a definition for the directory extension


attribute, and a mapping between the
attributes
Use a plain text editor of your choice (for example, Notepad++ or JSON Editor
Online ) to:

1. Add an attribute definition for the extension_9d98asdfl15980a_Nickname attribute.

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.

2. Add an attribute mapping between extension_9d98asdfl15980a_Nickname and


CommunityNickname.

Under synchronizationRules, find the rule that specifies Azure AD as source


directory, and Salesforce.com as the target directory ( "sourceDirectoryName":
"Azure Active Directory", "targetDirectoryName": "salesforce.com" ).
In the objectMappings of the rule, find the mapping between users
( "sourceObjectName": "User", "targetObjectName": "User" ).
In the attributeMappings array of the objectMapping, add a new entry, 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"
},
]
}

Save the modified synchronization schema


When you save the updated synchronization schema, make sure that you include the
entire schema, including the unmodified parts. This request will replace the existing
schema with the one that you provide.

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:

An ISV building intelligent applications for any Microsoft 365 customer.


An enterprise developer building intelligent applications for users inside of your
organization that access Microsoft 365 data.

Access to data at scale


Rich applications require access to large amounts of data, often from many users in your
organization at once. For this reason, Microsoft Graph’s standard, transactional data
model has a tendency to throttle large datasets. Data delivery requires a complex
infrastructure and thousands of API calls, any of which might be throttled due to
resource limitations.

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.

Granular data consent


In the traditional Microsoft Graph consent model, an administrator or user can only
grant or deny an application’s request to access specific, predefined sets of entities. For
example, a request for Mail.Read includes read access to a fixed set of entities that
support Outlook mail, including entire message instances with all the relevant
properties.

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.

Data security and governance


Microsoft is facilitating rich, connected communication between Microsoft Graph Data
Connect and Azure that respects customer data. Data Connect supports all Azure-native
service capabilities, such as encryption, geo-fencing, auditing, and policy enforcement.

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.

Azure Active Directory

Dataset name Description Sample and Billing


Schema

BasicDataSet_v0.User_v0 Contains user information Sample Free


(DisplayName, Schema
UserPrincipalName, and other
information).

BasicDataSet_v0.User_v1 Contains user information. Sample Free


Schema

BasicDataSet_v0.Manager_v0 Contains user information for the Sample Free


manager of each user. Schema

BasicDataSet_v0.DirectReport_v0 Contains user information about Sample Free


the employees that directly report Schema
to each user.

Outlook and Exchange Online

Dataset name Description Sample and Billing


Schema
Dataset name Description Sample and Billing
Schema

BasicDataSet_v0.CalendarView_v0 Contains the Sample Paid


events from the Schema
Calendar view.

BasicDataSet_v0.Contact_v0 Contains the Sample Paid


available Schema
information from
each user’s
address book.

BasicDataSet_v0.Contact_v1 Contains contact Sample Paid


information from Schema
each user's
address book.

BasicDataSet_v0.Event_v0 Contains the Sample Paid


information from Schema
a user’s calendar
events.

BasicDataSet_v0.Event_v1 Contains the Sample Paid


events in each Schema
user's calendar.

BasicDataSet_v0.Inbox_v1 Contains the mail Sample Paid


folders from each Schema
user's inbox.

BasicDataSet_v0.MailboxSettings_v0 Contains the Sample Free


mailbox settings Schema
of each user.

BasicDataSet_v0.MailFolder_v0 Contains the mail Sample Paid


folders from each Schema
user's mailbox.

BasicDataSet_v0.Message_v0 Contains the email Sample Paid


messages from a Schema
user’s mailbox.

BasicDataSet_v0.Message_v1 Contains the email Sample Paid


message in each Schema
user's mailbox.

BasicDataSet_v0.SentItem_v0 Contains the Sample Paid


messages sent Schema
from each user's
mailbox.
Dataset name Description Sample and Billing
Schema

BasicDataSet_v0.SentItem_v1 Contains the Sample Paid


message sent Schema
from each user's
mailbox.

BasicDataSet_v0.TodoTaskFolders_v0 Contains all task Sample Paid


folders in the Schema
user's mailbox.

BasicDataSet_v0.TodoTasks_v0 Contains all the Sample Paid


tasks in the Schema
signed-in user's
mailbox.

BasicDataSet_v0.OutlookGroupConversations_v0 Contains the Sample Paid


message sent Schema
from each user's
mailbox.

Microsoft Teams

Dataset name Description Sample and Billing


Schema

BasicDataSet_v0.TeamChat_v1 Contains Sample Paid


Teams chat Schema
messages
for one-on-
one and
group chat
messages.
This dataset
excludes chat
messages
explicitly
deleted by
users.

BasicDataSet_v0.TeamsCallRecords_v1 Contains Sample Paid


activity Schema
records from
Teams calls
and
meetings.
Dataset name Description Sample and Billing
Schema

BasicDataSet_v0.TeamsChannelDetails_v0 Contains Sample Paid


details about Schema
Channels in a
team.

BasicDataSet_v0.TeamsStandardChannelMessages_v0 Contains Sample Paid


channel posts Schema
and messages
from
Standard
Channels in
Teams.

BasicDataSet_v0.TeamsTranscript_v1 Contains Sample Paid


transcripts Schema
from calls and
meetings in
Teams when
the transcript
is enabled for
a meeting or
a call.

Microsoft Groups

Dataset name Description Sample and Billing


Schema

BasicDataSet_v0.GroupDetails_v0 Contains a Teams Chat Group Sample Free


details. Schema

BasicDataSet_v0.GroupMembers_v0 Contains a Teams Chat Group Sample Free


member details. Schema

BasicDataSet_v0.GroupOwners_v0 Contains the Teams Chat Sample Free


Group owners' details. Schema

OneDrive and SharePoint Online


Please consider that these datasets are available after 48 hours (about two days). For
example, you can query data for 07/01 starting on 07/03.
The data available is from the last 21 days (about three weeks). For example, if you
would like to query data for 07/01, you can do so from 07/03 to 07/24.

Dataset name Description Sample and Billing


Schema

DocumentSharingDataset_v0_Preview Contains information about Sample Free


sharing permissions of Schema
documents.

SharePointSitesDataset_v0_Preview Contains information about Sample Free


SharePoint sites. Schema

SharePointGroupsDataset_v0_Preview Contains SharePoint group Sample Free


information, including details Schema
about group members.

Viva Insights

Dataset name Description Sample and Billing


Schema

VivaInsightsDataset_v0 Contains Viva Insights Sample Requires Viva Insights


metrics. Schema license

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.

Office region Azure region

Asia-Pacific East Asia


Southeast Asia
Office region Azure region

Australia Australia East


Australia Southeast

Europe North Europe


West Europe

North America Central US


East US
East US 2
North Central US
South Central US
West Central US
West US
West US 2

United Kingdom UK South


UK West

Canada (CAN) Canada Central


Canada East

Japan (JPN) Japan West


Japan East

India (IND) South India


Central India

Korea (KOR) Korea Central


Korea South

Switzerland (CHE) Switzerland North

Germany (DEU) Germany West Central

Norway (NOR) Norway East

France (FRA) France Central

UAE (UAE) UAE North


Sinks
Sinks are the output location that Azure Synapse or Azure Data Factory uses to place
data in Azure storage. Microsoft Graph Data Connect supports the following sink
storage types:

Azure Data Lake Storage Gen1


Azure Data Lake Storage Gen2
Azure Storage Blob
Azure SQL DB (mapping data flows only)

The following characteristics apply to sinks:

Service Principal authentication is the only supported authentication mechanism


for all sink types in a copy activity with Microsoft 365 as the source.

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.

Area Copy Activity Mapping data flows

Output data formats JSON JSON, Parquet


supported

Data transformation Requires additional transformation step Supports inline


(normalization/flattening/etc.) in the ADF/Synapse pipeline transformations
Area Copy Activity Mapping data flows

Supported data sinks ADLS gen2, Azure Blob ADLS gen2, Azure
Blob, Azure SQL DB

Azure VNET IR Not supported Supported

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:

Azure Policy built-in definitions for Azure Storage


Introduction to Azure Data Lake Storage Gen2
Azure Policy built-in definitions for Azure Data Lake Storage Gen1

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.

There is no charge for extraction of objects from the following datasets:

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:

All users within the organization


Up to 10 groups of users within the organization
A set of users based on a predicate consisting of Azure Active Directory user
properties

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

to limit the selection to one user, you can use https://graph.microsoft.com/v1.0/users?


$filter=mail eq '[email protected]' .

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.

The following datasets require a filter to be provided on one of the corresponding


DateTime properties.

Dataset name Properties that support filtering

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

Pipelines requesting BasicDataSet_v0.CalendarView_v0 also require a DateTime


filter, but no dateFilterColumn is specified in the SourceDataSet. However, a
startTime and endTime are required, and only events that begin after the
startTime and finish before the endTime are provided.

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:

Requestor: The user who requested the pipeline.


Duration: If approved, how long the approval persists, which is always 4320 hours
(6 months).
Reason: Reason for the request, typically "An app installed for your organization
requires approval for access to Office 365 Data."
Requested at: The DateTime of the request.
Request id: The ID of the request, used for approval purposes.
DataTable: The data set being extracted (for example, Sent Items).
Columns: The list of columns being extracted from the data table (for example,
SentDateTime).
AllowedGroups: The group or groups of users against whom the pipeline is
extracting data. If the list of groups is empty, the pipeline is requesting access to
data from all users in the tenant.
User Scope Query: The predicate used to filter out users. This only applies if the
request is for all users in the tenant. If this is empty, no filter is applied.
OutputUri: The output path in which the extracted data is stored.
SourceTenantId: The tenant ID from which data is being extracted.
InstallerIdentity: The identity of the app installer.

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.

Approve, deny, and revoke requests by using PowerShell


Use the following steps to interact with a request by using the Exchange Online
PowerShell module:

1. Install the Exchange Online PowerShell module. For installation instructions, see
Connect to Exchange Online PowerShell using multi-factor authentication.

2. Connect to Exchange Online PowerShell by using multi-factor authentication


(MFA). For instructions, see Connect to Exchange Online PowerShell using multi-
factor authentication.

7 Note

Note: You do not need to enable multi-factor authentication for your


organization to use these steps while connecting to Exchange Online
PowerShell. Connecting with MFA creates an OAuth token that is used by PAM
for signing your requests.

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

4. Find all pending requests.

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

Get-ElevatedAccessRequest | ?{$_.RequestStatus -eq 'Pending'}

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

Get-ElevatedAccessRequest -RequestId ($requestId).Context |


ConvertFrom-Json

You get a response similar to the following:

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

Approve-ElevatedAccessRequest -RequestId $requestId -Comment "Yay!!"


Deny-ElevatedAccessRequest -RequestId $requestId -Comment "Nay!!"

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

$request = Get-ElevatedAccessRequest -RequestId


$hash = $request.Context
$hash["DenyList"] = <Object ID of denied user group>;
Approve-ElevatedAccessRequest -RequestId $requestId -Comment "Yay!!" -
RequestContext $hash
Deny-ElevatedAccessRequest -RequestId $requestId -Comment "Nay!!"

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

Revoke-ElevatedAccessAuthorization -Comment "Revoking this request!" -


RequestId $requestId

You get a response similar to the following:

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

Approve, deny, and revoke requests by using the PAM


user experience
Use the following steps to interact with a request by using the PAM user experience:

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.

Dataset name Columns used for deny list-based scrubbing

BasicDataSet_v0.Message_v0 Sender, From, ToRecipients, CcRecipients, BccRecipients


BasicDataSet_v0.Message_v1

BasicDataSet_v0.SentItem_v0 Sender, From, ToRecipients, CcRecipients, BccRecipients


BasicDataSet_v0.SentItem_v1

BasicDataSet_v0.Event_v0 Organizer, Attendees


BasicDataSet_v0.Event_v1

BasicDataSet_v0.Contact_v0 EmailAddresses
BasicDataSet_v0.Contact_v1

BasicDataSet_v0.CalendarView_v0 Organizer, Attendees


See also
Data Connect frequently asked questions
Use Microsoft Graph Data Connect to
define the scope of a dataset
Article • 05/02/2023

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.

Scope selection in Microsoft Graph Data


Connect
You can scope Microsoft Graph Data Connect datasets by users or by groups. The
following sections provide details about the scope options for each.

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.

The following are the options for user-scoped datasets:

* **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.

The following are the options for group-scoped datasets:

* **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.

Dataset Microsoft Distribution Security Mail-enabled


365 group group group security group

TeamsStandardChannelMessages Yes* No No No

TeamsChannelDetails_v0 Yes* No No No

OutlookGroupConversations Yes No No No

GroupDetails Yes Yes Yes Yes

GroupMembers Yes Yes Yes Yes

GroupOwners Yes Yes** Yes** Yes

Viva Insights NA NA NA NA

OneDrive and SharePoint Online NA NA NA NA

All other datasets Yes Yes Yes Yes

*For Teams datasets, Microsoft 365 groups must also be Teams-enabled.

**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.

Search for and verify group types


Use the following steps to search for the types of groups in your tenant to help you
determine what is compatible with the type of scope you want to select:
1. Sign in to your ADF portal, select your tenant, and choose Source.

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.

Is Microsoft Graph Data Connect right for me?


Microsoft Graph Data Connect and Microsoft Graph APIs provide access to the same
underlying data but in very different ways. Microsoft Graph Data Connect is designed to
extract large amounts of datasets in bulk, scalable to your entire organization; while
Microsoft Graph APIs are suitable for accessing small amount of data from selected
users and groups in your organization.

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.

What are some scenarios that companies use


Microsoft 365 data for?
There are any number of use cases that can be powered by Microsoft 365 data. The
following are some top scenarios that customers are interested in:

Customer Relationship Analytics: For commercial business leaders, go beyond


traditional CRM insights and understand customer interactions and relationships
based on communication and collaboration patterns.

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.

People Productivity Analytics: For driving transformation, export your Viva


productivity metrics, so you can convert insights into solutions with digital
adoption, smart meetings and content, hybrid workplaces, and cultural change.

How do Viva Insights and Microsoft Graph Data


Connect differ?
Viva Insights and Microsoft Graph Data Connect are complementary. Although both rely
on Microsoft 365, Viva Insights and Data Connect serve different audiences and needs.

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.

Is there any initial overhead with Microsoft


Graph Data Connect?
Because Data Connect is designed to extract large amounts of data in bulk, some
overhead is incurred before the data can be extracted. This overhead is around 45
minutes, which means that all pipelines take at least that long regardless of the data
size. If the initial overhead is too long for your use case, please reach out to the
Microsoft Graph Data Connect team.

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.

In what regions is Microsoft Graph Data


Connect available?
Microsoft Graph Data Connect is currently available in multiple regions across the
following geographies: North America, Europe, Asia Pacific, United Kingdom/Great
Britain, and Australia. Other regions will be available in the future.

For a list of Office to Azure regions and mappings, see Dataset, regions and sinks.

What datasets are available through Microsoft


Graph Data Connect?
The following types of datasets are available:

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).

Cleaned: Datasets generated by either normalization and de-duplication from


basic datasets, or datasets created from user activity or behavior signals in
Microsoft 365 (for example, SharePoint, Office 365 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).

Multiple datasets for each of the following are available:

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.

Which datasets are in preview and which are


generally available?
Datasets for the OneDrive/SharePoint and Viva Insights are currently available for
customers in preview or for those who have the Viva Insights license, respectively.

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 .

There is no charge for extraction of objects from the following datasets:

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

How is billing calculated?


Microsoft Graph Data Connect charges customers on a monthly basis and also does
fractionable rounding up when calculating the bill. Each pipeline run is billed separately.

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.

What can I do if a dataset is not yet supported


for my tenant?
For datasets like OneDrive/SharePoint and Viva Insights, make sure that you meet the
criteria described in Datasets, regions, and sinks. These datasets are only available to
customers who have opted in for them explicitly.

For questions, contact the Microsoft Graph Data Connect team.

What scenarios is Microsoft Graph Data


Connect best for?
Organizations that can tap into the large datasets that power their productivity tools can
gain tremendous insights into the challenges and opportunities they might encounter.
Customers build applications across multiple scenarios, such as organization networks
for people productivity nalytics, information oversharing for security and compliance
analytics, seller relationship strengths for customer relationship analytics, and more.

Is it possible for my data to stay within the


organization's subscription with Microsoft
Graph Data Connect?
Microsoft Graph Data Connect respects your organizational tenant boundary when
delivering your requested datasets. Both Azure resources and Microsoft 365 services
must be located within the same Azure AD tenancy to access your Microsoft 365
dataset. Cross-tenant dataset access is not available today.
Are service principals required with Microsoft
Graph Data Connect?
When creating the Azure Synapse or Data Factory pipeline, you have to provide a service
principal to the Microsoft 365 linked service. In Azure, a service principal is a security
identity that represents an application/service (as opposed to a user). Microsoft Graph
Data Connect uses this service principal as its identity when getting authorized access to
your Microsoft 365 data.

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.

How can I check for pending Privileged Access


Management (PAM) requests?
Before Microsoft Graph Data Connect can copy your data, an administrator must
approve a Privileged Access Management (PAM) request. PAM is the mechanism used to
authorize your data pipeline access to the data in Microsoft 365.

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).

How can I approve PAM requests via the


Microsoft 365 admin center?
To approve using the PAM UX, visit the PAM interface in the Microsoft 365 admin center.
The admin center provides an easy and user-friendly way to view and
approve/deny/revoke PAM requests.

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.

Use the following steps to approve or deny a PAM request:

1. Sign in the PAM interface at Microsoft 365 admin center .


2. On the right pane, click Settings > Org Settings > Services > Microsoft Graph
Data Connect.
3. Locate the request.
4. Review the request details.
5. Add deny list scrubbing if needed.
6. Approve or deny the request.

For more details, see the Data Connect quick start.

Will every pipeline run trigger a new consent


request?
As long as the scope of the data being extracted remains the same for datasets,
columns, users, etc, the pipeline run will NOT trigger a new consent request. Instead, the
pipeline will use the approved consent which will last for 6 months. Running a pipeline
with the same scope for different dates will NOT trigger a new consent either.
How do I trigger a new consent request?
A new consent request will be triggered if the scope of data changes-- such as adding
new dataset, selecting more columns, or adding other users. A new consent can also be
triggered when changing the pipeline or activity name in Azure Synapse or Azure Data
Factory.

Why do I need a second user to approve PAM


requests?
When you request a dataset pipeline run, Microsoft Graph Data Connect service will
verify and then trigger a PAM approval request if needed. The request is sent to the
approver group defined for the tenant when enabling Microsoft Graph Data Connect in
the Microsoft Admin Center.

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.

Can I deduplicate emails when needed?


When you extract emails from the Message dataset, there are often multiple JSON
objects for the same email. These duplicates exist because when an email is sent to
multiple people, there is a copy of the email in every recipient's mailbox. Because the
dataset is extracted from every mailbox, it contains all copies across users. In some
scenarios, it might be necessary to keep every copy, but in others, you might want to
remove the duplicates.

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.

Is hybrid mode tenant setup supported?


If your Microsoft 365 setup has some users in Exchange Online and some users in
Exchange on-premises, then the users who are in Exchange on-premises would not be
supported. Unfortunately, we do not currently support Data Connect for Exchange on-
premises users.

Are resource accounts supported?


We don't currently support access to messages or events from resource accounts.

Why do I sometimes see multiple files per ADF


pipeline run but other times see only one file
per run?
Microsoft Graph Data Connect takes the user list for each pipeline run and then
distributes the dataset extraction and curation across multiple jobs that run in parallel.
For each parallel run, one output file is generated in the data sink defined by you. In
some cases, if the user list is small, they might be mapped into one extraction and
curation job, and in those cases only one output file would be generated in the data
sink.
Troubleshoot Microsoft Graph Data
Connect
Article • 04/29/2023

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.

For more questions, reach out to the Data Connect team.

Issues with service principal check when


running your first pipeline
If you're having issues running your pipelines for the first time, verify that you have
defined the owners for the Source Linked Service as follows:

The service principal's owner must be a valid user account within the tenant, not
another service principal.

The owner’s account must have:

A valid mailbox, either via an Exchange Online license or an Exchange Online


plan within an Office 365 or Microsoft 365 license.

An Office 365 or Microsoft 365 E5 subscription assigned. No specific services


within the license need to be enabled unless the user does not have a separate
Exchange Online license, in which case the Exchange Online plan must be
enabled.
Note: This account does not need the Global Admin role enabled. This is only
required for Approver accounts that approve requests through the admin
center.

Because Data Connect uses the Privilege Access Management system to


generate consent requests, E5 licenses are required. For details, see Integrate
with PAM and Get started with privileged access management.

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 .

Multi-geo tenant extraction issues


Sometimes, customers might want to add other regions to their pipelines, especially
larger customers with multi-geo tenants. While multi-geo tenants can still use Microsoft
Graph Data Connect, be aware that when customers request data, they can only extract
data for one region. Customers cannot use one pipeline to extract data from multiple
regrions. Data Connect enforces this rule for the privacy and security of a customer's
tenant users.

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.

Aggregating mutliple JSON file outputs


To combine files:

1. Add a new Copy data activity after the extraction.


2. Set the source of the new activity to the location where you extracted the files
(Azure storage), set the file format to JSON, and specify Wildcard file path as the
path type.

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.

Serverless SQL pool service connectivity issue


When connecting Azure Synapse to the destination storage account, you might run into
an issue similar to the one described in Notebook websocket connection issue. The
issue is related Synapse and how it sets up a websocket in the browser to retrieve the
data that is blocked by default on the customer internet proxy.

You can resolve this issue with an SSP request: INTERNT PROXY (SWG) - EXCEPTION ON
SECURITY FILTERING POLICY .

Issues adding network IP address to allow list


with Azure integration runtime
If the destination storage account needs to be closed for public access, you need to
allow access for a particular set of Azure service IP addresses. Customers will need to
allow list IPs based on the targeted Office region. To do this:

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 .

For details about this destination storage region restriction, see:

Azure Integration Runtime IP addresses - Azure Data Factory | Microsoft Docs


Configure Azure Storage firewalls and virtual networks | Microsoft Docs

Office region Azure region Alternate Azure regions to use

Asia-Pacific East Asia NA


Southeast Asia*

Australia Australia East NA


Australia Southeast*

Europe North Europe NA


West Europe*
Office region Azure region Alternate Azure regions to use

North America Central US NA


East US*
East US 2
North Central US
South Central US
West Central US
West US
West US 2

United Kingdom UK South* NA


UK West

Canada (CAN) Canada Central NA


Canada East*

Japan (JPN) Japan West NA


Japan East*

India (IND) South India* NA


Central India

Korea (KOR) Korea Central NA


Korea South

Switzerland (CHE) Switzerland North North Europe


West Europe

Germany (DEU) Germany West Central* North Europe


West Europe

Norway (NOR) Norway East* North Europe


West Europe

France (FRA) France Central* North Europe


West Europe

UAE (UAE) UAE North* East Asia


Southeast Asia
7 Note

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.

Network access and Azure IR example


The following example describes how to troubleshoot network access issue:

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.

Issues with running your pipeline using


mapping data flows
First time runs of Microsoft Graph Data Connect and the mapping data flow activity for
a new dataset are expected to fail with a Consent Pending error. This triggers a consent
request for the tenant admin, who can use Privileged Access Management to review and
approve/decline the data access request. To resolve the issue:

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

Why integrate with Outlook calendar?


The rich features of Outlook calendar and its API open up many app opportunities. The
following sections list a few of them.

Reach hundreds of millions of customers and


build rich scenarios
Many millions of customers use Outlook calendar as part of an integrated hub that lets
them effectively communicate and get things done. They can set up meetings, manage
emails, find information about contacts and other users, and initiate conversations or
online meetings all in one place, be it on the web, mobile, or desktop. Microsoft Graph
not only connects apps to the calendar, mail, and contacts data of these customers, it
enables apps to integrate with the best of Microsoft 365 and support a wide range of
scenarios that enhance productivity and collaboration.

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.

Automate appointment organization and


calendaring
Customers like how Outlook lets them organize their time for work, family, and personal
activities. Microsoft Graph REST API keeps close parity with the customer experience,
letting apps create, manage, and respond to events just as naturally:

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.

Help customers stay synchronized and navigate


their day
The calendar API helps customers navigate their day and enhance productivity:

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.**

Teleconference across multiple locations and


time zones
With globalization, today's business meetings often involve attendees participating from
different locations and time zones. Here's how you can use the calendar API to manage
such meetings:

As an example in Outlook, customers can organize a meeting and include


attendees joining from a conference room in Seattle, a coffee shop in Paris, and a
home office in China. Programmatically, the event locations property, which is a
collection of location objects, can reflect this level of details in displayName and
locationType for each location. See an example.
Outlook gives customers the flexibility to organize events and specify a time zone
for each of the start and end times of an event. To support this flexibility, by
default, the calendar API returns the start and end times of an event in UTC, and
provides the originalStartTimeZone and originalEndTimeZone properties to note
the time zones used when the event was created.
Alternatively, you can specify the Prefer: outlook.timezone="{time zone name}"
header so that a GET event operation returns start and end in the time zone you
specify. The time zone name can be any of those supported by Windows, as well as
those on this list. See an example of the Prefer header in use.
Organizations that support online meeting providers, such as Microsoft Teams and
Skype, can set up Outlook calendars to use these providers. You can conveniently
organize or attend events in these calendars as online meetings.

Build apps with location awareness and provide


intelligent context
Use the places API to help users navigate to a place, or provide an intelligent solution
based on the user's location. The following are some example scenarios:

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.

Where is the data?


The Microsoft Graph API supports accessing data in users' primary mailboxes and in
shared mailboxes . The data can be calendar, mail, or personal contacts stored in a
mailbox in the cloud on Exchange Online as part of Microsoft 365, or on Exchange on-
premises in a hybrid deployment.

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?

Outlook calendar API in Microsoft Graph v1.0


Outlook calendar API in Microsoft Graph beta

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}}"

Especially useful for larger meetings, you can specify a percentage


(minimumAttendeePercentage) for a quorum and have findMeetingTimes return
suggestions only if that minimum attendee availability is met.

If findMeetingTimes cannot suggest any meeting times, it indicates a specific reason


(emptySuggestionsReason), such as the organizer or a required attendee not available.
Based on this value, you can better adjust the parameters and call findMeetingTimes
again.

7 Note

The findMeetingTimes action is currently available to Microsoft 365 work or school


mailboxes, but not personal, outlook.com mailboxes.
Example
The following example shows how to use findMeetingTimes to return possible times for
2 users to meet for a couple of hours, taking into account the users' free/busy and work
schedules, and the attendee being away for part of the time. Because there are only 2
users for this meeting, suggestions require 100% attendance. The following shows the
users' free/busy schedule.

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.

After getting meeting time suggestions, you might want to:

1. Create an event and send it as a meeting request.


2. Add an attachment to the event.

Find out more about integrating with Outlook calendar.


Get free/busy schedule of Outlook
calendar users and resources
Article • 01/04/2023

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.

How does getSchedule compare with


findMeetingTimes
The findMeetingTimes action is similar to getSchedule in that both read the free/busy
status and working hours of specified users and resources. The two actions differ in a
few major ways.

Application
findMeetingTimes applies certain business logic to suggest meeting times and
locations, such as:

Optional or mandatory attendance of each entity


The nature of the requested activity for the time of the day
The minimum attendance required for a quorum for a meeting

It is appropriate for scenarios that depend on streamlining appointment booking.


getSchedule simply returns the free/busy status of existing events in each of the
requested calendars for a given time period, and assumes the remaining time in that
time period to be free. You would then apply further business logic to make use of this
data to complete your scenario.

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.

getSchedule supports both delegated and app-only scenarios. In the latter, an


administrator consents the app to access all calendars without a signed-in user.

Permissions
The least privileged permissions required by findmeetingtimes is
Calendars.Read.Shared.

The least privileged permission required by getSchedule is Calendars.Read.

Version support
findmeetingtimes and getSchedule are both generally available and appropriate for use
in production apps.

Event data returned


The least privileged permission required by getSchedule for an app to get free/busy
information is Calendars.Read. Depending on your app scenario, this can be consented
by the signed-in user or administrator.

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

These conditions apply regardless of whether the signed-in user is an administrator in


the organization. The requested user has control over the event data returned.

Time zone representation


By default, the start and end times of the returned schedule items are represented in
UTC. You can use a Prefer header to specify a time zone appropriate for your app. As
an example:

HTTP

Prefer: outlook.timezone="Pacific Standard Time"

Limits and error conditions


Be aware of the following limits and error condition:

getSchedule can support looking up free/busy information for up to 20 entities at


once. This limit applies to the number of users identified individually or as
members of a distribution list, and to the number of resources as well.
The time period to look up must be less than 62 days.
If getSchedule cannot identify a specified user or resource, it returns a single
schedule item and indicates the error.

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.

Example: attendee responds tentative and


suggests a different date/time
The following is an example where Alex invites Adele to lunch, Adele tentatively accepts
and proposes an alternative date and time, and Alex accepts the proposal by adjusting
the meeting accordingly:

1. As the organizer, Alex sends a meeting request to Adele. He sets the


allowNewTimeProposals property of the event to true to let Adele suggest
another time if she needs to.

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"
}
]
}

Alex gets the following response:

HTTP

HTTP/1.1 201 Created


Content-type: application/json

{
"@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]"
}
}
}

2. Adele receives the invitation in her Inbox as an eventMessageRequest. She notices


the allowNewTimeProposals property is set. Using the event associated with this
eventMessageRequest, she makes a tentative reply and proposes the next day at
the same time, in the proposedNewTime body parameter. She also sets the
sendResponse parameter to true.

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"
}
}
}

Adele's reply succeeds and she gets the following response:

HTTP

HTTP/1.1 202 Accepted

3. Alex receives an email of the eventMessageResponse type. He notices the


following:

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"
}
}

Alex's update succeeds and gets the following response.

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]"
}
}
}

No attendee proposes alternative time


In step 2, if Adele replied tentative or declined, and did not propose a different
date/time, then the following would happen:

In step 3, Alex would receive an eventMessageResponse with the responseType


property set to tentativelyAccepted (or decline if Adele declined). Alex would not
find a proposedNewTime property in this instance of eventMessageResponse.
In step 4, Alex would not find a proposedNewTime property in the associated
event either.

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.

In an organization that supports online meeting providers, administrators can set up


Outlook calendars to support meetings that use these providers, with one of these
providers being the default provider. You can create or update an event in Outlook and
allow attendees to join the meeting online using a supported provider. You can
conveniently get the online meeting information of the event, including the URL to join
the meeting.

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.

Calendars and online meeting providers


An organization that supports any of the following online meeting providers can set up
Outlook calendars and enable organizing meetings online:

Microsoft Teams, acquired as part of a Microsoft 365 business or enterprise suite


Skype
Skype for Business (which is being superceded by Microsoft Teams )

Look for the allowedOnlineMeetingProviders and defaultOnlineMeetingProvider


properties to verify if an Outlook calendar supports any online meeting providers. The
following example shows the signed-in user's default calendar supports two providers,
Microsoft Teams and Skype for Business, and uses Microsoft Teams as the default online
meeting provider.
Example: Find whether a calendar supports any online
meeting provider

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]"
}
}

Create an event and enable attendees to meet


online
You can create a meeting and allow attendees to join the meeting online, by setting
isOnlineMeeting to true , and onlineMeetingProvider to one of the providers
supported by the parent calendar. The following example creates a meeting in the
signed-in user's default calendar, and enables attendees to join the meeting via
Microsoft Teams. The response includes an event with online meeting information
specified in the onlineMeeting property.

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.

Example: Create and make meeting available as an online


meeting

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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:&#43;1 323-
886-7531,,291633251# \" target=\"_blank\" rel=\"noreferrer noopener\"
style=\"font-size:14px; text-decoration:none; color:#6264a7\">&#43;1 323-
886-7531</a>\r\n<span style=\"font-size:12px\">&nbsp; 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&amp;tenantId=98a79ebe-74bf-
4e07-a017-
7b410848cb32&amp;threadId=19_meeting_ODkyNWFmNGYtZjBjYS00MDdlLTllOWQtN2E3MzJ
[email protected]&amp;messageId=0&amp;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"
}
}

Get information to join meeting online


Attendees and organizers can use the isOnlineMeeting property to verify if an event is
enabled for online participation. They can use the onlineMeetingProvider property to
determine the meeting provider, and the onlineMeeting property for connection
information including joinUrl.

) 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.

Example: Get online meeting information

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"
}
}

Update a meeting to enable attendees to meet


online
You can change an existing event to make it available as an online meeting, by setting
isOnlineMeeting to true , and onlineMeetingProvider to one of the online meeting
providers supported by the parent calendar. The response includes the updated event
with the corresponding online meeting information specified in the onlineMeeting
property.

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.

Example: Update a meeting to make it available as an


online meeting

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:&#43;1 323-
886-7531,,275984951# \" target=\"_blank\" rel=\"noreferrer noopener\"
style=\"font-size:14px; text-decoration:none; color:#6264a7\">&#43;1 323-
886-7531</a>\r\n<span style=\"font-size:12px\">&nbsp; 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&amp;tenantId=98a79ebe-74bf-
4e07-a017-
7b410848cb32&amp;threadId=19_meeting_NTRkMWViMmEtNzcxNC00OTk3LWJjOTEtYTdhMDU
[email protected]&amp;messageId=0&amp;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:

Calendar API: use the event resource.


Cloud communications API: use the onlineMeeting resource.

The choice is between:

A convenient programmatic way to set up an online meeting in the Outlook


calendar where attendees click to join the meeting, and continue their experience
in Teams or Skype.
A richer programmatic integration of Teams or Skype features in an app for a more
customized experience.

Considerations when choosing an API for your


scenario
Choose the calendar API for a streamlined, built-in integration with Outlook calendar
that results in an online meeting event in the Outlook calendar:

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.

Comparing the APIs


The following table details the differences at the API level.

Online Calendar API (event resource) Cloud communications API


meeting (onlineMeeting resource)
feature

Main API event resource: onlineMeeting resource


members - isOnlineMeeting property audioConferencing resource
- onlineMeeting property of the
onlineMeetingInfo type
- onlineMeetingProvider property
calendar resource:
-
allowedOnlineMeetingProviders
property
- defaultOnlineMeetingProvider
property
Online Calendar API (event resource) Cloud communications API
meeting (onlineMeeting resource)
feature

Integration - Create API returns an onlineMeeting


with a - Create or update event API resource that is independent of a particular
calendar item automatically sets the resultant calendar type.
Outlook calendar event as an - Does not create or update any Outlook
online meeting. event.
- Use the isOnlineMeeting, - Integrate the returned onlineMeeting
onlineMeeting, and resource information in an app experience
onlineMeetingProvider properties appropriate for your scenario.
of the returned Outlook calendar - Use createOrGet to return an online
event. meeting that has a specified externalId
value, or create one if none already exists,
to streamline embedding the resultant
meeting in a third-party calendar.

Changing to - No - once you enable an event No - once you create an onlineMeeting


offline for joining online, you cannot resource, you can only delete it but cannot
meeting update it to make it an offline change it to an offline meeting.
meeting.
- Cannot change the
onlineMeetingProvider property,
nor set isOnlineMeeting to false
to disable the meeting online.

Locale-based No direct API integration. - Use the Accept-Language HTTP header


join when creating an online meeting.
information - See example.

Joining over Through the onlineMeeting Use the joinWebUrl property.


Internet (VoIP) property, access joinUrl.

Joining by Through the onlineMeeting Through the audioConferencing property,


dial-in property, access: access:
- conferenceId, quickDial, - conferenceId, tollFreeNumber,
phones, tollFreeNumbers, tollNumber.
tollNumber. - dialinUrl property for an externally-
accessible web page that contains dial-in
info to facilitate integration with third-party
apps.

Joining by No direct API integration. Use the videoTeleconferenceId property.


video
conferencing
(audio and
video)
Online Calendar API (event resource) Cloud communications API
meeting (onlineMeeting resource)
feature

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.

Relating to a No direct API integration. Use the chatInfo property.


Teams chat
Schedule repeating appointments as
recurring events in Outlook
Article • 01/14/2023

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.

Let's take a look at each of the possible pattern types.

Daily
The daily recurrence pattern causes an event to repeat based on a number of days
between each occurrence.

Relevant properties
Property Relevance Description

interval Required Specifies the number of days between each occurrence.

type Required Must be set to daily .

Examples
Repeat this event every day

JSON

"pattern": {
"type": "daily",
"interval": 1
}

Repeat this event every three days

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

Property Relevance Description

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.

type Required Must be set to weekly .


Examples
Repeat this event every Thursday

JSON

"pattern": {
"type": "weekly",
"interval": 1,
"daysOfWeek": [ "Thursday" ]
}

Repeat this event every other Monday and Tuesday

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

Property Relevance Description

dayOfMonth Required Specifies on which day of the month the event occurs.

interval Required Specifies the number of months between each occurrence.

type Required Must be set to absoluteMonthly .

Examples
Repeat this event on the 15th of every month

JSON
"pattern": {
"type": "absoluteMonthly",
"interval": 1,
"dayOfMonth": 15
}

Repeat this event quarterly (every 3 months) on the 7th

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

Property Relevance Description

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.

index Optional Specifies on which instance of the allowed days specified in


daysOfsWeek the event occurs, counted from the first instance in the
month. Possible values: first , second , third , fourth , and last .
Default value: first .

interval Required Specifies the number of months between each occurrence.

type Required Must be set to relativeMonthly .

Examples
Repeat this event on the second Wednesday of every month

JSON
"pattern": {
"type": "relativeMonthly",
"interval": 1,
"daysOfWeek": [ "Wednesday" ],
"index": "second"
}

Repeat this event on the first Thursday or Friday of every month

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

Property Relevance Description

dayOfMonth Required Specifies on which day of the month the event occurs.

month Required Specifies in which month the event occurs.

interval Required Specifies the number of years between each occurrence.

type Required Must be set to absoluteYearly .

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

Property Relevance Description

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.

index Optional Specifies on which instance of the allowed days specified in


daysOfsWeek the event occurs, counted from the first instance in the
month. Possible values: first , second , third , fourth , and last .
Default value: first .

month Required Specifies in which month the event occurs.

interval Required Specifies the number of years between each occurrence.

type Required Must be set to relativeYearly .

Examples

Repeat this event on the last Wednesday of November every year

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.

Depending on the type of range, certain fields of recurrenceRange are required 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.

Let's take a look at each of the possible range types.

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

Property Relevance Description

numberOfOccurrences Required Specifies the number of occurrences. Must be a positive


integer.

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.

type Required Must be set to numbered .

Examples
Repeat this event 10 times

JSON
"range": {
"type": "numbered",
"startDate": "2017-04-02",
"numberOfOccurrences": 10
}

End date range


The end date range causes an event to occur on all days that fit the applicable pattern
between a start date and an end date.

Relevant properties

Property Relevance Description

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.

type Required Must be set to endDate.

Examples

Repeat this event from July 1, 2017, to July 31, 2017

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

Property Relevance Description

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.

type Required Must be set to noEnd .

Examples
Repeat this event from May 15, 2017, forever

JSON

"range": {
"type": "noEnd",
"startDate": "2017-05-15"
}

Using patterns and ranges to create recurring


events
Now that we've looked at patterns and ranges separately, let's look at how they work
together and how they interact with the start and end properties on the event.

Creating a recurrence rule


To create a recurrence rule, you must specify both a pattern and a range. Any pattern
type can work with any range type. Here are a few examples.

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.

The rest of this article is based on the following example scenario:

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:

Get shared or delegated Outlook calendar or its events


Create Outlook events in a shared or delegated calendar
7 Note

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.

Get calendar information about sharees and


delegates, and update individual permissions
In this section:

Calendar owner: Get sharing or delegation information and permissions


Calendar owner: Update permissions for an existing sharee or delegate on a
calendar

Each calendar is associated with a collection of calendarPermission objects, each of


which describes a sharee or delegate and the associated permission that the calendar
owner has set up. The calendarRoleType enumeration defines the range of permissions
that Microsoft Graph supports:

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

details on the calendar.


limitedRead The sharee can view the owner's free/busy status, and the titles and
locations of non-private events on the calendar.
read The sharee can view the owner's free/busy status in private events, and all
the details of non-private events on the calendar.
write The sharee can view the owner's free/busy status in private events, and can

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.

Calendar owner: Get sharing or delegation information


and permissions
This example shows with the consent of Alex or administrator, how to get the
calendarPermission objects associated with Alex' primary calendar. The request returns
two such permission objects:

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.

emailAddress specifies Megan.

The second calendarPermission object is a default object assigned to "My


Organization", and has the following property values:
isRemovable is set to false, since the primary calendar is always shared with the
owner's organization.
isInsideOrganization is true.
role is freeBusyRead , the default setting for "My Organization".
emailAddress specifies the name sub-property as "My Organization"; address
for "My Organization" is by default null.

Microsoft Graph permissions

Use the least privileged delegated or application permission, Calendars.Read , as


appropriate, for this operation. For more information, see calendar permissions.

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"
}
}
]
}

Calendar owner: Update permissions for an existing


sharee or delegate on a calendar
With the consent of Alex or administrator, you can update the permissions assigned to
an existing sharee or delegate (specified by the role property), as long as the new
permissions are supported by those allowedRoles set up initially for the sharee or
delegate for that calendar.

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".

Microsoft Graph permissions

Use the least privileged delegated or application permission, Calendars.ReadWrite , as


appropriate, for this operation. For more information, see calendar permissions.

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]"
}
}

Get properties of a shared or delegated


calendar
In this section:

Calendar owner: Get properties of a shared or delegated calendar


Sharee or delegate: Get properties of shared or delegated calendar

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.

Calendar owner: Get properties of a shared or delegated


calendar
The example in this section gets the properties of the primary calendar from the
perspective of the owner, Alex.

Note the following properties on Alex' behalf:

canShare is true as Alex is the owner.


canViewPrivateItems is true since Alex is the owner.
isShared is set to true, as Alex has set up a delegate for this calendar.
isSharedWithMe is always false for the calendar owner.
owner shows Alex as the owner.

Microsoft Graph permissions

Use the least privileged delegated or application permission, Calendars.Read , as


appropriate, for this operation. For more information, see calendar permissions.
HTTP

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]"
}
}

Sharee or delegate: Get properties of shared or delegated


calendar
The example in this section gets the properties of the same calendar from the
perspective of the delegate, Megan.

Note the following properties:


name of the calendar is by default the owner's display name. In this case, it's "Alex
Wilber", since this is Alex' calendar delegated to Megan.
canShare is false, since Megan is not the owner of this calendar.
canViewPrivateItems is true for the delegate Megan, as set up by Alex. For a
sharee that is not a delegate, this property is always false.
isShared is false. This property indicates only to a calendar owner whether the
calendar has been shared or delegated.
isSharedWithMe property is true, since Megan is a delegate.
canEdit is true, since delegates, including Megan, have write access.
owner is set to Alex.

7 Note

A sharee or delegate can customize only the name property of a shared/delegated


calendar. The update is visible only to themselves; the calendar owner does not see
such calendar name changes.

Microsoft Graph permissions

Use the least privileged delegated permission, Calendars.Read.Shared , or application


permission, Calendars.Read , as appropriate, for this operation. For more information,
see calendar permissions.

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]"
}
}

Get or set mailbox setting to receive meeting


requests and responses
In this section:

Get delegation delivery setting for a user's mailbox


Set delegation delivery setting for a user's mailbox

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.

Programmatically, you can get or set the delegateMeetingMessageDeliveryOptions


property of the calendar owner's mailboxSettings to specify to whom Outlook should
direct eventMessageRequest and eventMessageResponse instances:

sendToDelegateOnly

Outlook to direct eventMessageRequest and eventMessageResponse instances to


only delegates. This is the default setting. The owner can see responses to a
meeting or respond to an invitation through the corresponding event in the
delegated calendar.

sendToDelegateAndInformationToPrincipal

Outlook to direct eventMessageRequest and eventMessageResponse instances to


delegates and the calendar owner. Only the delegates see the option to accept or
decline a meeting request, and the notification sent to the owner appears like a
normal email message. The owner can still respond to the meeting by opening the
event in the delegated calendar and responding.

sendToDelegateAndPrincipal

Outlook to direct eventMessageRequest and eventMessageResponse instances to


delegates and the calendar owner, either of whom can respond to the meeting
request.

This is a mailbox-wide setting, so the same setting applies to all delegates of the
mailbox owner.

Get delegation delivery setting for a user's mailbox


The example in this section gets the mailboxSettings of a calendar owner who lets
Outlook direct meeting requests and responses to only calendar delegates; that is,
delegateMeetingMessageDeliveryOptions is set to sendToDelegateOnly .

Microsoft Graph permissions

Use the least privileged delegated or application permission, MailboxSettings.Read , as


appropriate, for this operation. For more information about mailbox permissions, see
mail permissions.

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"
}
}
}

Set delegation delivery setting for a user's mailbox


The example in this section updates the delegateMeetingMessageDeliveryOptions
property to sendToDelegateAndPrincipal , to have Outlook direct meeting requests and
responses of the delegated calendar to all delegates and the owner.

Microsoft Graph permissions

Use the least privileged delegated or application permission,


MailboxSettings.ReadWrite , as appropriate, for this operation. For more information

about mailbox permissions, see mail permissions.

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"
}

Delete a sharee or delegate of a calendar


In the example below, Alex deletes Megan as a sharee of the "Kids parties" calendar.

Microsoft Graph permissions

Use the least privileged delegated or application permission, Calendars.ReadWrite , as


appropriate, for this operation. For more information, see calendar permissions.

HTTP

HTTP

DELETE
https://graph.microsoft.com/beta/users/[email protected]/cal
endars/AAMkADAwAABf02bAAAA=/calendarPermissions/L289RXhjaGFuZ2VMYWJTWVnY
W5C

HTTP

HTTP/1.1 204 No Content


Next steps
Find out more about:

How the Outlook clients support sharing and delegating calendars:


Share an Outlook calendar with other people
Allow someone else to manage your mail and calendar as a delegate
Share your calendar in Outlook on the web
Calendar delegation in Outlook on the web
Get Outlook events in a shared or delegated calendar
Create Outlook events in a shared or delegated calendar
Why integrate with Outlook calendar
The calendar API in Microsoft Graph beta.
Get shared or delegated Outlook
calendar and its events
Article • 06/23/2022

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.

Programmatically, Microsoft Graph supports reading and writing events in calendars


that have been shared by other users, as well as reading the shared calendars and
updating the calendar name for sharees. The support also applies to calendars that have
been delegated. The rest of this article describes reading events in a shared or
delegated calendar. For creating events, refer to Create Outlook events in a shared or
delegated calendar.

Sharee: Get a shared calendar or its events


directly from calendar owner's mailbox
The three examples below use this scenario: in Outlook, Alex has shared his primary
calendar with Megan and given Megan read permissions. If Megan signs into your app
and provides delegated permissions (Calendars.Read.Shared or
Calendars.ReadWrite.Shared), on behalf of Megan, your app can access Alex' primary
calendar and its events directly from Alex' mailbox.

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

The sharing permissions (Calendars.Read.Shared or Calendars.ReadWrite.Shared)


allow you to read or write events in a shared or delegated calendar. They do not
support subscribing to change notifications on items in such folders. To set up
change notification subscriptions on events in a shared, delegated, or any other
user or resource calendar in the tenant, use the application permission,
Calendars.Read.

Megan: Get the shared, primary calendar directly from


Alex' mailbox
Signed in as Megan, get the primary calendar that Alex has shared with Megan, directly
from Alex' mailbox:

HTTP

GET https://graph.microsoft.com/v1.0/users/{Alex-userId | Alex-


userPrincipalName}/calendar

On successful completion, you'll get HTTP 200 OK and a calendar instance that
represents Alex' shared, primary calendar, in Alex' mailbox.

Megan: Get an event in the shared, primary calendar


directly from Alex' mailbox
Signed in as Megan, your app can get a specific event in the primary calendar that Alex
has shared with Megan, directly from Alex' mailbox:

HTTP

GET https://graph.microsoft.com/v1.0/users/{Alex-userId | Alex-


userPrincipalName}/calendar/events/{id}

On successful completion, you'll get HTTP 200 OK and the event instance identified by
{id} in Alex' primary calendar, directly from Alex' mailbox.

Megan: Get all the events in the shared, primary calendar


from Alex' mailbox
Signed in as Megan, get all the events in the primary calendar that Alex has shared with
Megan, directly from Alex' mailbox:

HTTP

GET https://graph.microsoft.com/v1.0/users/{Alex-userId | Alex-


userPrincipalName}/calendar/events
On successful completion, you'll get HTTP 200 OK and a collection of event instances in
Alex' primary calendar, directly from Alex' mailbox.

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.

Sharee: Get shared, custom calendar or its


events from sharee's mailbox
If Alex has shared a custom calendar (as an example, a calendar named "Kids parties")
with Adele, and Adele has provided delegated permissions (Calendars.Read or
Calendars.ReadWrite), your app can get the events or calendar from the local copy of
Alex' calendar in Adele's mailbox, as described below.

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:

Create Outlook events in a shared or delegated calendar


Share or delegate a calendar in Outlook (preview)
Why integrate with Outlook calendar
The calendar API in Microsoft Graph v1.0.
Create Outlook events in a shared or
delegated calendar
Article • 03/02/2023

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.

Programmatically, Microsoft Graph supports reading or writing events in calendars that


have been shared by other users, as well as reading the shared calendars, and updating
the calendar name for sharees. The support also applies to calendars that have been
delegated. The rest of this article walks through creating a meeting event in a shared or
delegated calendar. For getting events, refer to Get Outlook events in a shared or
delegated 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 .)

The walkthrough describes a few subsequent steps:

1. Adele gets the calendar that Alex has delegated to her.


2. Adele sends a meeting invitation to Christie and Megan on Alex' behalf.
3. Christie receives the meeting request, and inspects the associated event in her
calendar.
4. Christie responds tentative to the invitation.
5. Adele receives Christie's response message.
6. Alex checks attendees' responses as part of the event.

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.

Microsoft Graph permissions

Use the least privileged delegated permission, Calendars.Read.Shared . For more


information, see calendar permissions.

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.

Step 2: Adele creates and sends an invitation


on Alex' behalf
Signed in as Adele, use the calendar ID obtained from step 1 to create an event in the
delegated calendar and send it to Christie and Megan, on Alex' behalf.

Microsoft Graph permissions

Use the least privileged delegated permission, Calendars.ReadWrite.Shared . For more


information, see calendar permissions.

HTTP

POST
https://graph.microsoft.com/v1.0/me/calendars/AAMkADRpAABf0JlzAAA=/events

Prefer: outlook.timezone="Pacific Standard Time"


Content-type: application/json

{
"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#

Snippet not available

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 specifies this message is meetingRequest .


sender is Adele.
from is Alex.
toRecipients include Megan and Christie.

And the following event properties:

attendees include Alex, Megan, and Christie.


organizer is Alex.

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]"
}
}
}
}

Step 4: Christie responds to the meeting


request
Signed in as Christie, reply to the event as tentative, and include a reply message in the
response:

Microsoft Graph permissions

Use the least privileged delegated permission, Calendars.ReadWrite.Shared . For more


information, see calendar permissions.

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

var graphClient = new GraphServiceClient(requestAdapter);

var requestBody = new


Microsoft.Graph.Me.Events.Item.TentativelyAccept.TentativelyAcceptPostRe
questBody
{
Comment = "I will probably be able to make it.",
SendResponse = true,
};
await graphClient.Me.Events["{event-
id}"].TentativelyAccept.PostAsync(requestBody);

Read the SDK documentation for details on how to add the SDK to your project
and create an authProvider instance.

A successful response returns HTTP 202 Accepted.

HTTP

HTTP/1.1 202 Accepted

Step 5: Adele receives the response message


Because Adele is a delegate of Alex' primary calendar, Adele receives all meeting
responses for that calendar on Alex' behalf.

Signed in as Adele, get the eventMessage that represents the response from Christie in
step 4.

Microsoft Graph permissions


Use the least privileged delegated permission, Mail.Read.Shared . For more information,
see mail permissions.

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

var graphClient = new GraphServiceClient(requestAdapter);

var result = await graphClient.Me.Messages["{message-id}"].GetAsync();

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"
}
}

Step 6: Alex accesses responses as part of the


event
Because Alex kept the default to have Outlook direct all meeting requests and responses
to only delegates, Alex does not receive Christie's response from step 4. He can however
get the response through the event in his primary calendar.

Signed in as Alex, get the event that Adele created in step 2 and get responses from the
attendees property.

Microsoft Graph permissions

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

var graphClient = new GraphServiceClient(requestAdapter);

var result = await graphClient.Me.Calendar.Events["{event-


id}"].GetAsync();

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:

Get Outlook events in a shared or delegated calendar


Share or delegate a calendar in Outlook (preview)
Why integrate with Outlook calendar
The calendar API in Microsoft Graph v1.0.
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

Be aware of a known issue if you're attaching large files to a message or event in a


shared or delegated mailbox.

Step 1: Create an upload session


Create an upload session to attach a file to a message or event. Specify the file in the
input parameter AttachmentItem.

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.

The uploadSession object in the response also includes the nextExpectedRanges


property, which indicates the initial upload starting location should be byte 0.

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.

Example: Create an upload session for a message

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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-"
]
}

Example: Create an upload session for an event

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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-"
]
}

Step 2: Use the upload session to upload a


range of bytes of the file
To upload the file, or a portion of the file, make a PUT request to the URL returned in
step 1 in the uploadUrl property of the uploadSession resource. You can upload the
entire file, or split the file into multiple byte ranges. For better performance, keep each
byte range less than 4 MB.

Specify request headers and request body as described below.

Request headers

Name Type Description

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.

Content- String The MIME type. Specify application/octet-stream . Required.


Type

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).

Example: First upload to the message

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"]
}

Example: First upload to the event

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"]
}

Step 3: Continue uploading byte ranges until


the entire file has been uploaded
Following the initial upload in step 2, continue to upload the remaining portion of the
file, using a similar PUT request as described in step 2, before you reach the expiration
date/time for the session. Use the nextExpectedRanges collection to determine where
to start the next byte range to upload. You may see multiple ranges specified, indicating
parts of the file that the server has not yet received. This is useful if you need to resume
a transfer that was interrupted and your client is unsure of the state on the service.

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.

Example: Final upload to the message

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

HTTP/1.1 201 Created

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

Example: Final upload to the event

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

Step 4 (optional): Get the file attachment from


the Outlook item
As always, getting an attachment from an Outlook item is not technically limited by
attachment size.

However, getting a large file attachment in base64-encoded format affects API


performance. If you expect a large attachment:

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.

Example: Get the raw file attached to the event


Following the event example and using the attachment ID returned in the Location
header of the previous step, the example request in this section shows using a $value
parameter to get the attachment raw content data.

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

{Raw bytes of the file}

Example: Get the metadata of the file attached to the


message
Following the message example, the example request in this section shows using a
$select parameter to get some of the metadata of a file attachment on a message,
excluding contentBytes.

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
}

Alternative: Cancel the upload session


At any point of time before the upload session expires, if you have to cancel the upload,
you can use the same initial opaque URL to delete the upload session. A successful
operation returns HTTP 204 No Content .

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.

Example: Cancel the upload session for the message

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

HTTP/1.1 204 No content


Errors

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.

Lifetime of immutable IDs


An item's immutable ID will not change so long as the item stays in the same mailbox.
That means that immutable ID will NOT change if the item is moved to a different folder
in the mailbox. However, the immutable ID will change if:

The user moves the item to an archive mailbox.


The user exports the item (to a PST, as an MSG file, etc.) and re-imports it into their
mailbox.

Items that support immutable IDs


The following items support immutable IDs:

message resource type


attachment resource type
event resource type
eventMessage resource type
contact resource type
outlookTask resource type

Container types (mailFolder, calendar, etc.) do not support immutable ID, but their
regular IDs were already constant.

Immutable ID with sending mail


You can use immutable IDs to find a message in the Sent Items folder after it has been
sent, using the following steps:

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.

Immutable ID with change notifications


You can request that Microsoft Graph send immutable IDs in change notifications by
including the Prefer: IdType="ImmutableId" header when creating a subscription.
Existing subscriptions created without the header will continue to use the default ID
format. In order to switch existing subscriptions to use immutable IDs, you must delete
and recreate them using the header.

Immutable ID with delta query


You can request that Microsoft Graph return immutable IDs in delta query responses for
supported resource types by including the Prefer: IdType="ImmutableId" header. The
@odata.nextLink and @odata.deltaLink values returned by delta queries are compatible

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.

Updating existing data


If you've already got a database filled with thousands of regular IDs, you can migrate
those IDs to immutable format using the translateExchangeIds function. You can provide
an array of up to 1000 IDs to be translated into a target format.

7 Note

You can also use translateExchangeIds to migrate Exchange Web Services


applications to Microsoft Graph.

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.

Subscribe to changes in contacts, calendar, or


mail
To subscribe to change notifications of Outlook resources, first create a subscription.

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:

Delegated permission supports subscribing to items in folders in only the signed-in


user's mailbox. For example, you cannot use the delegated permission Calendars.Read
to subscribe to events in another user’s mailbox.

To subscribe to change notifications of Outlook contacts, events, or messages in


shared or delegated folders:
Use the corresponding application permission to subscribe to changes of items in a
folder or mailbox of any user in the tenant.
Do not use the Outlook sharing permissions (Contacts.Read.Shared,
Calendars.Read.Shared, Mail.Read.Shared, and their read/write counterparts), as
they do not support subscribing to change notifications on items in shared or
delegated folders.

Depending on the resource, use the least privileged permission specified in the following
table to call this API.

Resource Supported Resource Paths Delegated Delegated Application


(work or (personal
school Microsoft
account) account)

contact Changes to all personal contacts in a user's Contacts.Read Contacts.Read Contacts.Read


mailbox:
/me/contacts
/users/{id}/contacts
Changes to contacts in a user's
contactFolder:
/users/{id}/contactFolders/{id}/contacts

event Changes to all events in a user's mailbox: Calendars.Read Calendars.Read Calendars.Read


/me/events
/users/{id}/events

message Changes to all messages in a user's Mail.ReadBasic, Mail.ReadBasic, Mail.ReadBasic,


mailbox: Mail.Read Mail.Read Mail.Read
/me/messages
/users/{id}/messages
Changes to messages in a user's
mailFolder:
/users/{id}/mailFolders/{id}/messages

Include resource data in notification payload (preview)


7 Note

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:

includeResourceData: Set this property to true to explicitly request resource data.

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

Do not include in the URL $top , $skip , $orderby , $select=Body,UniqueBody , and


$expand other than singleValueExtendedProperties or
multiValueExtendedProperties.

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.

Refine the conditions for a notification


You can further refine the conditions for a notification by using the $filter query
parameter. See an example.

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:

A message added to or marked unread in the folder would trigger a Created


notification.
Reading a message or marking it as read in the folder would trigger a Deleted
notification.
A change to any property, other than isRead, of a message resource in the folder
would trigger an Updated notification.

If you don’t use a $filter when creating the subscription:

Adding a message to the folder would result in a Created notification.


Reading a message in the folder, marking the message as read, or changing any other
property of a message in that folder would result in an Updated notification.
Deleting the message would result in a Delete notification.

Subscribe to lifecycle notifications


The Outlook contact, event, and message resources also support subscribing to lifecycle
notifications. Lifecycle notifications are needed in case your app gets their subscriptions
removed or misses some change notifications. Apps should implement logic to detect and
recover from the loss, and resume a continuous change notification flow. To learn more, see
subscribing to lifecycle notifications.

Keep track of subscription lifetime


Make sure to extend a subscription before it expires. The maximum lifetime for a
subscription without Outlook resource data is 4230 minutes (under 3 days), and 1 day with
resource data.

If you lose the permission granted earlier for a subscription and the subscription expires
meanwhile, request permission again to create a new subscription.

Receive notification payloads


Depending on your subscription, notifications may include resource data. Subscriptions
with resource data allow you to get the resource payload along with the notification,
avoiding the overhead for a separate API call to get the changed resource data.

Receive notifications with resource data (preview)


The following is an example of the payload of a notification with resource data of a
message resource. The resource and resourceData properties correspond to the message
instance that triggered the notification. Use the encryptedContent property to decrypt the
resource data.
JSON

{
"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.

The following is an example of a decrypted notification payload. The decrypted payload


conforms to the Outlook message schema. The payload is similar to that returned by a GET
message operation. However, the notification payload contains only those properties
specified with a $select parameter in the resource property of the subscription.
Notification payloads for other Outlook resources like contact and event follow their
respective schemas.

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]"
}
}
}

Receive notifications without resource data


Notifications without resource data give you enough information to make GET calls to get
the resource. Subscriptions for notifications without resource data don't require an
encryption certificate, because the actual resource data is not sent over.

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

Example 1: Create a subscription to get change notifications


without resource data when the user receives a new
message
The following example requests a notification for a message being created in the user's
mailbox.

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

The following is an example of the 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/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
}

Example 2: Create a subscription to get change


notifications with resource data when the user receives a
new message (preview)
The following example subscribes to notifications with resource data for a message being
created in the user's mailbox. The properties of the message resource to be included in the
notification payload are specified using the $select query parameter.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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
}

Example 3: Create a subscription to get change


notifications with resource data for a message based on a
condition (preview)
The following example subscribes to notifications with resource data for a message being
created in the Drafts folder, containing one or more attachments, and of high importance.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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

Change notifications enable applications to receive alerts when a Microsoft Graph


resource they're interested in changes; that is, created, updated, or deleted. Microsoft
Graph sends notifications to the specified client endpoint, and the client service
processes the notifications according to the business requirements. For example, the
service may fetch more data, update its cache and views, and so on.

Why get change notifications?


Change notifications follow an event-driven model where customers receive alerts when
changes occur instead of them polling Microsoft Graph. Depending on your business
logic, change notifications are suitable when:

You're subscribing to a resource that changes frequently.


You need to react to changes in near real-time.
You want to avoid frequently polling Microsoft Graph which might cause you to hit
the throttling limits.

https://www.youtube-nocookie.com/embed/rC1bunenaq4

Types of change notifications


Microsoft Graph supports three types of change notifications:

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

Subscriptions to resources marked with an asterisk ( * ) are available on the /beta


endpoint only.

Resource Supported resource paths Limitations

Cloud printing Changes when a print job is ready to be downloaded -


printer (jobFetchable event): /print/printers/{id}/jobs

Cloud printing Changes when there is a valid job in the queue (jobStarted -
printTaskDefinition event): /print/printtaskdefinition/{id}/tasks

driveItem on Changes to content within the hierarchy of any folder: -


OneDrive (personal) /users/{id}/drive/root

driveItem on Changes to content within the hierarchy of the root folder: -


OneDrive for /drives/{id}/root , /users/{id}/drive/root
Business
Resource Supported resource paths Limitations

group Changes to all groups: /groups Maximum


subscription
Changes to a specific group: /groups/{id} quotas:
Per app
Changes to owners of a specific group: /groups/{id}/owners (for all
tenants
Changes to members of a specific group: /groups/{id}/members combined):
50,000 total
subscriptions.
Per tenant
(for all
applications
combined):
1000 total
subscriptions
across all
apps.
Per app
and tenant
combination:
100 total
subscriptions
.

Not
supported for
Azure AD
B2C tenants.

A known
issue for the
subscription
changeType.

list under a Changes to content within the list: /sites/{site- -


SharePoint site id}/lists/{list-id}

Microsoft 365 group Changes to a group's conversations: -


conversation groups/{id}/conversations
Resource Supported resource paths Limitations

Outlook message Changes to all messages in a user's mailbox: A maximum


/users/{id}/messages , /me/messages of 1,000
active
Changes to messages in a user's Inbox: subscriptions
/users/{id}/mailFolders('inbox')/messages , per mailbox
/me/mailFolders('inbox')/messages for all
applications
is allowed.

Outlook event Changes to all events in a user's mailbox: /users/{id}/events , A maximum


/me/events of 1,000
active
subscriptions
per mailbox
for all
applications
is allowed.

Outlook personal Changes to all personal contacts in a user's mailbox: A maximum


contact /users/{id}/contacts , /me/contacts of 1,000
active
subscriptions
per mailbox
for all
applications
is allowed.

Security alert Changes to a specific alert: /security/alerts/{id} -

Changes to filtered alerts: /security/alerts/?$filter=


{parameters}

Teams callRecord Changes to all call records: /communications/callRecords Maximum


subscription
quotas:
Per
organization:
100 total
subscriptions.
Resource Supported resource paths Limitations

Teams chat Changes to any chat in the tenant: /chats Maximum


subscription
Changes to a specific chat: /chats/{id} quotas:
Per app
Changes to all chats in an organization where a particular and chat
Teams app is installed: combination:
/appCatalogs/teamsApps/{id}/installedToChats 1
subscription.
Per
organization:
10,000 total
subscriptions.

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

Teams channel Changes to channels in all teams: /teams/getAllChannels Maximum


subscription
Changes to channel in a specific team: /teams/{id}/channels quotas:
Per app
and team
combination:
1
subscription.
Per
organization:
10,000 total
subscriptions.

Teams Changes to membership in a specific team: Maximum


conversationMember /teams/{id}/members subscription
quotas:
Changes to membership in all channels under a specific team: Per app
teams/{id}/channels/getAllMembers and team
combination:
Changes to membership in a specific chat: 1
/chats/{id}/members subscription.
Per
Changes to membership for all chats in an organization where organization:
a particular Teams app is installed: 10,000 total
/appCatalogs/teamsApps/{id}/installedToChats/getAllMembers subscriptions.

Changes to membership in all chats: /teams/getAllMembers

Teams onlineMeeting Changes to an online meeting:


* /communications/onlineMeetings/?$filter=JoinWebUrl eq
{joinWebUrl}

Teams presence Changes to a single user's presence:


/communications/presences/{id}

Changes to multiple user presences:


/communications/presences?$filter=id in ({id},{id}...)
Resource Supported resource paths Limitations

Teams team Changes to any team in the tenant: /teams Maximum


subscription
Changes to a specific team: /teams/{id} quotas:
Per app
and team
combination:
1
subscription.
Per
organization:
10,000 total
subscriptions.

todoTask Changes to all task in a specific task list: -


/me/todo/lists/{todoTaskListId}/tasks
Resource Supported resource paths Limitations

user Changes to all users: /users Maximum


subscription
Changes to a specific user: /users/{id} quotas:
Per app
(for all
tenants
combined):
50,000 total
subscriptions.
Per tenant
(for all
applications
combined):
1000 total
subscriptions
across all
apps
Per app
and tenant
combination:
100 total
subscriptions.

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.

Receiving change notifications


Microsoft Graph can deliver change notifications to clients via the following channels.

Webhooks. For more information, see Receive change notifications through


webhooks.
Azure Event Hubs. For more information, see Receive change notifications through
Azure Event Hubs.
Azure Event Grid (preview). For more information, see Receive change notifications
through Azure Event Grid.

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.

Resource Maximum expiration time

Security alert 43,200 minutes (under 30 days)

Teams callRecord 4,230 minutes (under 3 days)

Teams channel 60 minutes (1 hour)

Teams chat 60 minutes (1 hour)

Teams chatMessage 60 minutes (1 hour)

Teams 60 minutes (1 hour)


conversationMember

Teams onlineMeeting 4,320 minutes (3 days)

Teams team 60 minutes (1 hour)

Group conversation 4,230 minutes (under 3 days)

OneDrive driveItem 42,300 minutes (under 30 days)

SharePoint list 42,300 minutes (under 30 days)

Outlook message, event, 4,230 minutes (under 3 days)


contact

user, group, other 41,760 minutes (under 29 days)


directory resources
Resource Maximum expiration time

onlineMeeting 4,230 minutes (under 3 days)

presence 60 minutes (1 hour)

Print printer 4,230 minutes (under 3 days)

Print printTaskDefinition 4,230 minutes (under 3 days)

todoTask 4,230 minutes (under 3 days)

Webhooks for this resource are only available in the global endpoint
and not in the national clouds.

baseTask (deprecated) 4,230 minutes (under 3 days)

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.

Receive change notifications through webhooks.


Receive change notifications through Azure Event Hubs.
Receive change notifications through Azure Event Grid (preview).

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.

Resource Average latency Maximum latency

alert 1 Less than 3 minutes 5 minutes

callRecord Less than 15 minutes 60 minutes

channel Less than 10 seconds 60 minutes

chat Less than 10 seconds 60 minutes

chatMessage Less than 10 seconds 1 minute

contact Unknown Unknown

conversation Unknown Unknown

conversationMember Less than 10 seconds 60 minutes

driveItem Less than 1 minute 5 minutes

event Unknown Unknown

group Less than 2 minutes 15 minutes

list Less than 1 minute 5 minutes

message Unknown Unknown

onlineMeeting Less than 10 seconds 1 minute

presence Less than 10 seconds 1 minute

printer Less than 1 minute 5 minutes

printTaskDefinition Less than 1 minute 5 minutes

team Less than 10 seconds 60 minutes

todoTask Less than 2 minutes 15 minutes

user Less than 2 minutes 15 minutes


1
The latency provided for the alert resource is only applicable after the alert is created.
It doesn't include the time it takes for a rule to create an alert from the data.

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.

To receive change notifications through webhooks, you need to create a subscription to


the resource for which you want to be notified of changes. While the subscription is
valid, Microsoft Graph sends a notification to your app whenever a change is detected
on the resource.

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:

1. The client app sends a subscription request to subscribe to changes on a specific


resource.

2. Microsoft Graph verifies the request.

If the request is valid, Microsoft Graph sends a validation token to the


notification URL for the client app to validate the notification URL.
If the request is invalid, Microsoft Graph sends an error response with an
error code and details.

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

Any query string parameter included in the notificationUrl property will be


included in the HTTP POST request when notifications are being delivered to your
service.

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:

1. Microsoft Graph encodes a validation token and includes it in a POST request to


the notification URL as follows.

HTTP

Content-Type: text/plain; charset=utf-8


POST https://{notificationUrl}?validationToken=
{opaqueTokenCreatedByMicrosoftGraph}

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:

A status code of HTTP 200 OK .


A content type of text/plain .
A body that includes the URL decoded plain text validation token.

) 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.

Change notification example


When the user receives an email, Microsoft Graph sends a change notification object to
the client app as shown in the following example. See changeNotificationCollection and
the related changeNotification for details of the notification payload.

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}"
}
}
]
}

Processing the change notification


Your service should process every change notification it receives. The following are the
minimum tasks that your app must perform to process a change notification:

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.

3. Update your client app based on your business logic.


Renew a subscription
There are many reasons why you may need to renew a subscription. For more
information, see lifecycle notifications.

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.

To renew the subscription, the expirationDateTime property is required. If you don't


renew a subscription in time, Microsoft Graph deletes the subscription, and the app
won't receive future change notifications for the subscription.

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"
}

If the subscription renewal request is successful, Microsoft Graph returns a 200 OK


response code and a subscription object in the response body. The subscription object
includes the new expirationDateTime value.

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.

How Microsoft Graph handles throttling for change notifications


using webhooks

Notifications are published using an HTTP client with a 3-second timeout.

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.

When Microsoft Graph throttles an endpoint, notifications are subjected to a delay of 10


minutes and are offloaded to workers dedicated to failed and throttled notifications.
Notifications that failed to deliver due to an unsuccessful HTTP call are retried again in
10 minutes. Notifications are dropped if the throttled endpoint slow percentage is
greater than or equal to 15%.

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.

1. Create a subscription by sending a POST request to the /subscriptions endpoint.


2. Microsoft Graph will validate the webhook notification endpoint before it
completes the subscription creation process. A unique subscriptionId is linked to
the subscription.
3. As long as the subscription is still valid and changes occur to the subscribed
resource, Microsoft Graph will send change notifications to the notificationUrl
endpoint.
4. Regularly renew the subscription to maintain its validity and continue receiving
updates on the subscribed changes.

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.

Good examples of high throughput scenarios include applications subscribing to a large


set of resources, applications subscribing to resources that change with a high
frequency, and multi-tenant applications that subscribe to resources across a large set
of organizations.

The article guides you through the process of managing your Microsoft Graph
subscription and how to receive change notifications through Azure Event Hubs.

Using Azure Event Hubs to receive change


notifications
Azure Event Hubs is a popular real-time events ingestion and distribution service built
for scale. You can use Azure Events Hubs instead of traditional webhooks to receive
change notifications.
Using Azure Event Hubs to receive change notifications differs from webhooks in a few
ways, including:

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.

Set up the Azure KeyVault and Azure Event Hubs


This section will walk you through the setup of required Azure services.

Use Azure CLI


The Azure CLI allows you to script and automate adminstrative tasks in Azure. The
CLI can be installed on your local computer or run directly from the Azure Cloud
Shell.

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.

Creating the subscription and receiving notifications


After you create the required Azure KeyVault and Azure Event Hubs services, you will be
able to create your subscription and start receiving change notifications via Azure Event
Hubs.

Creating the subcription


Subscriptions to change notifications with Event Hubs are almost identical to change
notifications with webhooks. The key difference is that they rely on Event Hubs to deliver
notifications. All other operations are similar, including subscription creation.

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.

Note: Your application receives validation messages whenever it creates a new


subscription. You should ignore these notifications. The following example
represents the body of a validation message.

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"
}
}
]
}

What happens if the Microsoft Graph Change Tracking


application is missing?
It's possible that the Microsoft Graph Change Tracking service principal is missing from
your tenant, depending on when the tenant was created and administrative operations.
To resolve this issue, run the following query in Microsoft Graph Explorer.

Query details: 0bf30f3b-4a52-48df-9a82-234910c4a086 is the global appId for the


Microsoft Graph Change Tracking application.
HTTP

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.

Alternatively, you can use the New-MgServicePrincipal cmdlet in Microsoft Graph


PowerShell to add the missing service principal. The following is an example script.

PowerShell

Connect-Graph -Scopes "Application.ReadWrite.All"


New-MgServicePrincipal -AppId "0bf30f3b-4a52-48df-9a82-234910c4a086"

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.

Microsoft event source Resource(s) Available event types

Azure Active Directory User, Group Azure AD event types

Microsoft Outlook Event (calendar meeting), Message Microsoft Outlook


(email), Contact event types

Microsoft Teams ChatMessage, CallRecord (meeting) Microsoft Teams event


types

Microsoft SharePoint and DriveItem


OneDrive

Microsoft SharePoint List

Security alerts Alert

Microsoft Conversations Conversation

) Important

If you aren't familiar with the Partner Events feature, see Partner Events overview.

Why should I use Microsoft Graph API as a


destination?
Besides the ability to subscribe to Microsoft Graph API events via Event Grid, you have
other options through which you can receive similar notifications (not events). Consider
using Microsoft Graph API to deliver events to Event Grid if you have at least one of the
following requirements:

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'

onboarding and off-boarding. You may also want to send


Microsoft.Graph.UserUpdated events to another application that syncs contacts
information, for example. You can achieve that using a single Graph API
subscription when using Event Grid as a notification destination. For more
information, see event filtering and event handlers.
Interoperability is important to you. You want to forward and handle events in a
standard way using CNCF's CloudEvents specification standard, to which Event
Grid fully complies.
You like the extensibility support that CloudEvents provides. For example, if you
want to trace events across compliant systems, you may use CloudEvents extension
Distributed Tracing . Learn more about more CloudEvents extensions .
You want to use proven event-driven approaches adopted by the industry.

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.

Register the Event Grid resource provider


Unless you've used Event Grid before, you'll need to register the Event Grid resource
provider. If you’ve used Event Grid before, skip to the next section.

In the Azure portal, do the following steps:

1. On the left menu, select Subscriptions.

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.

4. Search for Microsoft.EventGrid, and select it in the provider list.

5. Select Register on the command bar.

6. Refresh to make sure the status of Microsoft.EventGrid is changed to Registered.


Authorize partner to create a partner topic
You must grant your consent to the partner to create partner topics in a resource group
that you designate. This authorization has an expiration time. It's effective for the time
period you specify between 1 to 365 days.

) 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.

1. Sign in to the Azure portal .

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.

4. On the Create Partner Configuration page, do the following steps:


a. In the Project Details section, select the Azure subscription and the resource
group where you want to allow the partner to create a partner topic.

b. In the Partner Authorizations section, specify a default expiration time for


partner authorizations defined in this configuration.

c. To provide your authorization for a partner to create partner topics in the


specified resource group, select + Partner Authorization link.

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.

b. Specify authorization expiration time.


c. select Add.

) Important

Your partner won't be able to create resources (partner topics) in your


Azure subscription after the authorization expiration time.

6. Back on the Create Partner Configuration page, verify that the partner is added to
the partner authorization list at the bottom.

7. Select Review + create at the bottom of the page.

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"
}

Here are some of the key headers and payload properties:

x-ms-enable-features : Header used to indicate your desire to participate in the

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-region-name-where-you-want-the-topic-created> . The location (also known

as Azure region) name can be obtained by executing the az account list-locations


command. Don't use a location displayname. For example, don't use "West Central
US". Use westcentralus instead.

Azure CLI
az account list-locations

resource: the resource that generates events to announce state changes.


expirationDateTime: the expiration time at which the subscription expires and
hence the flow of events stop. It must conform to the format specified in RFC
3339 . You must specify an expiration time that is within the maximum
subscription length allowable for the resource type used.
client state. A value that is set by you when creating a Graph API subscription. For
more information, see Graph API subscription properties.

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.

What happens when you create a Microsoft Graph API


subscription?
When you create a Graph API subscription with a notificationUrl bound to Event Grid,
a partner topic is created in your Azure subscription. For that partner topic, you
configure event subscriptions to send your events to any of the supported event
handlers that best meets your requirements to process the events.

Test APIs using Graph Explorer

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.

Activate a partner topic


1. In the search bar of the Azure portal, search for and select Event Grid Partner
Topics.

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.

Create an event handler


To test your partner topic, you'll need an event handler. Go to your Azure subscription
and spin up a service that's supported as an event handler such as an Azure Function.
For an example, see Event Grid Viewer sample that you can use as an event handler via
webhooks.

Subscribe to the partner topic


Subscribing to the partner topic tells Event Grid where you want your partner events to
be delivered.

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.

4. On the Create Event Subscription page, do the following steps:


a. Enter a name for the event subscription.

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.

f. Now on the Create Event Subscription page, select Create.


Next steps
See the following articles:

Azure Event Grid - Partner Events overview


Microsoft Graph API webhook samples . Use these samples to send events to
Event Grid. You just need to provide a suitable value notificationUrl according to
the request example above.
Varied set of resources on Microsoft Graph API.
Microsoft Graph API webhooks
Best practices for working with Microsoft Graph API
Microsoft Graph API SDKs
Microsoft Graph API tutorials, which shows how to use Graph API in different
programming languages.This doesn't necessarily include examples for sending
events to Event Grid.
Reduce missing subscriptions and
change notifications
Article • 04/26/2023

In the lifetime of a subscription, Microsoft Graph sends special kinds of notifications to


help you minimize the risk of missing subscriptions and change notifications. These
notifications are called lifecycle notifications.

There are three types of lifecycle events:

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.

Configure your subscription to receive lifecycle


notifications
To receive lifecycle notifications, you must provide a valid lifecycleNotificationUrl
endpoint when creating the subscription.

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>"
}

The lifecycleNotificationUrl endpoint can be the same as the notificationUrl.

Existing subscriptions without a lifecycleNotificationUrl property don't receive the


lifecycle notifications. To add the lifecycleNotificationUrl property, you should remove
such existing subscriptions and create new subscriptions while specifying the property
during subscription creation.

When using the webhooks delivery channel, you must validate both endpoints.

Structure of a lifecycle notification


A lifecycle notification payload follows the structure of the changeNotificationCollection
and the related changeNotification resource types as follows:

JSON

{
"value": [
{
"subscriptionId":"<subscription_guid>",
"subscriptionExpirationDateTime":"2019-03-20T11:00:00.0000000Z",
"tenantId": "<tenant_guid>",
"clientState":"<secretClientState>",
"lifecycleEvent": "subscriptionRemoved or missed or
reauthorizationRequired"
}
]
}

The lifecycleEvent can be subscriptionRemoved , missed , or reauthorizationRequired ,


representing the lifecycle notification types.

A lifecycle notification doesn't contain any information about a specific resource,


because it isn't related to a resource change, but to the subscription state change.
Similar to change notifications, lifecycle notifications can be batched together and
received as a collection, each with a possibly different lifecycleEvent value. Process each
lifecycle notification in the batch accordingly.
When you process the lifecycle notification and resume the flow of change notifications,
the change notifications start flowing to the notificationUrl.

Resources that support lifecycle notifications


While you can provide a lifecycleNotificationUrl when creating a subscription on any
resource type, lifecycle notifications are currently supported only for the following
resource types.

reauthorizationRequired notifications - All resources


subscriptionRemoved notifications - Outlook message, Outlook event, Outlook
personal contact, Teams chatMessage
missed notifications - Outlook message, Outlook event, Outlook personal contact

Responding to reauthorizationRequired
notifications
reauthorizationRequired lifecycle events alert you when Microsoft Graph requires the

app to reauthorize the subscription, for example in the following cases:

When the access token is about to expire.


When a subscription is about to expire.
When a tenant administrator has revoked your app's permissions to read a
resource.

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#

//The following code is for illustrative purposes only


var TokenTimeToExpirationInMinutes=(TokenExpirationTime-CurrentTime)/4;

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:

1. Microsoft Graph requires a subscription to be reauthorized.

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.

2. Microsoft Graph sends an authorization challenge notification to the


lifecycleNotificationUrl.

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.

2. Validate the authenticity of the lifecycle notification.

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.

Call the /reauthorize action to reauthorize the subscription without


extending its expiration date.

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"
}

Renewing may fail if the app is no longer authorized to access to the


resource. It may then be necessary for the app to obtain a new access token
to successfully reauthorize a subscription.

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.

The frequency of authorization challenges is subject to change.

Don't assume the frequency of authorization challenges. These lifecycle


notifications tell you when to take actions, saving you from having to track which
subscriptions require reauthorization. Be ready to handle authorization challenges
from once every few minutes for every subscription to rarely for some of your
subscriptions.

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.

The following flow shows the flow of a subscriptionRemoved event:

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.

2. Microsoft Graph sends a subscriptionRemoved lifecycle notification to the


lifecycleNotificationUrl (if specified).

No lifecycle notifications are available from the period when the


subscriptionRemoved lifecycle notification was sent to when the app recreates the

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.

2. Validate the authenticity of the lifecycle notification.

3. Ensure that the app has a valid access token to take the next step.

4. Create a new subscription.

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.

Responding to missed notifications


missed lifecycle events alert you that some change notifications might not have been

delivered. For example, because of throttling.

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:

Handle special subscription lifecycle notifications to maintain an uninterrupted


flow of data. Microsoft Graph sends lifecycle notifications from time to time to
require an app to re-authorize, to make sure access issues have not unexpectedly
cropped up for including resource data in change notifications.
Validate the authenticity of change notifications as having originated from
Microsoft Graph.
Provide a public encryption key and use a private key to decrypt resource data
received through change notifications.

Resource data in notification payload


In general, this type of change notifications include the following resource data in the
payload:

ID and type of the changed resource instance, returned in the resourceData


property.
All the property values of that resource instance, encrypted as specified in the
subscription, returned in the encryptedContent property.
Or, depending on the resource, specific properties returned in the resourceData
property. To get only specific properties, specify them as part of the resource URL
in the subscription, using a $select parameter.

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.

Available in the v1.0 and beta endpoints:

New or changed messages in a specific Teams channel:


/teams/{id}/channels/{id}/messages

New or changed messages in all Teams channels: /teams/getAllMessages

New or changed messages in a specific Teams chat: /chats/{id}/messages

New or changed messages in all Teams chats: /chats/getAllMessages

New or changed messages in all Teams chats a particular user is part of:
/users/{id}/chats/getAllMessages

New or changed members in all Teams chats: /chats/getAllMembers

New or changed members in a specific Teams chat: /chats/{id}/members

New or changed chat across the entire tenant: /chats

Property changes in a specific chat: /chats/{id}

New or changed members in all channels under a specific team:


/teams/{id}/channels/getAllMembers

New or changed members in a specific team: /teams/{id}/members

New or changed team across the entire tenant: /teams

Property changes in a specific team: /teams/{id}

New or changed channels in all Teams teams: /teams/getAllChannels

New or changed channel in a specific team: /teams/{id}/channels

User's presence information update: /communications/presences/{id}

Available in only the beta endpoint:

New or changed personal contacts in a user's mailbox: /users/{id}/contacts


New or changed personal contacts in a user's contactFolder:
/users/{id}/contactFolders/{id}/contacts

New or changed events in a user's mailbox: /users/{id}/events

New or changed messages in a user's mailbox: /users/{id}/messages

New or changed messages in a user's mailFolder:


/users/{id}/mailFolders/{id}/messages

Teams Meeting status information updates: /communications/onlineMeetings/?


$filter=JoinWebUrl eq '{joinWebUrl}

New or changed members in all channels across the entire tenant:


/teams/getAllChannels/getAllMembers

Change notifications that include chatMessage, onlineMeeting, or presence resource


data consist of all the properties of the changed instance. They do not support returning
only selected properties of the instance.

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:

includeResourceData which should be set to true to explicitly request resource


data.
encryptionCertificate which contains only the public key that Microsoft Graph
uses to encrypt resource data. Keep the corresponding private key to decrypt the
content.
encryptionCertificateId which is your own identifier for the certificate. Use this ID
to match in each change notification, which certificate to use for decryption.

Keep the following in mind:

Validate both endpoints as described in Notification endpoint validation. If you


choose to use the same URL for both endpoints, you will receive and respond to
two validation requests.

Subscription request example


The following example subscribes to channel messages being created or updated in
Microsoft Teams.

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

HTTP/1.1 201 Created


Content-Type: application/json

{
"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)

Validating the authenticity of notifications


Apps often run business logic based on resource data included in change notifications.
Verifying the authenticity of each change notification first is important. Otherwise, a
third party can spoof your app with false change notifications and make it run its
business logic incorrectly, and this can lead to a security incident.

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:

Validation tokens in the change notification


How to validate
Example JWT token

Validation tokens in the change notification


A change notification with resource data contains an additional property,
validationTokens, which contains an array of JWT tokens generated by Microsoft Graph.
Microsoft Graph generates a single token for each distinct app and tenant pair for
whom there is an item in the value array. Keep in mind that change notifications may
contain a mix of items for various apps and tenants that subscribed using the same
notificationUrl.
Note: If you're setting up change notifications delivered through Azure Event Hubs,
Microsoft Graph will not send the validation tokens. Microsoft Graph does not need
to validate the notificationUrl.

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.

Be mindful of the following:

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.

In particular, perform validation on every JWT token in the validationTokens collection.


If any tokens fail, consider the change notification suspicious and investigate further.

Use the following steps to validate tokens and apps that generate tokens:

1. Validate that the token has not expired.

2. Validate the token has not been tampered with and was issued by the expected
authority, Microsoft identity platform:

Obtain the signing keys from the common configuration endpoint:


https://login.microsoftonline.com/common/.well-known/openid-

configuration . This configuration is cached by your app for a period of time.


Be aware that the configuration is updated frequently as signing keys are
rotated daily.
Verify the signature of the JWT token using those keys.

Do not accept tokens issued by any other authority.

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.

Validate the "audience" in the token matches your app ID.


If you have more than one app receiving change notifications, make sure to
check for multiple IDs.

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.

Example JWT token


The following is an example of the properties included in the JWT token that are needed
for validation.

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"
}

Example: Verifying validation tokens


C#

// add Microsoft.IdentityModel.Protocols.OpenIdConnect and


System.IdentityModel.Tokens.Jwt nuget packages to your project
public async Task<bool> ValidateToken(string token, string tenantId,
IEnumerable<string> appIds)
{
var configurationManager = new
ConfigurationManager<OpenIdConnectConfiguration>
("https://login.microsoftonline.com/common/v2.0/.well-known/openid-
configuration", new OpenIdConnectConfigurationRetriever());
var openIdConfig = await configurationManager.GetConfigurationAsync();
var handler = new JwtSecurityTokenHandler();
try
{
handler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ValidIssuer = $"https://sts.windows.net/{tenantId}/",
ValidAudiences = appIds,
IssuerSigningKeys = openIdConfig.SigningKeys
}, out _);
return true;
}
catch (Exception ex)
{
Trace.TraceError($"{ex.Message}:{ex.StackTrace}");
return false;
}
}

Java

private boolean IsValidationTokenValid(String[] appIds, String tenantId,


String serializedToken) {
try {
JwkKeyResolver jwksResolver = new JwkKeyResolver();
Jws<Claims> token = Jwts.parserBuilder()
.setSigningKeyResolver(jwksResolver)
.build()
.parseClaimsJws(serializedToken);
Claims body = token.getBody();
String audience = body.getAudience();
boolean isAudienceValid = false;
for(String appId : appIds) {
isAudienceValid = isAudienceValid || appId.equals(audience);
}
boolean isTenantValid = body.getIssuer().endsWith(tenantId + "/");
return isAudienceValid && isTenantValid; //nbf,exp and signature
are already validated by library
} catch (Exception e) {
LOGGER.error("could not validate token");
LOGGER.error(e.getMessage());
return false;
}
}

JavaScript

import jwt from 'jsonwebtoken';


import jkwsClient from 'jwks-rsa';

const client = jkwsClient({


jwksUri: 'https://login.microsoftonline.com/common/discovery/v2.0/keys'
});

export function getKey(header, callback) {


client.getSigningKey(header.kid, (err, key) => {
var signingKey = key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
});
}

export function isTokenValid(token, appId, tenantId) {


return new Promise((resolve) => {
const options = {
audience: [appId],
issuer: [`https://sts.windows.net/${tenantId}/`]
};
jwt.verify(token, getKey, options, (err) => {
if (err) {
// eslint-disable-next-line no-console
console.error(err);
resolve(false);
} else {
resolve(true);
}
});
});
}

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;

public class JwkKeyResolver extends SigningKeyResolverAdapter {


private JwkProvider keyStore;
private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
public JwkKeyResolver() throws java.net.URISyntaxException,
java.net.MalformedURLException {
this.keyStore = new UrlJwkProvider((new
URI("https://login.microsoftonline.com/common/discovery/keys").toURL()));
}
@Override
public Key resolveSigningKey(JwsHeader jwsHeader, Claims claims) {
try {
String keyId = jwsHeader.getKeyId();
Jwk pub = keyStore.get(keyId);
return pub.getPublicKey();
} catch (Exception e) {
LOGGER.error(e.getMessage());
return null;
}
}
}

Decrypting resource data from change


notifications
The resourceData property of a change notification includes only the basic ID and type
information of a resource instance. The encryptedData property contains the full
resource data, encrypted by Microsoft Graph using the public key provided in the
subscription. The property also contains values required for verification and decryption.
This is done to increase the security of customer data accessed via change notifications.
It is your responsibility to secure the private key to ensure that customer data cannot be
decrypted by a third party, even if they manage to intercept the original change
notifications.

In this section:

Managing encryption keys


Decrypting resource data
Example: decrypting a notification with encrypted resource data

Managing encryption keys


1. Obtain a certificate with a pair of asymmetric keys.

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.

3. When creating a subscription:

Provide the certificate in the encryptionCertificate property, using the


base64-encoded content that the certificate was exported in.

Provide your own identifier in the encryptionCertificateId property.


This identifier allows you to match your certificates to the change
notifications you receive, and to retrieve certificates from your certificate
store. The identifier can be up to 128 characters.

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.

2. Update existing subscriptions with the new certificate key.

Do this as part of regular subscription renewal.


Or, enumerate all subscriptions and provide the key. Use the PATCH
operation on the subscription and update the encryptionCertificate and
encryptionCertificateId properties.

3. Keep in mind the following:

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.

Decrypting resource data


To optimize performance, Microsoft Graph uses a two-step encryption process:

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:

1. Use the encryptionCertificateId property to identify the certificate to use.

2. Initialize an RSA cryptographic component (such as the .NET


RSACryptoServiceProvider) with the private key.

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.

Compare it to the value in dataSignature. If they do not match, assume the


payload has been tampered with and do not decrypt it.

5. Use the symmetric key with an Advanced Encryption Standard (AES) (such as the
.NET AesCryptoServiceProvider) to decrypt the content in data.

Use the following decryption parameters for the AES algorithm:


Padding: PKCS7
Cipher mode: CBC

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.

Example: decrypting a notification with encrypted


resource data
The following is an example change notification that includes encrypted property values
of a chatMessage instance in a channel message. The instance is specified by the
@odata.id value.

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.

Decrypt the symmetric key

C#

// Initialize with the private key that matches the encryptionCertificateId.


RSACryptoServiceProvider rsaProvider = ...;
byte[] encryptedSymmetricKey = Convert.FromBase64String(<value from dataKey
property>);

// Decrypt using OAEP padding.


byte[] decryptedSymmetricKey = rsaProvider.Decrypt(encryptedSymmetricKey,
fOAEP: true);

// Can now use decryptedSymmetricKey with the AES algorithm.

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

const base64encodedKey = 'base 64 encoded dataKey value';


const asymetricPrivateKey = 'pem encoded private key';
const decodedKey = Buffer.from(base64encodedKey, 'base64');
const decryptedSymetricKey = crypto.privateDecrypt(asymetricPrivateKey,
decodedKey);
// Can now use decryptedSymmetricKey with the AES algorithm.

Compare data signature using HMAC-SHA256

C#

byte[] decryptedSymmetricKey = <the aes key decrypted in the previous step>;


byte[] encryptedPayload = <the value from the data property, still
encrypted>;
byte[] expectedSignature = <the value from the dataSignature property>;
byte[] actualSignature;

using (HMACSHA256 hmac = new HMACSHA256(decryptedSymmetricKey))


{
actualSignature = hmac.ComputeHash(encryptedPayload);
}
if (actualSignature.SequenceEqual(expectedSignature))
{
// Continue with decryption of the encryptedPayload.
}
else
{
// Do not attempt to decrypt encryptedPayload. Assume notification
payload has been tampered with and investigate.
}

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

const decryptedSymetricKey = []; //Buffer provided by previous step


const base64encodedSignature = 'base64 encodded value from the dataSignature
property';
const hmac = crypto.createHmac('sha256', decryptedSymetricKey);
hmac.write(base64encodedPayload, 'base64');
if(base64encodedSignature === hmac.digest('base64'))
{
// Continue with decryption of the encryptedPayload.
}
else
{
// Do not attempt to decrypt encryptedPayload. Assume notification
payload has been tampered with and investigate.
}

Decrypt the resource data content

C#

AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider();


aesProvider.Key = decryptedSymmetricKey;
aesProvider.Padding = PaddingMode.PKCS7;
aesProvider.Mode = CipherMode.CBC;

// Obtain the intialization vector from the symmetric key itself.


int vectorSize = 16;
byte[] iv = new byte[vectorSize];
Array.Copy(decryptedSymmetricKey, iv, vectorSize);
aesProvider.IV = iv;
byte[] encryptedPayload = Convert.FromBase64String(<value from data
property>);

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();
}
}
}
}

// decryptedResourceData now contains a JSON string that represents the


resource.

Java

SecretKey skey = new SecretKeySpec(decryptedSymmetricKey, "AES");


IvParameterSpec ivspec = new
IvParameterSpec(Arrays.copyOf(decryptedSymmetricKey, 16));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skey, ivspec);
String decryptedResourceData = new
String(cipher.doFinal(Base64.decodeBase64(encryptedData)));

JavaScript

const base64encodedPayload = 'base64 encoded value from data property';


const decryptedSymetricKey = []; //Buffer provided by previous step
const iv = Buffer.alloc(16, 0);
decryptedSymetricKey.copy(iv, 0, 0, 16);
const decipher = crypto.createDecipheriv('aes-256-cbc',
decryptedSymetricKey, iv);
let decryptedPayload = decipher.update(base64encodedPayload, 'base64',
'utf8');
decryptedPayload += decipher.final('utf8');

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.

Get started with change notifications


Before you can take advantage of change notifications via Microsoft Graph, you must
register your application in Azure and provision your application in the customers Azure
Active Directory (Azure AD) tenant. Make sure that the application has the required
permission scopes enabled, as described later in this article.

Notifications and subscriptions


Universal Print currently supports notifications for two scenarios related to print jobs:

PrintTask is triggered (JobStarted): An application can subscribe to receive


notifications when their printTask(hook) is triggered. For details about how to
trigger a task, see Enable pull printing. Currently, a printTask can be triggered only
for a JobStarted event. A JobStarted event is raised when a print job has been
successfully created, its payload has been uploaded, and job processing has
started.

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

For listening to the change notifications for JobFetchable event, a


printTaskDefinition resource is not required.

The application should handle duplicate notifications.

Create an application to listen to notifications


For information about how to listen for Microsoft Graph notifications, see Use change
notifications and track changes with Microsoft Graph and Set up notifications for
changes in user data – Code Samples.

Permission scopes
To subscribe to notifications for print jobs, applications must have the following
permission scopes approved in the customer’s Azure AD tenant:

For printTask triggered (JobStarted) event, the permissions listed in Get


taskDefinition.

For JobFetchable event, the permissions listed in Create subscription.

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.

Create subscription: printTask triggered


(JobStarted) event
Some applications monitor print queues for incoming jobs and want to be notified as
soon as there is a valid job in the queue. After they're notified, they can collect the
relevant job metadata or even perform modifications in the print job – including
aborting the job or redirecting the job from the current print queue to another queue
after modifying the job attributes accordingly.

Before creating a notification for a printTask-triggered event, ensure that application


has created the following:
A printTaskDefinition for the customer’s Azure AD tenant. A single task definition
can be associated with one or more printers within the same Azure AD tenant.

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:

The resource field needs to be set as print/taskDefinitions/{printTaskDefinition


ID}/tasks .
The changeType field needs to be set as created .
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":"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

HTTP/1.1 201 Created


Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
"id": "{Subscription ID}",
"resource": "print/taskDefinitions/{printTaskDefinition ID}/tasks",
"applicationId": "{application ID}",
"changeType": "created",
"clientState": "secret",
"notificationUrl": "{URL for receiving the event – e.g.
https://webhookappexample.azurewebsites.net/api/notifications}",
"notificationQueryOptions": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2020-12-30T22:42:09Z",
"creatorId": "{Creator ID}",
"includeResourceData": null,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": null,
"encryptionCertificateId": null
}

Create subscription: JobFetchable event


Some cloud applications need to download print jobs from Universal Print when they
are ready. Because these applications running in the cloud are not behind the
customer's firewall, they can use Microsoft Graph change notifications to be notified
when a print job is ready to be downloaded.

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 resource field needs to be set as 'print/printers/{printer id}/jobs'.


The changeType field needs to be set as updated .
The notificationQueryOptions field needs to be set as $filter = isFetchable eq
true .

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

HTTP/1.1 201 Created


Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
"id": "{Subscription ID}",
"resource": "print/printers/{printer ID}/jobs",
"applicationId": "{Application ID}",
"changeType": "updated",
"clientState": "mysecret",
"notificationUrl": "{URL for receiving the event – e.g.
https://webhookappexample.azurewebsites.net/api/notifications}",
"notificationQueryOptions": "$filter = isFetchable eq true",
"lifecycleNotificationUrl": null,
"expirationDateTime": "2020-12-30T22:42:09Z",
"creatorId": "{Creator ID}",
"includeResourceData": null,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": null,
"encryptionCertificateId": null
}
Renew a notification subscription
Microsoft Graph has a limit on the expiration time. For details, see maximum expiration
time. To continue receiving notifications, the subscription needs to be renewed
periodically by using the Update subscription API.

Get or delete notification subscriptions


Applications can get details of the subscription or delete a subscription when required.
For details, see Use the Microsoft Graph API to get change notifications.

FAQs

How does Microsoft Graph validate notification URLs?


Microsoft Graph validates the notification endpoint provided in the notificationUrl
property of the subscription request before creating the subscription. For details, see
Notification endpoint validation.

What are applications expected to do after receiving a


change notification?
Applications should process and acknowledge every change notification they receive.
For details, see Processing the change notification.

How can I validate the authenticity of notifications?


The authenticity of notifications can either be validated using clientState value as
described in Processing the change notification or validating tokens in the change
notification.

How can I get a list of active subscriptions?


For details about how to retrieve a list of webhook subscriptions, see List subscriptions.

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

The maximum time a subscription can last is 60 minutes; however, subscriptions


can be renewed until the caller has permissions to access the resource.

Change notification types


Microsoft Teams supports two types of change notifications:

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 channel Changes to channels in all teams: Yes


/teams/getAllChannels
Changes to channel in a specific team:
/teams/{id}/channels

Teams chat Changes to any chat in the tenant: Yes


/chats
Changes to a specific chat:
/chats/{id}
Changes to any chat in the tenant where a particular Teams
app is installed:
/appCatalogs/teamsApps/{id}/installedToChats

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

Teams Changes to membership in a specific team: Yes


conversationMember /teams/{id}/members
Changes to membership in a specific chat:
/chats/{id}/members
Changes to membership in all chats:
/chats/getAllMembers
Changes to membership in all channels under a specific team:
teams/{id}/channels/getAllMembers
Changes to membership in all the chats in the tenant where a
particular Teams app is installed:
/appCatalogs/teamsApps/{id}/installedToChats/getAllMembers
Changes to membership in all channels across the tenant:
teams/getAllChannels/getAllMembers
Resource Supported resource paths Resource
data can be
included in
notifications

Teams team Changes to any team in the tenant: Yes


/teams
Changes to a specific team:
/teams/{id}

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.

Notifications with resource data


For notifications with resource data, the payload looks like the following. This payload is
for a notification corresponding to the chat message resource. The actual notification
includes the resource and resourceData properties, which represent the resource that
has triggered the notification.

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": []
}

Notifications without resource data


Notifications without resource data give you enough information to make GET calls to
get the resource. Subscriptions for notifications without resource data don't require an
encryption certificate (because actual resource data is not sent over).

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')"
}
}

Previous example above shows a notification that corresponds to a chat message


resource. The actual notification includes the resource and resourceData properties,
which represent the resource that has triggered the notification. The resource and
@odata.id properties can be used 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 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.

Subscribe to changes in any team at tenant


level
To get change notifications for all changes (create, update, and delete) related to any
team in a tenant, subscribe to /teams . This resource supports including resource data in
the notification.

Permissions

Permission type Permissions (from least to most privileged)

Delegated (work or school Not supported.


account)

Delegated (personal Microsoft Not supported.


account)

Application Team.ReadBasic.All, TeamSettings.Read.All,


TeamSettings.ReadWrite.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",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}

Subscribe to changes in a particular team


To get change notifications for all changes related to a particular team in a tenant,
subscribe to /teams/{team-id} . This resource supports including resource data in the
notification.

Permissions

Permission type Permissions (from least to most privileged)

Delegated (work or Team.ReadBasic.All, TeamSettings.Read.All, TeamSettings.ReadWrite.All


school account)

Delegated (personal Not supported.


Microsoft account)

Application TeamSettings.Read.Group*, TeamSettings.ReadWrite.Group*,


Team.ReadBasic.All, TeamSettings.Read.All, TeamSettings.ReadWrite.All

Note: Permissions marked with * are supported as part of resource-specific consent.

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}"
}

Subscribe to changes in any channel at tenant


level
To get change notifications for all changes (create, update, and delete) related to any
channel in a tenant, subscribe to /teams/getAllChannels . This resource supports
including resource data in the notification.

Continue with this article about scenarios for the channel or chat context. Or, find out
about change notifications for other Microsoft Teams resources.

Permissions

Permission type Permissions (from least to most privileged)

Delegated (work or school Not supported.


account)

Delegated (personal Microsoft Not supported.


account)

Application Channel.ReadBasic.All, ChannelSettings.Read.All,


ChannelSettings.ReadWrite.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/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

Permission type Permissions (from least to most privileged)

Delegated (work or Channel.ReadBasic.All, ChannelSettings.Read.All,


school account) ChannelSettings.ReadWrite.All

Delegated Not supported.


(personal Microsoft
account)

Application ChannelSettings.Read.Group*, ChannelSettings.ReadWrite.Group*,


Channel.ReadBasic.All, ChannelSettings.Read.All,
ChannelSettings.ReadWrite.All

Note: Permissions marked with * are supported as part of resource-specific consent.

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}"
}

Notifications with resource data


For notifications with resource data, the payload looks like the following. This payload is
for a property change in a team.

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.

Note: discoverySettings and classSettings aren't exposed in payload data.

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
}

Notifications without resource data


Notifications without resource data give you enough information to make GET calls to
get the message content. Subscriptions for notifications without resource data don't
require an encryption certificate (because actual resource data is not sent over).

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.

Note: Channel email address isn't returned in the payload.

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

Change notifications enable you to subscribe to membership changes (create, update,


and delete) in a team or private channel. You can get notified whenever a member is
added, removed, or updated in a team or in a private channel. 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
team or channel context. Or, find out about change notifications for other Microsoft
Teams resources.

Subscribe to changes in membership of a


particular team
To get change notifications for membership changes in a particular team, subscribe to
/teams/{team-id}/members . This resource supports including resource data in the
notification.

Permissions

Permission type Permissions (from least to most privileged)

Delegated (work or school TeamMember.Read.All, TeamMember.ReadWrite.All


account)

Delegated (personal Microsoft Not supported.


account)

Application TeamMember.Read.Group*, TeamMember.Read.All,


TeamMember.ReadWrite.All

Note: Permissions marked with * are supported as part of resource-specific consent.

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}"
}

Subscribe to membership changes in all teams


across the tenant
To get change notifications for membership changes in all teams across the tenant,
subscribe to /teams/getAllMembers . This resource supports including resource data in
the notification.

Permissions

Permission type Permissions (from least to most privileged)

Delegated (work or school account) Not supported.

Delegated (personal Microsoft account) Not supported.

Application TeamMember.Read.All, TeamMember.ReadWrite.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/getAllMembers",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2022-08-10T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}

Subscribe to membership changes in all


channels across the tenant (preview)
To get change notifications for membership changes in all channels across the tenant,
subscribe to /teams/getAllChannels/getAllMembers . This resource supports including
resource data in the notification. Currently, only private channels are supported. This
subscription is only available in the beta endpoint.

Permissions

Permission type Permissions (from least to most privileged)

Delegated (work or school account) Not supported.

Delegated (personal Microsoft Not supported.


account)

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 resource doesn't support delegated context in v1.0.

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

Permission type Permissions (from least to most privileged)

Delegated (work or school account) ChannelMember.Read.All.

Delegated (personal Microsoft account) Not supported.

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}"
}

Notifications with resource data


For notifications with resource data, the payload looks like the following. This payload is
for a membership change in a team.

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
}

Notifications without resource data


Notifications without resource data give you enough information to make GET calls to
get the message content. Subscriptions for notifications without resource data don't
require an encryption certificate (because actual resource data is not sent over).

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.

Subscribe to changes at the tenant level


To track all changes related to messages in a tenant, you can use subscriptions at a
tenant level for channel and chat messages. This requires you to create two
subscriptions: one to track all messages across channels, and one to track all messages
across chats.

Subscribe to messages across all channels


To get change notifications for all messages and replies across channels in a tenant,
subscribe to /teams/getAllMessages . 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

Permission type Permissions (from least to most privileged)

Delegated (work or school account) Not supported.

Delegated (personal Microsoft account) Not supported.


Permission type Permissions (from least to most privileged)

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}"
}

Subscribe to messages across all chats


To get change notifications for all messages across chats in a tenant, subscribe to
/chats/getAllMessages . 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

Permission type Permissions (from least to most privileged)

Delegated (work or school account) Not supported.

Delegated (personal Microsoft account) Not supported.

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}"
}

Subscribe to messages in a channel


To track messages and replies in a channel, you can create a change notification
subscription at a channel level. To do this, subscribe to /teams/{team-
id}/channels/{channel-id}/messages . This resource supports including resource data in

the notification in both delegated and application-only mode.

Channel-level subscriptions also support keyword-based search via the $search query
parameter.

Permissions

Permission type Permissions (from least to most privileged)

Delegated (work or school account) ChannelMessage.Read.All

Delegated (personal Microsoft Not supported.


account)

Application ChannelMessage.Read.Group*,
ChannelMessage.Read.All

Note: Permissions marked with * are supported as part of resource-specific consent.

Example 1: Subscribe to all messages (and replies) in a


channel
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",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}

Example 2: Subscribe to messages (and replies) in a


channel that contain certain text
The following request will send messages that contain Hello to the subscriber.

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}"
}

Example 3: Subscribe to messages (and replies) in a


channel without resource data
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",
"includeResourceData": false,
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}

Example 4: Subscribe to messages (and replies) in a


channel that mention a specific user
To get notifications only for messages where a specific user has been mentioned, you
can specify the user's ID ( 9a6eb4d1-826b-48b1-9627-b50836c8fee9 in this example) in the
query.

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}"
}

Subscribe to messages in a chat


To track messages in a chat, you can create a change notification subscription at a chat
level. To do this, subscribe to /chats/{chat-id}/messages . This resource supports
including resource data in the notification in both delegated and application-only mode.

Chat-level subscriptions also support keyword-based search via the $search query
parameter.

Permissions
Permission type Permissions (from least to most privileged)

Delegated (work or school account) Chat.Read

Delegated (personal Microsoft account) Not supported.

Application ChatMessage.Read.Chat*, Chat.Read.All

Note: Permissions marked with * are supported as part of resource-specific consent


for the beta version only currently.

Example 1: Subscribe to messages in a chat


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",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}

Example 2: Subscribe to messages in a chat that contain


certain text
The following request will send messages that contain Hello to the subscriber.

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}"
}

Example 3: Subscribe to messages (and replies) in a chat


without resource data
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",
"includeResourceData": false,
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}

Example 4: Subscribe to message in a chat in which a


specific user is mentioned
To get notifications only for messages in which a specific user has been mentioned, you
can specify the user's ID ( 9a6eb4d1-826b-48b1-9627-b50836c8fee9 in this example) in the
query.

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}"
}

Subscribe to changes at the user level


To track messages across all chats a particular user is part of, you can create a change
notification subscription at a user level. To do this, subscribe to /users/{user-
id}/chats/getAllMessages . This resource supports including resource data in the

notification in both delegated and application-only modes.

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

Permission type Permissions (from least to most privileged)

Delegated (work or school account) Chat.Read, Chat.ReadWrite

Delegated (personal Microsoft account) Not supported.

Application Chat.Read.All, Chat.ReadWrite.All

Example: Subscribe to messages across all chats a


particular user is part of
HTTP

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}"
}

Subscribe to messages of any chat in a tenant


where a specific Teams app is installed
To get change notifications for all messages across chats in a tenant where a specific
Teams app is installed, subscribe to /appCatalogs/teamsApps/{teams-app-
id}/installedToChats/getAllMessages . This resource supports including resource data 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

Permission type Permissions (from least to most privileged)

Delegated (work or school account) Not supported.

Delegated (personal Microsoft Not supported.


account)

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": []
}

Notifications without resource data


Notifications without resource data give you enough information to make GET calls to
get the message content. Subscriptions for notifications without resource data do not
require an encryption certificate (because actual resource data isn't sent over).

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.

Subscribe to changes in any chat at tenant level


To get change notifications for all changes (create and update) related to any chat in a
tenant, subscribe to /chats . This resource supports including resource data in the
notification.

Permissions

Permission type Permissions (from least to most privileged)

Delegated (work or school account) Not supported.

Delegated (personal Microsoft account) Not supported.

Application Chat.ReadBasic.All, Chat.Read.All, Chat.ReadWrite.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": "/chats",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}

Subscribe to changes in a particular chat


To get change notifications for all changes related to a particular chat, subscribe to
/chats/{id} . This resource supports including resource data in the notification.

Permissions

Permission type Permissions (from least to most privileged)

Delegated (work or Chat.ReadBasic, Chat.Read, Chat.ReadWrite


school account)

Delegated (personal Not supported.


Microsoft account)

Application ChatSettings.Read.Chat*, ChatSettings.ReadWrite.Chat*,


Chat.Manage.Chat*, Chat.ReadBasic.All, Chat.Read.All, Chat.ReadWrite.All

Note: Permissions marked with * use resource-specific consent.

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}"
}

Notifications with resource data


For notifications with resource data, the payload looks like the following. This payload is
for a property change in a chat.

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": []
}

Subscribe to changes in any chat in a tenant


where a Teams app is installed
To get change notifications for all changes related to any chat in a tenant where a
specific Teams app is installed, subscribe to /appCatalogs/teamsApps/{teams-app-
id}/installedToChats . This resource supports including resource data 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
Permission type Permissions (from least to most privileged)

Delegated (work or school Not supported.


account)

Delegated (personal Not supported.


Microsoft account)

Application Chat.ReadBasic.WhereInstalled, 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",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}

Notifications without resource data


The following payload describes the information sent in the request for notifications
without resource data. This particular payload signifies that a new chat has been created.

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.

Subscribe to changes in membership of any


chat at tenant level
To get change notifications for membership changes in any chat across the tenant,
subscribe to /chats/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

Permission type Permissions (from least to most privileged)

Delegated (work or Not supported.


school account)

Delegated (personal Not supported.


Microsoft account)

Application ChatMember.Read.All, ChatMember.ReadWrite.All, Chat.ReadBasic.All,


Chat.Read.All, Chat.ReadWrite.All

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}"
}

Subscribe to changes in membership of a


particular chat
To get change notifications for membership changes in a particular chat, subscribe to
/chats/{id}/members . This resource supports including resource data in the notification.

Permissions

Permission type Permissions (from least to most privileged)

Delegated (work or ChatMember.Read, ChatMember.ReadWrite, Chat.ReadBasic, Chat.Read,


school account) Chat.ReadWrite

Delegated Not supported.


(personal
Microsoft account)

Application ChatMember.Read.Chat*, Chat.Manage.Chat*, ChatMember.Read.All,


ChatMember.ReadWrite.All, Chat.ReadBasic.All, Chat.Read.All,
Chat.ReadWrite.All

Note: Permissions marked with * use resource-specific consent.

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}"
}

Subscribe to changes in membership of any


chat in a tenant where a Teams app is installed
To get change notifications for membership changes in any chat across the tenant
where a specific Teams app is installed, subscribe to /appCatalogs/teamsApps/{teams-
app-id}/installedToChats/getAllMembers . This resource supports including resource data

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

Permission type Permissions (from least to most privileged)

Delegated (work Not supported.


or school
account)

Delegated Not supported.


(personal
Microsoft
account)

Application ChatMember.Read.WhereInstalled, ChatMember.ReadWrite.WhereInstalled,


Chat.ReadBasic.WhereInstalled, 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/getAllMembers",
"includeResourceData": true,
"encryptionCertificate": "{base64encodedCertificate}",
"encryptionCertificateId": "{customId}",
"expirationDateTime": "2019-09-19T11:00:00.0000000Z",
"clientState": "{secretClientState}"
}

Notifications with resource data


For notifications with resource data, the payload looks like the following. This payload is
for a membership change in a chat.

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
}

Notifications without resource data


The following payload describes the information sent in the request for notifications
without resource data. This particular payload signifies that a user has been added to a
chat.

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.

Subscribe to changes in contacts, calendar, or


mail
To subscribe to change notifications of Outlook resources, first create a subscription.

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:

Delegated permission supports subscribing to items in folders in only the signed-in


user's mailbox. For example, you cannot use the delegated permission Calendars.Read
to subscribe to events in another user’s mailbox.

To subscribe to change notifications of Outlook contacts, events, or messages in


shared or delegated folders:
Use the corresponding application permission to subscribe to changes of items in a
folder or mailbox of any user in the tenant.
Do not use the Outlook sharing permissions (Contacts.Read.Shared,
Calendars.Read.Shared, Mail.Read.Shared, and their read/write counterparts), as
they do not support subscribing to change notifications on items in shared or
delegated folders.

Depending on the resource, use the least privileged permission specified in the following
table to call this API.

Resource Supported Resource Paths Delegated Delegated Application


(work or (personal
school Microsoft
account) account)

contact Changes to all personal contacts in a user's Contacts.Read Contacts.Read Contacts.Read


mailbox:
/me/contacts
/users/{id}/contacts
Changes to contacts in a user's
contactFolder:
/users/{id}/contactFolders/{id}/contacts

event Changes to all events in a user's mailbox: Calendars.Read Calendars.Read Calendars.Read


/me/events
/users/{id}/events

message Changes to all messages in a user's Mail.ReadBasic, Mail.ReadBasic, Mail.ReadBasic,


mailbox: Mail.Read Mail.Read Mail.Read
/me/messages
/users/{id}/messages
Changes to messages in a user's
mailFolder:
/users/{id}/mailFolders/{id}/messages

Include resource data in notification payload (preview)


7 Note

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:

includeResourceData: Set this property to true to explicitly request resource data.

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

Do not include in the URL $top , $skip , $orderby , $select=Body,UniqueBody , and


$expand other than singleValueExtendedProperties or
multiValueExtendedProperties.

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.

Refine the conditions for a notification


You can further refine the conditions for a notification by using the $filter query
parameter. See an example.

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:

A message added to or marked unread in the folder would trigger a Created


notification.
Reading a message or marking it as read in the folder would trigger a Deleted
notification.
A change to any property, other than isRead, of a message resource in the folder
would trigger an Updated notification.

If you don’t use a $filter when creating the subscription:

Adding a message to the folder would result in a Created notification.


Reading a message in the folder, marking the message as read, or changing any other
property of a message in that folder would result in an Updated notification.
Deleting the message would result in a Delete notification.

Subscribe to lifecycle notifications


The Outlook contact, event, and message resources also support subscribing to lifecycle
notifications. Lifecycle notifications are needed in case your app gets their subscriptions
removed or misses some change notifications. Apps should implement logic to detect and
recover from the loss, and resume a continuous change notification flow. To learn more, see
subscribing to lifecycle notifications.

Keep track of subscription lifetime


Make sure to extend a subscription before it expires. The maximum lifetime for a
subscription without Outlook resource data is 4230 minutes (under 3 days), and 1 day with
resource data.

If you lose the permission granted earlier for a subscription and the subscription expires
meanwhile, request permission again to create a new subscription.

Receive notification payloads


Depending on your subscription, notifications may include resource data. Subscriptions
with resource data allow you to get the resource payload along with the notification,
avoiding the overhead for a separate API call to get the changed resource data.

Receive notifications with resource data (preview)


The following is an example of the payload of a notification with resource data of a
message resource. The resource and resourceData properties correspond to the message
instance that triggered the notification. Use the encryptedContent property to decrypt the
resource data.
JSON

{
"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.

The following is an example of a decrypted notification payload. The decrypted payload


conforms to the Outlook message schema. The payload is similar to that returned by a GET
message operation. However, the notification payload contains only those properties
specified with a $select parameter in the resource property of the subscription.
Notification payloads for other Outlook resources like contact and event follow their
respective schemas.

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]"
}
}
}

Receive notifications without resource data


Notifications without resource data give you enough information to make GET calls to get
the resource. Subscriptions for notifications without resource data don't require an
encryption certificate, because the actual resource data is not sent over.

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

Example 1: Create a subscription to get change notifications


without resource data when the user receives a new
message
The following example requests a notification for a message being created in the user's
mailbox.

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

The following is an example of the 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/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
}

Example 2: Create a subscription to get change


notifications with resource data when the user receives a
new message (preview)
The following example subscribes to notifications with resource data for a message being
created in the user's mailbox. The properties of the message resource to be included in the
notification payload are specified using the $select query parameter.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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
}

Example 3: Create a subscription to get change


notifications with resource data for a message based on a
condition (preview)
The following example subscribes to notifications with resource data for a message being
created in the Drafts folder, containing one or more attachments, and of high importance.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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.

Use delta query to track changes in a resource


collection
The typical call pattern is as follows:

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.

a. If a @odata.nextLink URL is returned, there may be additional pages of data to


be retrieved in the session. The application continues making requests using the
@odata.nextLink URL to retrieve all pages of data until a @odata.deltaLink URL is

returned in the response.

b. If a @odata.deltaLink URL is returned, there is no more data about the existing


state of the resource to be returned. For future requests, the application uses the
@odata.deltaLink URL to learn about changes to the resource.

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

and the response will contain a @odata.deltaLink and no resource data.


Resources in OneDrive and SharePoint also support this feature. For resources
in OneDrive and SharePoint, append token=latest instead.
The delta query function is generally referred to by appending /delta to the
resource name. However, /delta is a shortcut for the fully qualified name
/microsoft.graph.delta that you see in requests generated by the Microsoft

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 ,

and a @odata.deltaLink URL includes a $deltaToken .

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.

Optional query parameters


If a client uses a query parameter, it must be specified in the initial request. Microsoft
Graph automatically encodes the specified parameter into the @odata.nextLink or
@odata.deltaLink provided in the response. The calling application only needs to
specify the query parameters once upfront. Microsoft Graph adds the specified
parameters automatically for all subsequent requests.

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:

$expand is not supported.

$top is not supported.

$orderby is not supported.

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

groups respectively. Selecting those properties allows tracking of changes to user's


manager and group memberships.

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'

Resource representation in the delta query


response
Newly created instances of a supported resource are represented in the delta
query response using their standard representation.

Updated instances are represented by their id with at least the properties that have
been updated, but additional properties may be included.

Relationships on users and groups are represented as annotations on the standard


resource representation. These annotations use the format propertyName@delta.
The annotations are included in the response of the initial delta query request.

Removed instances are represented by their id and an @removed object. The


@removed object may include additional information about why the instance was
removed. For example, "@removed": {"reason": "changed"} .

Possible @removed reasons can be changed or deleted .

changed indicates the item was deleted and can be restored from deletedItems.

deleted indicates the item is deleted and cannot be restored.

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.

Resource collection API

Applications delta function of the application resource

Administrative units delta function of the administrativeUnit resource

Chat messages in a channel delta function (preview) of the chatMessage


resource

Device objects delta function of the device resource

Directory roles delta function of the directoryRole resource

Directory objects delta function of the directoryObject resource

Drive items* delta function of the driveItem resource

Education assignments delta function of the educationAssignment


resource

Education categories delta function of the educationCategory resource

Education classes delta function of the educationClass resource

Education schools delta function of the educationSchool resource

Education users delta function of the educationUser resource

Events in a calendar view (date range) of the delta function of the event resource
primary calendar

Groups delta function of the group resource

List items* delta function of the listItem resource

Mail folders delta function of the mailFolder resource

Messages in a folder delta function of the message resource

Organizational contacts delta function of the orgContact resource


Resource collection API

OAuth2PermissionGrants delta function of the oauth2permissiongrant


resource

Personal contact folders delta function of the contactFolder resource

Personal contacts in a folder delta function of the contact resource

Planner buckets (preview) delta function (preview) of the plannerBucket


resource

Planner items** (preview) delta function (preview) of the all segment of


plannerUser resource

Planner plans (preview) delta function (preview) of the plannerPlan


resource

Planner tasks (preview) delta function (preview) of the plannerTask


resource

Service principals delta function of the servicePrincipal resource

To-do tasks in a task list delta function of the todoTask resource

To-do task lists delta function of the todoTaskList resource

Users delta function of the user resource

* 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

Properties stored outside of the main data store


Some resources contain properties that are stored outside of the main data store for the
resource (for example, the user resource is mostly stored in the Azure AD system, while
some properties, like skills, are stored in SharePoint Online). Currently, those properties
are not supported as part of change tracking; a change to one of those properties will
not result in an object showing up in the delta query response. Currently, only the
properties stored in the main data store trigger changes in the delta query.

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

HTTP/1.1 501 Not Implemented


Content-type: application/json

{
"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.

For directory objects, the limit is seven days.


For education objects (educationSchool, educationUser, and educationClass), the
limit is seven days.
For Outlook entities (message, mailFolder, event, contact, contactFolder,
todoTask, and todoTaskList), the upper limit is not fixed; it's dependent on the size
of the internal delta token cache. While new delta tokens are continuously added
in the cache, after the cache capacity is exceeded, the older delta tokens are
deleted.

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.

Delta query request examples


Training module: Use change notifications and track changes with Microsoft Graph
Get incremental changes to events in a calendar view
Get incremental changes to messages in a folder
Get incremental changes to groups
Get incremental changes to users
Get incremental changes to events in a
calendar view
Article • 03/02/2023

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

The capability for the former—getting incremental changes to events in a calendar


not bound to a fixed start and end date range—is currently available only in the
beta version. For more information, see delta function.

A calendar view is a collection of events in a date/time range (../me/calendarView) from


the default calendar or some other specified calendar of a user or from a group
calendar. The returned events may include single instances or occurrences and
exceptions of a recurring series. The delta data enables you to maintain and synchronize
a local store of a user's events without having to fetch the entire set of the user's events
from the server every time.

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.

Track event changes in a calendar view


Delta query for events in a calendar view is specific to a calendar and date/time range
that you specify. To track the changes in multiple calendars, you need to track each
calendar individually.

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}

A GET request with the delta function returns either:

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 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.

Use query parameters in a delta query for calendar view


Include the startDateTime and endDateTime parameters to define a date/time
range for your calendar view.
$select is not supported.

Optional request header


Each delta query GET request returns a collection of one or more events in the response.
You can optionally specify the request header, Prefer: odata.maxpagesize={x} , to set
the maximum number of events in a response.

Example: synchronize events in a calendar view


The following example shows a series of 3 requests to synchronize the user's default
calendar in a specific time range. There are 5 events in that calendar view.

Step 1: sample initial request and response


Step 2: sample second request and response
Step 3: sample third request and final response

For brevity, the sample responses show only a subset of the properties for an event. In
an actual call, most event properties are returned.

See what you'll do in the next round.

Step 1: sample initial request


In this example, the specified calendar view in the signed-in user's default calendar is
being synchronized for the first time, so the initial sync request does not include any
state token. This round will return all the events in that calendar view.

The first request specifies the following:

Date/time values for the startDateTime and endDateTime parameters.


The optional request header, odata.maxpagesize, returning 2 events at a time.

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

Sample initial response


The response includes two events and a @odata.nextLink response header with a
skipToken . The @odata.nextLink URL indicates there are more events in the calendar

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="
}
]
}

Step 2: sample second request


The second request specifies the @odata.nextLink URL returned from the previous
response. Notice that it no longer has to specify the same startDateTime and
endDateTime parameters as in the initial request, as the skipToken in the
@odata.nextLink URL encodes and includes them.

HTTP

HTTP

GET https://graph.microsoft.com/v1.0/me/calendarView/delta?
$skiptoken=R0usmcCM996atia_s HTTP/1.1
Prefer: odata.maxpagesize=2

Sample second response


The second response returns the next 2 events in the calendar view and another
@odata.nextLink , indicating there are more events to get from the calendar view.

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

Sample third and final response


The third response returns the only remaining event in the calendar view, and a
@odata.deltaLink URL which indicates synchronization is complete for this calendar

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="
}
]
}

The next round: sample first request


Using the @odata.deltaLink from the last request in the last round, you will be able to
get only those events that have changed (by being added, deleted, or updated) in that
calendar view 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

HTTP

GET https://graph.microsoft.com/v1.0/me/calendarView/delta?
$deltatoken=R0usmcMDNGg0J1E HTTP/1.1
Prefer: odata.maxpagesize=2

The next round: sample first response


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=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.

Track changes to groups


Track groups changes through one or more GET requests with the delta function. The
GET request is like a list groups request, except with the following extra objects in the
URL:

The delta function.


A state token (deltaToken or skipToken) from the previous GET delta function call.

Example: track changes to groups


The following example shows a series of requests to track changes to groups:

1. An initial request and response


2. A nextLink request and response
3. A final nextLink request and response
4. A deltaLink request and deltaLink response

Take note of the following in the responses:

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" .

When the group is created, or restored, there's no annotation.


Initial request
To track changes in the group resource, make a request and include the delta function
as a URL segment.

Take note of the following items:

The optional $select query parameter is included in the request to demonstrate


how query parameters are automatically included in future requests.
The optional $select query parameter is also used to show how group members
can be retrieved together with group objects. This allows tracking of membership
changes, such as when users are added or removed from groups.
The initial request doesn't include a state token. State tokens will be used in
subsequent requests.

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

@odata.deltaLink parameter) is returned in the final response, even if the value is an


empty array.

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"
}
]
}
]
}

Final nextLink request


The third request uses the latest @odata.nextLink returned from the last sync request.
HTTP

HTTP

GET https://graph.microsoft.com/v1.0/groups/delta?
$skiptoken=ppqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjtQ5LOhVoS7qQG_wdVC
HHlbQpga7

Final nextLink response


When a @odata.deltaLink URL is returned, there's no more data about the existing state
of group objects. For future requests, the application uses the @odata.deltaLink URL to
learn about other changes to groups. Save the deltaToken and use it in the subsequent
request URL to discover more changes to groups.

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:

Newly created group objects.


Deleted group objects.
Group objects for which a property has changed (for example, displayName has
been modified).
Group objects for which member objects have been added or removed.

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"
}
]
}
]
}

Some things to note about the previous example response:

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.

members@delta contains the following changes to the group membership.

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).

The second user has been added to the group.

Paging through members in a large group


The members@delta property is included in group objects by default, when the $select
query parameter hasn't been specified, or when the $select=members parameter is
explicitly specified. For groups with many members, it's possible that all members can't
fit into a single response. Implement the following pattern to handle such cases.

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.

We recommend the following best practices to correctly handle this pattern:

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.

Track message changes in a folder


Delta query is a per-folder operation. To track the changes of the messages in a folder
hierarchy, you need to track each folder individually.

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 GET request with the delta function returns either:

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.

The rest of this article includes 2 examples:

See example 1 to learn how to use the @odata.nextLink and @odata.deltaLink


URLs.
See example 2 to learn how to incrementally get only messages created since the
initial round.

Use query parameters in a delta query for messages


You can use a $select query parameter as in any GET request to specify only the
properties your need for best performance. The id property is always returned.
Delta query support $select , $top , and $expand for messages.
There is limited support for $filter and $orderby :
The only supported $filter expressions are $filter=receivedDateTime+ge+
{value} or $filter=receivedDateTime+gt+{value} .
Applying $filter in a delta query returns only up to 5,000 messages.
The only supported $orderby expression is $orderby=receivedDateTime+desc . If
you do not include an $orderby expression, the return order is not guaranteed.
There is no support for $search .

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

Optional request header


Each delta query GET request returns a collection of one or more messages in the
response. You can optionally specify the request header, Prefer: odata.maxpagesize=
{x} , to set the maximum number of messages in a response.
Example 1: synchronize messages in a folder
The following example shows 2 rounds of synchronization of a specific folder that
initially contains 5 messages.

The first round involves a series of 3 requests to synchronize all 5 messages in the
folder:

Sample initial request and response


Sample second request and response
Sample third request and final response

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.

Sample initial request


In this example, the specified folder is being synchronized for the first time, so the initial
sync request does not include any state token. This round will return all the messages in
that folder.

The first request specifies the following:

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

Sample initial response


The response includes two messages and an @odata.nextLink response header. The
@odata.nextLink URL indicates there are more messages in the folder to get.

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=="
}
]
}

Sample second request


The second request specifies the @odata.nextLink URL returned from the previous
response. Notice that it no longer has to specify the same $select parameter as in the
initial request, as the skipToken in the @odata.nextLink URL encodes and includes it.

HTTP

GET
https://graph.microsoft.com/v1.0/me/mailfolders/AQMkADNkNAAAgEMAAAA/messages
/delta?$skiptoken=GwcBoTmPuoTQWfcsAbkYM HTTP/1.1
Prefer: odata.maxpagesize=2

Sample second response


The second response returns the next 2 messages in the folder and another
@odata.nextLink , indicating there are more messages to get from the folder.

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"
}
]
}

Sample third request


The third request continues to use the latest @odata.nextLink URL returned from the
last sync request.

GET
https://graph.microsoft.com/v1.0/me/mailFolders/AQMkADNkNAAAgEMAAAA/messages
/delta?$skiptoken=GwcBoTmPKILK4jLH7mAd1lLU HTTP/1.1
Prefer: odata.maxpagesize=2

Sample third and final response


The third response returns the only remaining message in the folder, and a
@odata.deltaLink URL which indicates synchronization is complete for the time being

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="
}
]
}

Synchronize messages in the same folder in the next


round
Using the @odata.deltaLink from the last request in the last round, you will be able to
get only those messages that have changed (by being added, deleted, or updated) 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/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="
}
]
}

Example 2: Synchronize messages in a folder


based on change type
The following example shows getting only messages that are created in a specific folder
since the initial sync. The example involves 2 rounds of synchronization of that folder
that initially contains 4 messages.

The first round involves a series of 2 requests to synchronize all 4 messages in the
folder:

Sample initial request with specified change type and response


Sample second request with specified change type and response

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.

Sample initial request with specified change type


In this example, the specified folder is being synchronized for the first time, so the initial
sync request does not include any state token. This round will return all the messages in
that folder.

The first request specifies the following:

A changeType parameter to return only the created messages in the subsequent


delta response.
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/AAMkAGUwNc4LTMzAAA=/messages
/delta?changeType=created&$select=subject,sender,isRead HTTP/1.1
Prefer: odata.maxpagesize=2

Sample initial response with specified change type


The response includes two messages and an @odata.nextLink response header. The
@odata.nextLink URL indicates there are more messages in the folder to get.

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]"
}
}
}
]
}

Sample second request with specified change type


The second request specifies the @odata.nextLink URL returned from the previous
response. Notice that it no longer has to specify the same $select or the changeType
parameter as in the initial request, as the skipToken in the @odata.nextLink URL
encodes and includes it.

HTTP

GET
https://graph.microsoft.com/v1.0/me/mailFolders/AAMkAGUwNc4LTMzAAA=/messages
/delta?$skiptoken=P4lmXpjPRrjB6haAQzSkpK89jYTVD2kVtOeXNRnfYzPbCs HTTP/1.1
Prefer: odata.maxpagesize=2

Sample second response with specified change type


The second response returns the next 2 messages in the folder and @odata.deltaLink
URL which indicates synchronization is complete for the time being 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/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.

Track changes to users


Track user changes through one or more GET requests with the delta function. The GET
request is like a list users request, except with the following extra objects in the URL:

The delta function.


A state token (deltaToken or skipToken) from the previous GET delta function call.

Example: track changes to users


The following example shows a series of requests to track changes to users:

1. An initial request and response


2. A nextLink request and response
3. A final nextLink request and response
4. A deltaLink request and deltaLink response

Take note of the following in the responses:

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.

Take note of the following items:

The optional $select query parameter is included in the request to demonstrate


how query parameters are automatically included in future requests.
The initial request doesn't include a state token. State tokens will be used in
subsequent requests.

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

@odata.deltaLink parameter) is returned in the final response, even if the value 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.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"
}
]
}

Final nextLink request


The third request uses the latest skipToken returned from the last sync request.

HTTP

HTTP

GET https://graph.microsoft.com/v1.0/users/delta?
$skiptoken=pqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjtQ5LOhVoS7qQG_wdVCH
HlbQpga7

Final nextLink response


When a @odata.deltaLink URL is returned, there's no more data about the existing state
of the user objects. For future requests, the application uses the @odata.deltaLink URL
to learn about other changes to users. Save the deltaToken and use it in the subsequent
request URL to discover more changes to users.

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.

Electronic discovery (eDiscovery) (preview)

Develop applications that ensure a repeatable,


predictable, and standard process
Organizations rely on Microsoft 365 eDiscovery capabilities to meet requirements to
find the truth about what happened in their organization when they need to, based on
internal or external requirements such as litigation, investigation, or regulatory
compliance.

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.

Manage your eDiscovery workflows


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 advanced eDiscovery 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.

Build custom eDiscovery workflows with Microsoft Graph


https://www.youtube-nocookie.com/embed/gXqBEHy5K6E

Automate case management and synchronization with case management tools.

Add standardized tagging pallets to cases.

Create custom reporting to track case load and progress from individual cases.

Privacy management by subject rights requests


In accordance with certain privacy regulations around the world, individuals can make
requests to review or manage the personal data about themselves that companies have
collected. These requests are referred to as subject rights requests within the Microsoft
365 privacy management solution; they are sometimes also referred to as data subject
requests (DSRs) or data subject access requests (DSARs). Microsoft 365 privacy
management empowers personnel responsible for fulfilling subject rights requests to
easily identify data subjects and find their personal information among an organization’s
data in Exchange, SharePoint, OneDrive, and Teams.

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.

Records management (preview)


Organizations of all types require a records-management solution to manage critical
records across their corporate data. Microsoft Purview records management helps an
organization manage their legal obligations, provides the ability to demonstrate
compliance with regulations, and increases efficiency with regular disposition of items
that are no longer required.

The records management solution is used by organizations in large volumes to protect,


label, retain, or delete their data. The Microsoft Graph APIs for records management
allow organizations to manage labels and label-associated functionalities more
efficiently, automate the repetitive tasks, and equip customers with flexible options.

API reference
Looking for the API reference for these services?

Microsoft Graph eDiscovery API beta


Microsoft Graph subject rights request API v1.0
Microsoft Graph subject rights request API beta

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

Microsoft 365 is a complete, intelligent solution that empowers users and


organizations with innovative productivity experiences and rich insights to increase
efficiency and drive business growth. Microsoft Graph is the data fabric that powers
these intelligent experiences, and the Microsoft Graph API provides access to this data
and intelligence.

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.

The following diagram provides a high-level overview of Microsoft Graph connectors.


Get started with custom connectors
The 100+ connectors currently available from Microsoft and partners enable you to
connect to popular Microsoft and non-Microsoft services. Examples of existing
connectors include Azure services, Box, ServiceNow, Salesforce, Google services, and
MediaWiki.

To learn more about the existing Microsoft Graph connectors, visit the Microsoft Graph
connectors gallery .

Build a custom connector


While the existing connectors help connect to popular services, you might want to
integrate with services that aren't available in the connectors gallery. You can use the
Microsoft Graph connectors API to build custom connectors to bring your external data
into Microsoft 365 experiences within your organization.

To get started, see the following:

Build your first custom Microsoft Graph connector using APIs


Build your first custom Microsoft Graph connector using the SDK

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.

You can use the Microsoft Graph connectors API to:

1. Create and manage external data connections.


2. Define and register the schema of the external data types.
3. Ingest external data items into Microsoft Graph.
4. Sync external groups.

Create and manage external data connections


The externalConnection resource (external connection API) is a logical container for your
external data that you can manage as a single unit.

To learn more, see Create, update, and delete connections in Microsoft Graph.

Define and register the schema of the external


data types
The connection schema (schema API) determines how your content is used in various
Microsoft 365 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 ingesting items into Microsoft Graph.

To learn more, see Register and update schema for the Microsoft Graph connection.

Ingest external data items into Microsoft Graph


Items added by your application to the Microsoft Search service are represented by the
externalItem resource (external item API) in Microsoft Graph.

To learn more, see Create, update, and delete items added by your application via
Microsoft Graph connectors.

Sync external groups


Items in the external service can be granted or denied access via ACL to different types
of non-Azure Active Directory groups. For example, Salesforce items might have
permission sets and profiles, while ServiceNow items might have local groups. When
you ingest these items into Microsoft Graph, you need to honor these ACLs.

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.

Step 1: Fork the Microsoft Graph Postman


collection
To use the Postman collection, you need to fork it into your Postman workspace. Do this
from a web browser.

1. Go to Postman and sign up. If you already have a Postman account, you can sign
in .

2. After you sign in, go to the following URL:


https://www.postman.com/microsoftgraph/workspace/microsoft-

graph/collection/455214-085f7047-1bec-4570-9ed0-3a7253be148 and select the

Microsoft Graph collection.

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.

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.

1. Go to portal.azure.com and sign in with your developer tenant administrator


account.
2. Under Azure Services, select Azure Active Directory.
3. On the left menu, select App registrations.
4. On the horizontal menu, select New registration.
5. Set the Application name to Parts Inventory .
6. Set the Redirect URI to https://oauth.pstmn.io/v1/browser-callback .
7. Select Register.
8. On the left menu, select API Permissions.
9. On the horizontal menu, select Add a permission > Microsoft Graph > Delegated
Permissions or Application Permissions.
10. Start typing External and choose the delegated or application permissions
necessary for the API you are calling. Search for Search Permissions in the Graph
Permissions reference for more details.
11. Select Add permissions.
12. On the horizontal menu, select Grant admin consent for, and then select Yes.
13. On the left menu, select Overview. From here, you can get the application (client)
ID and directory (tenant) ID. You'll need these in step 4.
14. On the left menu, select Certificates and secrets.
15. Select New client secret, enter a description, and then select Add. Copy the new
client secret value; you'll need this in step 4.
The application now has two permissions configured. ExternalItem.ReadWrite.All is
added as a delegated permission, which is a permission that requires a signed-in user.
The application can read/write external items on behalf of the user.
ExternalItem.ReadWrite.All is added as an application permission, which is a
permission that does not require a signed-in user. The application can read/write
external items on its own behalf.

Step 4: Configure authentication


In this step, you set up the environment variables in Postman that you use to retrieve an
access token.

1. Select the Microsoft Graph tab and go to the Variables section.

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.

Step 5: Get an authentication token


You need to get an access token because this is the first time you are running a request
as an application authentication flow. Get the app access token by making the following
POST request:

The following example shows how to get an access token with a shared secret:

HTML

POST /{{tenant}}/oauth2/v2.0/token HTTP/1.1 //Line breaks for clarity


Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

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

The following example shows a successful response:


HTML

{
"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.

Step 6: Create a new connection


A connection is a logical container for your external data that you can manage as a
single unit. Choose a connection name, description, and ID. Get the necessary details
from the admin to connect to the data source and provide a mechanism to authorize
against the content source when setting up the connection. You can use the Microsoft
Graph SDK and APIs to program your connector setup. If you want to store credentials,
you can use Azure Key Vault.

HTTP

POST /external/connections

The following is an example of the request.

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"
}

The following is an example of the response.

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"
]
}
}

The following is a screenshot of the Create connection section.

Step 7: Register connection schema


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.

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"
]
}
]
}

The following is an example of the response.


HTTP

HTTP/1.1 202 Accepted


Location:
https://graph.microsoft.com/beta/external/connections/contosotasks/operation
s/616bfeed-666f-4ce0-8cd9-058939010bfc

7 Note

Registering connection schema is an asynchronous operation, so do not ingest


items into the connection until the connection schema is in the Completed state. To
check connection schema status, execute the following request:

HTTP

GET /external/connections/contosotasks/operations/616bfeed-666f-4ce0-
8cd9-058939010bfc

The following is another example of the request.

HTTP

Request
GET
https://graph.microsoft.com/beta/external/connections/operations/616bfeed-
666f-4ce0-8cd9-058939010bfc

The following is another example of the response.

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
}

The following is a screenshot of the Get connection operation status section.


After the connection schema operation status changes from InProgress to Completed,
you can ingest items for the connection.

After the connection state changes from draft to ready, you can ingest items into the
current connection.

Step 8: Add external group member (optional)


If your external service uses non-Azure AD access control lists (ACLs), sync those
permissions.

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.

This is an example of a request.

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"
}

This is an example of the response.

HTTP
HTTP/1.1 201 Created
Content-Type: application/json

{
"@odata.type": "#microsoft.graph.externalGroupMember",
"id": "14m1b9c38qe647f6a",
"type": "group",
"identitySource": "external"
}

Step 9: Ingest Items


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 itemId or derive it from one or more
fields. An externalItem has three key components: access control list, properties, and
content.

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 .

The following is an example of a request.

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"
}
}

The following is an example of a successful response.

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.

How does the custom connector work?


The sample code included in the Develop your connector section creates a gRPC server
that runs the custom connector on your virtual machine. Your custom connector code is
responsible for fetching the data from the data source which must be accessible from
your virtual machine. A gRPC client from the Microsoft Graph connector agent running
on the same computer makes requests over gRPC to the server to fetch the required
response. The Microsoft Graph connector agent integrates the custom connector with
the Microsoft 365 admin center, ingests the content into Microsoft Graph and performs
other platform tasks through the orchestration framework. For details on the platform
tasks, see connector agent capabilities.
Next steps
Develop your connector
Build a custom Microsoft Graph
connector in C#
Article • 03/16/2023

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 .

Install the extension


1. Open Visual Studio and go to Extensions > Manage extensions.

2. Search for the GraphConnectorsTemplate extension and download it.

3. Close and relaunch Visual Studio to install the template.

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.

7. The custom connector template project is now created.

Create the custom connector


Before you build the connector, use the following steps to install NuGet packages and
create the data models that will be used.

Install NuGet packages


1. Right-click the project and choose Open in Terminal.

2. Run the following command.

.NET CLI

dotnet add package CsvHelper --version 27.2.1

Create data models


1. Create a folder called Models under CustomConnector and create a file named
AppliancePart.cs under the folder.

2. Paste the following code in AppliancePart.cs.


C#

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.

1. Create a folder called Data under CustomConnector and create a file


CsvDataLoader.cs in the folder.

2. Copy the following code to CsvDataLoader.cs:

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();
}
}
}

public class ApplianceListConverter : DefaultTypeConverter


{
public override object ConvertFromString(string text,
IReaderRow row, MemberMapData memberMapData)
{
var appliances = text.Split(';');
return new List<string>(appliances);
}
}

public class AppliancePartMap : ClassMap<AppliancePart>


{
public AppliancePartMap()
{
Map(m => m.PartNumber);
Map(m => m.Name);
Map(m => m.Description);
Map(m => m.Price);
Map(m => m.Inventory);
Map(m =>
m.Appliances).TypeConverter<ApplianceListConverter>();
}
}
}

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.

3. Add the following using directive in ConnectionManagementServiceImpl.cs.


C#

using CustomConnector.Data;

4. Update the ValidateAuthentication method in


ConnectionManagementServiceImpl.cs with the following code to call the
ReadRecordFromCsv method of the CsvDataLoader class.

C#

public override Task<ValidateAuthenticationResponse>


ValidateAuthentication(ValidateAuthenticationRequest request,
ServerCallContext context)
{
try
{
Log.Information("Validating authentication");

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

The ValidateCustomConfiguration method is used to validate any other parameters


required for the connection. The connector you're building doesn't require any extra
parameters; therefore, the method will validate that the extra parameters are empty.

1. Update the ValidateCustomConfiguration method in


ConnectionManagementServiceImpl.cs with the following code.

C#

public override Task<ValidateCustomConfigurationResponse>


ValidateCustomConfiguration(ValidateCustomConfigurationRequest request,
ServerCallContext context)
{
Log.Information("Validating custom configuration");
ValidateCustomConfigurationResponse response;
if
(!string.IsNullOrWhiteSpace(request.CustomConfiguration.Configuration))
{
response = new ValidateCustomConfigurationResponse()
{
Status = new OperationStatus()
{
Result = OperationResult.ValidationFailure,
StatusMessage = "No additional parameters are
required for this connector"
},
};
}
else
{
response = new ValidateCustomConfigurationResponse()
{
Status = new OperationStatus()
{
Result = OperationResult.Success,
},
};
}

return Task.FromResult(response);
}

GetDataSourceSchema
The GetDataSourceSchema method is used to fetch the schema for the connector.

1. Add the following using directives in AppliancePart.cs.

C#

using Microsoft.Graph.Connectors.Contracts.Grpc;
using static
Microsoft.Graph.Connectors.Contracts.Grpc.SourcePropertyDefinition.Type
s;

2. Add the following GetSchema method in the AppliancePart.cs class.

C#

public static DataSourceSchema GetSchema()


{
DataSourceSchema schema = new DataSourceSchema();
schema.PropertyList.Add(
new SourcePropertyDefinition
{
Name = nameof(PartNumber),
Type = SourcePropertyType.Int64,
DefaultSearchAnnotations = (uint)
(SearchAnnotations.IsQueryable | SearchAnnotations.IsRetrievable),
RequiredSearchAnnotations = (uint)
(SearchAnnotations.IsQueryable | SearchAnnotations.IsRetrievable),
});

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;
}

3. Add the following using directive in ConnectionManagementServiceImpl.cs.

C#

using CustomConnector.Models;

4. Update the GetDataSourceSchema method in


ConnectionManagementServiceImpl.cs with the following code.

C#

public override Task<GetDataSourceSchemaResponse>


GetDataSourceSchema(GetDataSourceSchemaRequest request,
ServerCallContext context)
{
Log.Information("Trying to fetch datasource schema");

var opStatus = new OperationStatus()


{
Result = OperationResult.Success,
};

GetDataSourceSchemaResponse response = new


GetDataSourceSchemaResponse()
{
DataSourceSchema = AppliancePart.GetSchema(),
Status = opStatus,
};

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.

1. Add the following using directive in AppliancePart.cs.

C#

using System.Globalization;

2. Add the following methods in AppliancePart.cs to convert the AppliancePart


record to CrawlItem.

C#

public CrawlItem ToCrawlItem()


{
return new CrawlItem
{
ItemType = CrawlItem.Types.ItemType.ContentItem,
ItemId =
this.PartNumber.ToString(CultureInfo.InvariantCulture),
ContentItem = this.GetContentItem(),
};
}

private ContentItem GetContentItem()


{
return new ContentItem
{
AccessList = this.GetAccessControlList(),
PropertyValues = this.GetSourcePropertyValueMap()
};
}

private AccessControlList GetAccessControlList()


{
AccessControlList accessControlList = new AccessControlList();

accessControlList.Entries.Add(this.GetAllowEveryoneAccessControlEntry()
);
return accessControlList;
}

private AccessControlEntry GetAllowEveryoneAccessControlEntry()


{
return new AccessControlEntry
{
AccessType = AccessControlEntry.Types.AclAccessType.Grant,
Principal = new Principal
{
Type = Principal.Types.PrincipalType.Everyone,
IdentitySource =
Principal.Types.IdentitySource.AzureActiveDirectory,
IdentityType = Principal.Types.IdentityType.AadId,
Value = "EVERYONE",
}
};
}

private SourcePropertyValueMap GetSourcePropertyValueMap()


{
SourcePropertyValueMap sourcePropertyValueMap = new
SourcePropertyValueMap();

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,
});

var appliancesPropertyValue = new StringCollectionType();


foreach(var property in this.Appliances)
{
appliancesPropertyValue.Values.Add(property);
}
sourcePropertyValueMap.Values.Add(
nameof(this.Appliances),
new GenericType
{
StringCollectionValue = appliancesPropertyValue,
});
sourcePropertyValueMap.Values.Add(
nameof(this.Description),
new GenericType
{
StringValue = Description,
});

return sourcePropertyValueMap;
}

3. Add the following using directive in CsvDataLoader.cs.

C#

using Microsoft.Graph.Connectors.Contracts.Grpc;

4. Add the following method in CsvDataLoader.cs.

C#

public static IEnumerable<CrawlItem> GetCrawlItemsFromCsv(string


filePath)
{
using (var reader = new StreamReader(filePath))
using (var csv = new CsvReader(reader,
CultureInfo.InvariantCulture))
{
csv.Context.RegisterClassMap<AppliancePartMap>();

// The GetRecords<T> method will return an IEnumerable<T>


that will yield records. This means that only one record is returned at
a time as you iterate the records.
foreach (var record in csv.GetRecords<AppliancePart>())
{
yield return record.ToCrawlItem();
}
}
}

5. Add the following using directive in ConnectorCrawlerServiceImpl.cs.

C#

using CustomConnector.Data;

6. Add the following method in ConnectorCrawlerServiceImpl.cs.


C#

private CrawlStreamBit GetCrawlStreamBit(CrawlItem crawlItem)


{
return new CrawlStreamBit
{
Status = new OperationStatus
{
Result = OperationResult.Success,
},
CrawlItem = crawlItem,
CrawlProgressMarker = new CrawlCheckpoint
{
CustomMarkerData = crawlItem.ItemId,
},
};
}

7. Update the GetCrawlStream method to the following.

C#

public override async Task GetCrawlStream(GetCrawlStreamRequest


request, IServerStreamWriter<CrawlStreamBit> responseStream,
ServerCallContext context)
{
try
{
Log.Information("GetCrawlStream Entry");
var crawlItems =
CsvDataLoader.GetCrawlItemsFromCsv(request.AuthenticationData.Datasourc
eUrl);
foreach (var crawlItem in crawlItems)
{
CrawlStreamBit crawlStreamBit =
this.GetCrawlStreamBit(crawlItem);
await
responseStream.WriteAsync(crawlStreamBit).ConfigureAwait(false);
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
CrawlStreamBit crawlStreamBit = new CrawlStreamBit
{
Status = new OperationStatus
{
Result = OperationResult.DatasourceError,
StatusMessage = "Fetching items from datasource
failed",
RetryInfo = new RetryDetails
{
Type = RetryDetails.Types.RetryType.Standard,
},
},
};
await
responseStream.WriteAsync(crawlStreamBit).ConfigureAwait(false);
}

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.

Use the following steps to test your connector:

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.

a. The provider ID is generated for each project and is located in the


ConnectorInfoServiceImpl.cs file.

b. The datasource path is the path where you downloaded the ApplianceParts.csv
file.

c. You can set AuthenticationKind to null because the connector is using


anonymous auth.

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
}
}

2. Update the CustomConnectorPortMap.json file with the port mapping of the


connector. This file located in the following folder C:\Program Files\Graph
connector agent. Update this file with an entry for the connector ID (which you
identified in the ConnectorInfoServiceImpl.cs file in the previous step) and the port,
which is defined in the ConnectorServer.cs file.

JSON

{
"a1c127ed-29ce-47fb-ad4a-8836871922ea": "30303" //Update your
ConnectorUniqueId and Port information
}

3. Update the manifest.json file located in the following folder: C:\Program


Files\Graph connector agent\TestApp\Config:

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" ]
}

4. Run GraphConnectorAgentTest.exe, which is located in the C:\Program Files\Graph


connector agent\TestApp folder.
5. Make sure the connector is running.

6. Test the connector using options all the options (1, 2, 3, 4, 5) in


GraphConnectorAgentTest.exe.

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.

Use the following steps to host the connector as a Windows service:

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.

3. Name the project CustomConnectorWorkerService and choose Next.


4. Choose .NET Core 3.1 as the target framework and choose Create.

5. Right-click the worker service project and choose Open in Terminal.

6. Run the following commands in the terminal.

.NET CLI

dotnet add package Microsoft.Extensions.Hosting --version 6.0.0


dotnet add package Microsoft.Extensions.Hosting.WindowsServices --
version 6.0.0

7. Right-click the worker service project and select Add > Project Reference.

8. Select the CustomConnector project and choose OK.

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();
}

protected override async Task ExecuteAsync(CancellationToken


stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(1000);
}
}
}
}

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();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>


Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
});
}
}

11. Select the Release configuration and build the CustomConnectorWorkerService


project.

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

The service name must be unique for each unique connector.


For more information about service user accounts, see Service User
Accounts.

13. Open services.msc and verify that the service is running.

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.

To publish your connector, use the following steps:

1. Go to the Microsoft 365 admin center .

2. Go to Search & intelligence > Data Sources, and choose Add.

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.

6. On the Additional parameters page, choose Next.

7. On the Assign property labels page, choose Next.

8. On the Manage schema page, choose Next.

9. On the Manage search permissions page, choose Everyone.

10. For Full refresh frequency, choose 15 minutes.

11. Review the details provided and choose Finish.

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:

1. Go to Settings > Search & intelligence > Customizations.


2. Go to Vertical, and then select Add.
3. Provide the following details:

Name the vertical: Appliance Parts.

Content source: The custom connector created with the sample code (Parts
Inventory).
Add a query: Leave blank.

Filters: Leave blank.

Create a result type


To create a result type:

1. Go to Settings > Search & intelligence > Customizations.


2. Go to the Result type tab, and then select Add.
3. Provide the following details:

Name: Appliance Part

Content source: The custom connector created with the sample code.
Rules: None

Paste contents of result-type.json into the layout designer textbox.

Test the results in a search


In this step, you'll verify that you've successfully added your data to Microsoft Graph by
searching for parts in SharePoint. To verify your data:

1. Go to the root SharePoint site for your tenant.

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.

Sample custom helpdesk system Tickets Connector structure.


Admin view of connections including the custom Tickets Connector.

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.

States and operations


Your connection can exist in one of the following states.

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.

Operation Draft Ready Obsolete LimitExceeded


Operation Draft Ready Obsolete LimitExceeded

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:

1. Create a connection with a unique ID, display name, and description.


2. Register a schema to define the fields that will be included in the index.

Note: For information about updating the schema for an existing connection,
see Schema update capabilities.

Enable content experiences


A Microsoft Graph connector can integrate with Microsoft 365 experiences beyond
Microsoft Search.

To enable one or more content experiences, set the value of the


enabledContentExperiences property to the values that represent those content
experiences when you create the connection. The supported values are listed in the
following table.

enabledContentExperiences Description
value

search Allows your content to appear in Microsoft search results. The


format of these results is consistent across different search
canvases, such as SharePoint and Microsoft Bing.

compliance Allows your content to be visible to the Microsoft Purview


advanced eDiscovery solution. For details about advanced
eDiscovery solution & licensing requirements, see Microsoft
Purview solutions.

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:

Markdown is not supported.


Data binding expressions with ${} are not supported. For example, "text": "Hello
{name}" is supported, but "text": "Hello ${name}" is not.
Only data binding expressions for single-valued properties are supported. For
example, "text": "Hello {name}" is supported, but "text": "Hello
{employee.Name}" is not.

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.

Property Type Searchable Queryable Retrievable Refinable Exact Labels Aliases


Match
Required

ticketId String ✔️ ✔️ ID

title String ✔️ ✔️ ✔️ title

createdBy String ✔️ ✔️ createdBy creator

assignedTo String ✔️ ✔️

lastEditedDate DateTime ✔️ ✔️ ✔️ lastModifiedDateTime editedDate

lastEditedBy String ✔️ ✔️ ✔️ lastModifiedBy edited

workItemType String ✔️ ✔️ ticketType

priority Int64 ✔️

tags StringCollection ✔️ ✔️ ✔️ ✔️

status String ✔️ ✔️

url String url

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

Suffix matching is not supported.

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.

A set of retrievable properties ( title and lastEditedBy ) rendered as a result.

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.

Exact match required


If isExactMatchRequired is true for a property, the full string value will be indexed. isExactMatchRequired can only
be set to true for non-searchable properties.

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.

Similarly, the tags property also specifies exact matching.

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:

Data integration in heterogenous experiences


Building common knowledge graphs (for example, Viva Topics)
Default templates for user experiences

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.

url The target URL of the item in the data source.

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.

iconUrl The URL of an icon.

containerName The name of the container.

containerUrl The URL of the container.

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

All properties that you map to labels must be retrievable.

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

For discovery (search scenarios), note the following:

Ensure that your mappings are accurate.


When you use a property as a label that contains large content, you might increase search latency and have to
wait longer for search to return results.
Especially in the scenario where you configure a custom vertical that allows search over more than one
connection, the search results greatly benefit from appointing as many labels as possible.

Default result types


Labels also affect how default result types are generated. Adding the title and content labels at a minimum ensures
that a result type is created for your connection.

A default result type with title and a result snippet.

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

Finally, when assigning labels, ensure the following:

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.

Schema update capabilities


This section includes information about the update capabilities for the schema API.

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 a search capability


You can add specific search attributes to a property, but keep in mind that you cannot add a refiner search attribute
as a schema change. Also, it is not possible to use refinable attributes as searchable capabilities.

Adding a search capability requires reingestion.

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.

Add/remove a semantic label


Adding a semantic label can affect experiences like Relevance and Viva Topics.

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.

Access control list


The access control list (ACL) is used to specify whether the given roles are granted or
denied access to view items in Microsoft experiences. The ACL is an array of access
control entries, each representing an Azure Active Directory (Azure AD) user or group. A
third access control entry type Everyone represents all the users in the tenant.
An example access control list.

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.

An example property component.

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 .

An example of a content component.

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.

A search result template.

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.

Common external group scenarios


The following are common non-Azure AD application-specific group examples.

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.

Using external groups in your connection


To use external groups in your connection, follow these steps:

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.

Create an external group


External groups belong to a connection. To create external groups in your connections,
follow these steps:

1. Use the groups API in Microsoft Graph, as shown in the following example.

7 Note

The displayName and description are optional fields.

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 external group can contain one or more of the following:

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"
}

Use external groups in the ACL


You can use external groups when defining ACLs for external items, as shown in the
following example. In addition to Azure AD users and groups, an external item can have
external groups in its access control entries.

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.

Keep external group memberships in sync


Keep the membership of your external group up to date in Microsoft Graph. When
memberships change in your custom group, make sure that the change is reflected in
the external group at a time that works for your needs.

Manage external groups and membership


You can use the groups API to manage your external groups and group membership.
For details, see externalGroup and externalGroupMember.

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

Connection resources per Microsoft 365 tenant 30

Items per connection 5,000,000

Connection byte size 500 GB

Items per tenant 50,000,000

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

External groups per Microsoft 365 tenant 100,000

Requests allowed per second (requests/sec) in the group administration throttling 1,000
threshold

External groups per user for search query 10,000

Item ingestion
Limit type Limit
Limit type Limit

Throughput limit to ingest items through a connection 25


items/sec

Item size; this limit applies to the request body when ingesting and indexing an 4 MB
item

Property size N/A

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.

Why invest in cross-device experiences?

Let customers pick up where they leave off with the


activity feed API
With activities, you have a way to capture the unique tasks for users of your app that
flow seamlessly across any platform and device, allowing them to quickly resume
working on their preferred screen. Using the activity feed, you can create a human-
centric view of the tasks most important to users, helping reduce friction when switching
from web to mobile to PC and beyond.

Build rich cross-device experiences by using the device


relay API
In addition to Microsoft devices (PCs, Xbox, IoT, HoloLens, and more), the device relay
API also exposes Android and iOS devices. This enables you to truly break down
boundaries between your users' devices. You can build apps that utilize the user’s
environment and create rich experiences that transcend a single device in real-time.

API reference
Looking for the API reference for these services?

API for cross-device experiences in Microsoft Graph v1.0


API for cross-device experiences in Microsoft Graph beta

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.

The following sections describe the benefits of integrating with activities.

Enable experiences that flow seamlessly


between Windows, Android, Linux, and iOS
devices
Great applications help users do great things—enabling a wide range of creativity,
productivity, and entertainment scenarios. Returning to a task can be a challenge,
especially when a person wants to continue the task on a different device or platform.
By incorporating activities into applications, you can help users return to recent tasks
quickly using whatever screen is handy—they can move from web to mobile to desktop
and back again. With history items, users can easily see which activities they used most
recently, when, and for how long.

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.

Create richer activities for any experience with


Adaptive Cards
When activities are rendered in Microsoft experiences such as Windows Timeline, they're
displayed using the Adaptive Card framework, which allows you to create beautiful,
rich cards to showcase your app's activities. You can use the Adaptive Card SDK to
render rich cards in your own app, too. If you do not provide an adaptive card for each
activity, we'll automatically create a simple activity card based on your application name
and icon, the required Title field, and optional Description field.

Let Microsoft help drive app usage with


features that reach hundreds of millions of
customers
Integrating with user activities not only enables users to resume activities in your app
seamlessly, it means tapping into a growing set of Microsoft experiences for Windows,
iOS, and Android—experiences designed to drive user productivity and help users
engage with your app on all devices. Using Microsoft Graph, you can integrate with user
activities just once and reach hundreds of millions of consumers, and tens of millions of
customers in organizations who use Windows as well as Microsoft products for iOS and
Android devices.

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.

Why integrate with device relay?


The device relay API enables your app to register itself, and discover, command, and
message your app on the user's devices. By doing this, you can make the tasks your
customers work on the central focus. They can work on the device that is most
convenient for them by discovering it and transferring tasks to it. They can also enhance
an ongoing experience with your app by using other devices around them.

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.

Extend the experience


Extend your app by providing UX to discover devices and to launch your app on those
devices. For example, the user could be working on a purchase order on her phone,
discover the PC in her office, and launch the app there to finish entering the purchase
order.

Augment the experience


Create a companion experience for your app on another of the user’s devices. For
example, the app could include UX to launch itself on other devices. In a game, the user
could launch the app to a device with a larger screen (for example, from a PC to an
Xbox). The Xbox could present a full view of the game (a first-person view), while the
device with the smaller screen could present a different view with additional context (a
top-level view of the game level showing the player and opponents' locations).

Enrich the experience


Add additional controlling abilities to your app. For example, provide remote control
abilities for the main app from a companion device. When the user launches an app
from one device to another, the target device could show the full experience (for
example, a 3D model in a design app), while the source device could show a list of the
most common actions given the state of the app on the target device (for example,
rotate, resize, color palette).

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.

A cross-device app enables you to:

Use the Project Rome activity feed API in Microsoft Graph.


Read and write user activities published by a group of platform-specific
applications by using the Project Rome SDK for Windows, Android, and/or iOS.
Target apps via the device relay capabilities in Project Rome by using the Project
Rome SDK for Android or iOS.

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.

Select the right hosting method for your cross-


device app configuration
You can host your cross-device app configuration either as a JSON file on your domain
or as a profile configurable via the Windows Dev Center. Choose a hosting option based
on the Project Rome capabilities you want to enable in your apps.

Windows Dev Center profile (recommended)


You can access all Project Rome capabilities using a cross-device app managed in the
Windows Dev Center. The Windows Dev Center also offers the best way to manage any
cross-device app configuration changes. You can save updates to an existing profile
more securely until you're ready to publish changes to production. When you publish
changes to an existing cross-device app in the Dev Center, the new profile will be
effective after approximately one hour.

Externally hosted JSON file (limited)


You can use the following Project Rome capabilities on all supported platforms using a
cross-device app managed as an externally hosted JSON file:

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.

Configure a cross-device app using the


Windows Dev Center
A cross-device app ID is represented as a domain that you own. The domain points to a
mapping of your platform-specific app IDs stored either as a JSON file hosted on your
domain or configurable via the Windows Dev Center. After you identify the domain
you'll use to represent your cross-device app ID, you'll need to collect information to
configure the associated profile.

Step 1: Select a secure domain for your cross-device app


ID and enable domain verification
The domain used as your cross-device app ID must either be a top-level domain or a
subdomain and must be protected via TLS. For example: https://contoso.com or
https://myapp.contoso.com , but NOT https://myapp.contoso.com/somepath . You
must have a unique domain (or subdomain) per cross-device app. However, you
decide which apps to associate with a single cross-device app based on the cross-
platform behavior you want to support.

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.

Assert domain ownership with the Windows Dev Center


When using the Windows Dev Center to manage your cross-device app configuration,
the domain representing your cross-device app ID is stored as part of your cross-device
app profile so Microsoft can verify that you are the domain owner. Your domain
ownership must be verified in order to finish publishing your cross-device app
configuration, so it's a good idea to tackle this first. If your domain is not yet verified,
you can save your cross-device app details and rerun the verification after you complete
this step so you can publish your cross-device app.

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='.

Step 2: Collect your platform-specific application IDs


Collect the platform-specific application IDs for each application and platform that will
use Project Rome APIs.

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.

To find the IDs:

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.

Step 3: Configure support for Microsoft account or Azure


AD
To enable cross-device experiences, your app users must sign in with either a Microsoft
account or an Azure Active Directory (Azure AD) account. You will provide the app
ID/client IDs to support authentication as part of your cross-device app configuration to
enable cross-platform support. You can provide up to 10 instances.

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:

1. Sign in to the Azure portal .


2. Select Azure Active Directory.
3. Under Manage, select App registrations.
4. Select your app from the list and view your Application ID (GUID) listed under
Essentials.

Step 4: Configure support for cross-platform push


notifications (optional)
If you've opted to configure your cross-device app in the Windows Dev Center, you can
enable support for cross-platform push notifications by providing the credentials you
use with the APIs for Android and iOS push messaging platforms. These are required if
you're using the Project Rome SDKs for iOS and Android and you want to do more than
publish user activities. If you're using Project Rome APIs for Microsoft Graph only, you
don't need to perform this step. You can associate up to 10 sets of credentials per
platform.

) Important

Do not store push notification credentials in an externally hosted JSON file.

To find the IDs:

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

If you're using Firebase to push notifications to iOS devices using Android


credentials, you'll need to provide your APNs credentials as part of your cross-
device app configuration.

Configure a cross-device app using an


externally hosted JSON file
A cross-device app ID is represented as a domain that you own. The domain points to a
mapping of your platform-specific app IDs stored either as a JSON file hosted on your
domain or configurable via the Windows Dev Center. After you identify the domain
you'll use to represent your cross-device app ID, you'll need to collect information to
configure the associated profile.

Step 1: Select a secure domain for your cross-device app


ID
A cross-device app ID is represented as a domain that you own. This must either be a
top-level domain or a subdomain, and must be protected via TLS. For example:
https://contoso.com or https://myapp.contoso.com but NOT
https://myapp.contoso.com/somepath . You must have a unique domain (or
subdomain) per cross-device app. However, you decide which apps to associate with a
single cross-device app based on the cross-platform behavior you want to support.

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.

Assert domain ownership with an externally hosted JSON file

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.

Step 2: Collect your platform-specific application IDs and


construct your JSON file
Collect the platform-specific application IDs for each application and platform that will
use the activity feed and/or device relay API.

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.

Constructing your cross-platform-app-identifiers file

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"},
]

To find the IDs:

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.

Step 3: Configure support for Microsoft account or Azure


AD
To enable cross-device experiences, your app users must sign in with either a Microsoft
account or an Azure AD account. You will provide the app ID/client IDs to support
authentication as part of your cross-device app configuration to enable cross-platform
support. You can provide up to 10 instances.

{"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".

To find the GUID in the Azure Portal for your tenant:

1. Sign in to the Azure portal .


2. Select Azure Active Directory.
3. Under Manage, select App registrations.
4. Select your app from the list. You can view your application ID (GUID) under
Essentials.

Encoding the cross-platform-app-identifiers file

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.

Updating the cross-platform-app-identifiers JSON file


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.

Configure your app client


If you're using the client-side APIs for Windows, iOS, or Android, you'll need to make
sure your app client is configured with the host value that represents your cross-device
app identity (for example, contoso.com).

Microsoft Graph apps


If you have an app using the activity feed API in Microsoft Graph, your host value must
be supplied in the activitySourceHost property. For details, see activity resource type.

Universal Windows apps


If you have a Windows app, you will need to configure the host value in your app
manifest before publishing data. For details, see uap5:UserActivity.

Maintain your cross-device app configuration


When releasing a new application that will generate user activities, it's important to
update the cross-device app with the new configuration values in advance so that any
new activities published are correctly associated with the cross-device app. The cross-
device app configuration associated with user activities that have been published prior
to a change in configuration will not be updated automatically. However, an update
operation performed on any activity with an old configuration will be updated to the
most recent version on file.

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.

Platform will not initialize on Android or iOS


The device relay API for Android or iOS requires the cross-device app configuration in
order to instantiate connections to the Android or iOS app. In the event that the
platform fails to initialize successfully, make sure you have correctly identified the
Microsoft account app IDs and push notification credentials used to configure your
cross-device app in the Windows Dev Center, and configure your client apps' host value
with the domain that identifies your cross-device app.
Microsoft Bookings API overview
Article • 06/22/2022

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.

Why integrate with Microsoft Bookings using


Microsoft Graph?

Streamline appointment booking


A business operator may never miss a customer booking when away from the phone or
the business is closed. Customers can see the available services and book appointments
any time directly on the scheduling page, on the business web site or Facebook.

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.

Reduce no-shows and increase productivity of the staff


Business operators can specify scheduling policies that include minimum notice for
bookings and cancellations, and customers can schedule or reschedule appointments
themselves. Automated appointment confirmations and reminders decrease no-shows,
and let the staff make better use of their production hours.

Manage customer information and relationships from


anywhere
Completing an appointment automatically verifies if the customer is already on the
customer list, and adds the customer's name and email address to the list if necessary.
This makes it convenient for business operators to stay in touch with their customers,
and send periodic newsletters or other promotional material.
Integrate with productivity and team collaboration
services in Microsoft Graph
Using the same unified Microsoft Graph REST endpoint, you can access the Bookings
API and integrate with the best of Microsoft 365 to support richer scenarios. For
example, you can use Excel to track and analyze business financial data, and generate
professional reports, or use SharePoint or Microsoft Teams to enhance team
collaboration.

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

When a non-admin user creates an appointment in Microsoft Bookings, Bookings uses


the business rules that are configured for the calendar. Only administrators have the
authority to override Bookings rules.

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

This setting is called Staff control in the Bookings web app.

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.

Partially set policies


If the user doesn't set a policy for the service level, it defaults to the business-level
policy setting.

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.

Why integrate with Edge settings in the


Microsoft 365 admin center?

Use a single browser for legacy and modern sites


Edge supports IE mode to enable your organization to use a single browser for both
legacy and modern websites and applications. Organizations can use cloud site lists for
IE mode to manage a list of websites that should automatically load in IE mode,
supporting the transition from IE11 to IE mode. As an alternative to using the Microsoft
365 admin center, apps can use the Microsoft Graph API to manage the same browser
site lists configured through the Microsoft 365 admin center.

Manage and store IE mode sites in the cloud


Cloud site lists for IE mode allows admins to manage and store a list of websites that
require Internet Explorer mode to a compliant cloud location. Admins can publish one
or more site lists to an authenticated endpoint that Microsoft Edge clients within their
tenant can download. Subsequent publishes of these site lists reflect automatically on
Microsoft Edge clients with no additional steps.

Automate the management of site lists


The Microsoft Graph APIs for managing cloud site lists retain the same core functionality
that is currently offered in the Microsoft 365 admin center. Administrators can automate
common tasks such as creating site lists, adding sites, adding shared cookies, and
publishing site lists.

API reference
Looking for the API reference for this service?

Use the Edge API in Microsoft Graph

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.

Why use Universal Print?


Universal Print moves key Windows Server print functionality to the Microsoft 365 cloud,
so organizations no longer need on-premises print servers and do not need to install
printer drivers on devices. In addition, Universal Print adds key functionality like security
groups for printer access, location-based printer discovery, and a rich administrator
experience.

As organizations adopt Universal Print, organizations and independent software vendors


(ISVs) can use the Universal Print API in Microsoft Graph to build and extend
applications to support new scenarios.

Print documents from web and mobile applications


Moving print infrastructure to the cloud enables printing documents directly from web
and mobile applications.
Users can submit print jobs to printerShare.
Printer admins can also submit print jobs to a printer, for doing preliminary testing
before sharing the printer with the organization.

Follow these steps to submit print jobs to printerShare:

1. Create a print job and store the resulting document ID.


2. Create an uploadSession for the document.
3. Upload bytes to the created upload session.
4. Start the print job.

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.

Keep an eye on printer status, configurations, and availability by using List


printers and printerStatus.

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

Configure user permissions by modifying user and group membership on printers:


List allowedUsers
Add allowedUser
Remove allowedUser
List allowedGroups
Add allowedGroup
Remove allowedGroup

Seamlessly replace or update printer hardware


Printers are not visible to users until they are shared, providing administrators fine-
grained control over which printer hardware is available at a given time.

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.

Enable pull printing


The Microsoft Graph Universal Print API enables your application to support pull
printing. To set up pull printing, you will register triggers that notify your application (via
service-to-service communication) when certain print events happen, such as a print job
being started.

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.

Follow these steps to enable pull printing:

1. Create a printTaskDefinition using application permissions. This abstract task


definition will be used to create task that will hold the job for your application. You
need to define at least one task definition per tenant, which can be associated with
any number of printers in the tenant using task triggers (see step 4).

2. Register one or more virtual printers using an administrator authentication token


and a null physicalDeviceId. A "virtual printer" is just a printer object in Universal
Print without a physical device attached. Usually, users will print to virtual printers
and later pick up their print jobs at a physical print device. See step 6.

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?

Universal Print API in Microsoft Graph

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-Range bytes {startByteIndex}-{endByteIndex}‬/{documentSizeInBytes}. Required.

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

<bytes 0-72796 of the file>

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

HTTP/1.1 202 Accepted


Content-Type: application/json

{
"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

HTTP/1.1 202 Accepted


Content-Type: application/json

{
"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.

Complete a file upload


When the last byte range of a file is received, the server will respond with an HTTP 201
Created . The response body will also include the property set for the associated

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

<final bytes of the file>

Response
HTTP

HTTP/1.1 201 Created


Content-Type: application/json

{
"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.

Get the upload session


To get the upload session, send a GET request to the upload URL.

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"
]
}

Code examples: Create upload session and


upload documents
C#

C#

GraphServiceClient graphClient = new GraphServiceClient(


authProvider );

var properties = new PrintDocumentUploadProperties


{
DocumentName = "TestFile.pdf",
ContentType = "application/pdf",
Size = 4533322
};

var uploadSession = await graphClient.Print.Printers["


{printer-id}"].Jobs["{printJob-id}"].Documents["{printDocument-id}"]
.CreateUploadSession(properties)
.Request()
.PostAsync()

// if using Graph SDK, maxSliceSize should in multiples of


320 KiB
int maxSliceSize = 320 * 1024;
var fileUploadTask =
new LargeFileUploadTask<PrintDocument>(uploadSession,
fileStream, maxSliceSize);

// Create a callback that is invoked after each slice is


uploaded
IProgress<long> progress = new Progress<long>(prog =>
{
Console.WriteLine($"Uploaded {prog} bytes of
{fileStream.Length} bytes");
});

// Upload the file

var uploadResult = await


fileUploadTask.UploadAsync(progress);

Cancel the upload session


To cancel an upload session, send a DELETE request to the upload URL. This should be
used in scenarios where the upload is aborted; for example, if the user cancels the
transfer.

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

HTTP/1.1 204 No Content


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.

Get started with change notifications


Before you can take advantage of change notifications via Microsoft Graph, you must
register your application in Azure and provision your application in the customers Azure
Active Directory (Azure AD) tenant. Make sure that the application has the required
permission scopes enabled, as described later in this article.

Notifications and subscriptions


Universal Print currently supports notifications for two scenarios related to print jobs:

PrintTask is triggered (JobStarted): An application can subscribe to receive


notifications when their printTask(hook) is triggered. For details about how to
trigger a task, see Enable pull printing. Currently, a printTask can be triggered only
for a JobStarted event. A JobStarted event is raised when a print job has been
successfully created, its payload has been uploaded, and job processing has
started.

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

For listening to the change notifications for JobFetchable event, a


printTaskDefinition resource is not required.

The application should handle duplicate notifications.

Create an application to listen to notifications


For information about how to listen for Microsoft Graph notifications, see Use change
notifications and track changes with Microsoft Graph and Set up notifications for
changes in user data – Code Samples.

Permission scopes
To subscribe to notifications for print jobs, applications must have the following
permission scopes approved in the customer’s Azure AD tenant:

For printTask triggered (JobStarted) event, the permissions listed in Get


taskDefinition.

For JobFetchable event, the permissions listed in Create subscription.

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.

Create subscription: printTask triggered


(JobStarted) event
Some applications monitor print queues for incoming jobs and want to be notified as
soon as there is a valid job in the queue. After they're notified, they can collect the
relevant job metadata or even perform modifications in the print job – including
aborting the job or redirecting the job from the current print queue to another queue
after modifying the job attributes accordingly.

Before creating a notification for a printTask-triggered event, ensure that application


has created the following:
A printTaskDefinition for the customer’s Azure AD tenant. A single task definition
can be associated with one or more printers within the same Azure AD tenant.

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:

The resource field needs to be set as print/taskDefinitions/{printTaskDefinition


ID}/tasks .
The changeType field needs to be set as created .
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":"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

HTTP/1.1 201 Created


Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
"id": "{Subscription ID}",
"resource": "print/taskDefinitions/{printTaskDefinition ID}/tasks",
"applicationId": "{application ID}",
"changeType": "created",
"clientState": "secret",
"notificationUrl": "{URL for receiving the event – e.g.
https://webhookappexample.azurewebsites.net/api/notifications}",
"notificationQueryOptions": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2020-12-30T22:42:09Z",
"creatorId": "{Creator ID}",
"includeResourceData": null,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": null,
"encryptionCertificateId": null
}

Create subscription: JobFetchable event


Some cloud applications need to download print jobs from Universal Print when they
are ready. Because these applications running in the cloud are not behind the
customer's firewall, they can use Microsoft Graph change notifications to be notified
when a print job is ready to be downloaded.

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 resource field needs to be set as 'print/printers/{printer id}/jobs'.


The changeType field needs to be set as updated .
The notificationQueryOptions field needs to be set as $filter = isFetchable eq
true .

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

HTTP/1.1 201 Created


Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
"id": "{Subscription ID}",
"resource": "print/printers/{printer ID}/jobs",
"applicationId": "{Application ID}",
"changeType": "updated",
"clientState": "mysecret",
"notificationUrl": "{URL for receiving the event – e.g.
https://webhookappexample.azurewebsites.net/api/notifications}",
"notificationQueryOptions": "$filter = isFetchable eq true",
"lifecycleNotificationUrl": null,
"expirationDateTime": "2020-12-30T22:42:09Z",
"creatorId": "{Creator ID}",
"includeResourceData": null,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": null,
"encryptionCertificateId": null
}
Renew a notification subscription
Microsoft Graph has a limit on the expiration time. For details, see maximum expiration
time. To continue receiving notifications, the subscription needs to be renewed
periodically by using the Update subscription API.

Get or delete notification subscriptions


Applications can get details of the subscription or delete a subscription when required.
For details, see Use the Microsoft Graph API to get change notifications.

FAQs

How does Microsoft Graph validate notification URLs?


Microsoft Graph validates the notification endpoint provided in the notificationUrl
property of the subscription request before creating the subscription. For details, see
Notification endpoint validation.

What are applications expected to do after receiving a


change notification?
Applications should process and acknowledge every change notification they receive.
For details, see Processing the change notification.

How can I validate the authenticity of notifications?


The authenticity of notifications can either be validated using clientState value as
described in Processing the change notification or validating tokens in the change
notification.

How can I get a list of active subscriptions?


For details about how to retrieve a list of webhook subscriptions, see List subscriptions.

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

Why integrate with Intune?


You can use the Intune API in Microsoft Graph to access Intune device and application
information, manage devices, manage apps, and automate Intune.

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:

Deploy apps to devices or prevent apps from being deployed.


Manage access to ebooks and related services.
Define and deploy app configuration settings, app protection settings, and app
usage policies.

Automate Intune
Automate Intune by using the Intune API to:

Define and assign role based access controls.


Audit and report compliance, usage, and access.
Manage telecom expenses.

API reference
Looking for the API reference for this service?

Intune API in Microsoft Graph v1.0


Intune API in Microsoft Graph beta

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.

Why integrate with Windows 365 Cloud PCs?


By integrating with and building on top of Windows 365, you can provision, manage,
and secure Cloud PCs for end users as quickly and easily as possible. Using the
Microsoft Graph API, you can provision Cloud PCs, manage device images, create and
run health checks on Azure network connections, create and assign provisioning
policies, and more.

Create Azure network connections


Create Azure network connections to give line of sight to a domain controller. Once
created, if not in use, an Azure network connection can be deleted. Health checks can
also be run on an Azure network connection to check its health status and, if needed,
the Active Directory domain password can be updated.

Provision Cloud PCs


Create provisioning policies and assign to user groups to provision Cloud PCs to them
when they have licenses assigned as well. After provisioning policy creation, you can
also list, update, and delete provisioning policies.

Upload device images


Upload and manage operating system images for Cloud PCs to determine which version
of Windows with what apps and other image details should be used for Cloud PCs when
provisioned.
View end users’ Cloud PCs and their properties
Once provisioned, list and view end users’ Cloud PCs and all associated properties. This
Cloud PC visibility allows for hands-on management and ease of troubleshooting when
needed.

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.

Why use the Windows Update for Business


deployment service?
IT professionals and management tool vendors alike can use the deployment service to:

Schedule update deployments to begin on a specific date.


Stage deployments over a period of days or weeks using rich expressions.
Bypass pre-configured Windows Update for Business policies to immediately
deploy a security update.
Ensure coverage of hardware and software in your organization through
deployments tailored to unique device population(s).

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:

Windows 10/11 Enterprise E3 or E5 (included in Microsoft 365 F3, E3, or E5)


Windows 10/11 Education A3 or A5 (included in Microsoft 365 A3 or A5)
Windows Virtual Desktop Access E3 or E5
Microsoft 365 Business Premium

Additionally, devices managed by the deployment service must:

Have installed Windows 10 version 1709 or later


Be Azure AD joined or Hybrid AD joined
Have one of the following Windows 10 or Windows 11 editions installed: Pro
Enterprise Education Pro Education Pro for Workstations

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.

Drivers and firmware


Driver and firmware updates are published to Windows Update by independent
hardware vendors and original equipment manufacturers, who continuously build new
drivers and firmware or update existing ones. The deployment service will only show you
driver and firmware updates that are applicable and better (normally by version number
or version date) than what is currently installed on your devices . The service takes the
guess work out of identifying what drivers and firmware updates apply to your devices
and lets you focus on approving content that will help keep your devices protected and
productive.

Capabilities of the Windows Update for


Business deployment service
The deployment service is designed for IT Pros who are looking for more control than is
provided through deferral policies and deployment rings. The service provides the
following capabilities:

Capabilities Quality updates Feature updates Drivers and firmware

Approval and scheduling Yes Yes

Gradual rollout Yes

Expedite Yes

Safeguard holds Yes

Approval and scheduling


The deployment service simplifies reviewing, approving, scheduling, and deploying
content for a diverse device ecosystem. A catalog of content and [applicable content]
exists to provide a view tailored for approvals, helping you focus on approval decisions
that matter without a need to sort through deep lists of related updates. After you
choose an update to deploy, you can schedule deployments to start at a future time.

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.

To learn more, see Deploy an expedited 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.

To learn more, see Manage safeguards for a deployment.

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.

To learn more, see Manage monitoring rules for a deployment.

API reference
Looking for the API reference for this service?

See Windows updates API in Microsoft Graph beta.


Software updates with the Windows
Update for Business deployment service
Article • 02/03/2023

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.

Windows update categories


In general, there are three high-level categories of Windows updates: feature updates,
quality updates, and driver updates. Quality updates category includes security updates.

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.

Identifying updates for deployment


The updates in the Microsoft Update Catalog are very granular and specific to individual
products, releases, and CPU architectures.

For example, the following two security quality updates are considered different releases
in the Microsoft Update Catalog, even though they differ only by architecture.

Title Products Classification

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.

Display name Type

03/09/2021 - 2021.03 B Security microsoft.graph.windowsUpdates.qualityUpdateCatalogEntry


Updates for Windows 10

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

id Unique identifier for the catalog entry.

displayName Title of the software update.

releaseDateTime Date and time the update was released or refreshed.

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

version Feature update version for the Windows 10 release.

Below are some examples of feature updates in the deployment service catalog.

Display name Version

Feature Update to Windows 10, version 20H1 20H1


Display name Version

Feature Update to Windows 10, version 1909 1909

Feature Update to Windows 10, version 1903 1903

Feature Update to Windows 10, version 1809 1809

Once you identify a desired version, assign it as content to a deployment using


catalogContent.

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

classification Classification (security or non-security) of the quality update.

releaseDateTime Date and time the update was released or refreshed.

The following table shows the classification mapping between the deployment service
catalog and the Microsoft Update Catalog.

Deployment service catalog Microsoft Update Catalog

Security Security Update


Critical Update
Update (if needed as a dependency)
Servicing Stack Update (if needed as a dependency)

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.

Title Products Classification

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

2021-03 Cumulative Update for Windows 10 Version Windows 10, Security


1809 for x64-based Systems (KB5000822) Windows 10 LTSB 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.

Deployments have the following key aspects:

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.

Create a deployment with content and an


audience
Because content and audience are key to the definition of a deployment, you are
required to assign both at the time of creation. While content and audience assignments
cannot be changed later, device membership within an audience can.

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.

To learn more about schedule settings, see Schedule a deployment.

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.

To learn more about monitoring settings, see Manage monitoring rules.

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.

Get or set lifecycle state

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.

offering The deployment is 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

scheduled → offering Scheduling condition is met.


Transition Condition

offering → scheduled Scheduling condition is not met.

scheduled or offering → paused There is a request or automatic action to pause.

paused → scheduled or offering There is no longer a request or automatic action to


pause.

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.

Assign a device to multiple deployments


You can assign a device to multiple deployments at one time. These deployments can be
for content of the same update category (for example all deployments are feature
updates), or for content of different update categories.

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.

Today, the deployment service supports enrollment in management of Windows 10/11


feature updates and driver updates. At this time, the deployment service does not
require enrollment in management of Windows 10/11 quality updates in order to
deploy expedited quality updates.

Enroll the device in update management


When you enroll a device in management for a certain update category, the deployment
service becomes the authority for updates of that category coming from Windows
Update. As a result, devices do not receive updates of that category from Windows
Update until you deploy an update using the deployment service by assigning it to a
deployment. Devices are automatically registered with the service when enrolled in
management by the service (i.e. an azureADDevice object is automatically created if it
does not already exist). For driver enrollment, see enroll devices in driver management.

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

HTTP/1.1 202 Accepted

Check the enrollment state of a device


You can check the enrollment state of a device by getting the device and looking at the
enrollments and errors properties on the azureADDevice object. A device that is
successfully enrolled in update management has an updateManagementEnrollment
object in the enrollments collection, and it does not have any updatableAssetError
objects in the errors collection. A device that the service tried to enroll but encountered
an error has populated collections for both enrollments and errors. A device for which
the service has not received any enrollment requests has empty collections for both
enrollments and errors.

The following example shows a device that is successfully enrolled in management of


feature updates by the service.

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"
}
]
}
}

Unenroll from management by the service or


unregister from the service
When you unenroll a device from management by the service for a given update
category, the device is no longer managed by the deployment service and may start
receiving other updates from Windows Update based on its policy configuration. The
unenrolled device is removed from all audiences and deployments that contains content
for the given update category. The device remains registered with the service and is still
enrolled and receiving content for other update categories (if applicable).

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

HTTP/1.1 202 Accepted

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

HTTP/1.1 202 Accepted


Deploy a feature 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 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.

Step 1: (Optional) Get a list of deployable


updates
You can query the deployment service catalog to get a list of updates that can be
deployed to devices as content in a deployment.

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"
}
]
}

Step 2: Create a deployment


A deployment specifies content to deploy, how and when to deploy the content, and
the targeted devices. When a deployment is created, a deployment audience is
automatically created as a relationship.

Below is an example of creating a deployment of a feature update, with optional


settings configuring the deployment schedule and monitoring rules. Safeguards are
applied by default. The targeted devices are specified in the next step.

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

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": [],
"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

HTTP/1.1 202 Accepted


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, 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.

Expedited security updates also have the following characteristics:

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).

Step 1: (Optional) Get a list of expeditable


updates
You can query the deployment service catalog to get a list of updates that can be
expedited to devices as content in a deployment.

Security updates are represented by the qualityUpdateCatalogEntry type, with a


qualityUpdateClassification of security . All Windows 10 quality updates that are
classified as security updates can be expedited and are tagged with the isExpeditable
property set to true to identify them.

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"
}
]
}

Step 2: Create a deployment


A deployment specifies content to deploy, how and when to deploy the content, and
the targeted devices. For quality updates, the content is specified using a target
compliance date. When a deployment is created, a deployment audience is
automatically created as a relationship.

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.

Below is an example of creating a deployment for an expedited quality update. The


targeted devices are specified in the next step.

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

HTTP/1.1 201 Created


Content-Type: application/json

{
"@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
}
}
}

Step 3: Assign devices to the deployment


audience
After a deployment is created, you can assign devices to the deployment audience.
When 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

HTTP/1.1 202 Accepted

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.

Step 1: Enroll devices in driver management


When you enroll a device in driver management, the deployment service becomes the
authority for driver updates coming from Windows Update. As a result, devices do not
receive drivers from Windows Update until a deployment is created or they are added to
a driver update policy with approvals. To enroll a device, you must provide an
azureADDevice ID.

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

HTTP/1.1 202 Accepted

Step 2: Create a deployment audience for


receiving updates
After devices are enrolled and managed by the deployement service, they can be placed
into audiences for a deployment. Deployment audiences specify content to deploy, how
and when to deploy the content, and the targeted devices.

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

HTTP/1.1 201 Created


Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#admin/windows/updates/deployment
Audiences/$entity",
"id": "f660d844-30b7-46e4-a6cf-47e36164d3cb",
"applicableContent": []
}

Step 3: Assign devices to the deployment


audience
After a deployment audience is created, you can assign devices to the deployment
audience. When the deployment audience is successfully updated, the Windows Update
for Business deployment service will start collecting scan results from Windows Update
to build a catalog of applicable drivers to be browsed, approved, and scheduled for
deployment.

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

HTTP/1.1 202 Accepted

Step 4: Create an update policy


After devices are added to a deployment audience, you can create an update policy that
governs the deployment of content to the associated deployment audiences. The
update policy is a high-level template so content can be deployed in a similar way for a
given audience without having to create, manage, and relate individual deployments.
Content is deployed to the devices in the associated audiences when a content approval
is added to the policy.

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

HTTP/1.1 202 Accepted


Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#admin/windows/updates/updatePoli
cies/$entity",
"id": "d7a89208-17c5-4daf-a164-ce176b00e4ef",
"createdDateTime": "2023-01-19T07:58:01.9721459Z",
"autoEnrollmentUpdateCategories": [],
"complianceChangeRules": [],
"deploymentSettings": {
"schedule": null,
"monitoring": null,
"contentApplicability": null,
"userExperience": null,
"expedite": null
}
}

Step 5: Get inventory of driver updates


After devices are added to a deployment audience, you can browse and review a catalog
of applicable content for drivers and firmware that are better than what is currently
installed on the collection of devices in a deployment audience. The applicable content
also provides a matched devices list of Azure Active Directory devices that are applicable
for each driver.

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": ""
}
},
}

Step 5: Create driver approval


Deployments for driver updates are created and enforced on a policy through
compliance changes. Content approvals for driver updates are added to a policy by
specifying the catalog entry associated to a specific driver update. Content will only be
delivered to devices in the deployment audiences associated with the update policy
when approved.

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

HTTP/1.1 201 Created


Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#admin/windows/updates/updatePoli
cies('d7a89208-17c5-4daf-a164-ce176b00e4ef')/complianceChanges/$entity",
"@odata.type": "#microsoft.graph.windowsUpdates.contentApproval",
"id": "dbf29574-ffd9-49cf-87f2-f03629e596ba",
"createdDateTime": "2023-01-19T08:41:29.3840994Z",
"isRevoked": false,
"revokedDateTime": "0001-01-01T00:00:00Z",
"content": {
"@odata.type": "#microsoft.graph.windowsUpdates.catalogContent"
"[email protected]":
"https://graph.microsoft.com/beta/$metadata#admin/windows/updates/updatePoli
cies('d7a89208-17c5-4daf-a164-ce176b00e4ef')/complianceChanges('dbf29574-
ffd9-49cf-87f2-
f03629e596ba')/microsoft.graph.windowsUpdates.contentApproval/content/micros
oft.graph.windowsUpdates.catalogContent/catalogEntry/$entity",
"id":
"5d6dede684ba5c4a731d62d9c9c2a99db12c5e6015e9f8ad00f3e9387c7f399c",
"displayName": "Microsoft - Test - 1.0.0.1",
"deployableUntilDateTime": null,
"releaseDateTime": "0001-01-21T04:18:32Z",
"description": "Microsoft test driver update released in January
2021",
"driverClass": "OtherHardware",
"provider": "Microsoft",
"setupInformationFile": null,
"manufacturer": "Microsoft",
"version": "1.0.0.1",
"versionDateTime": "2021-01-11T02:43:14Z"
}
},
"deploymentSettings": {
"schedule": null,
"monitoring": null,
"contentApplicability": null,
"userExperience": null,
"expedite": null
"schedule": {
"startDateTime": "2023-02-14T01:00:00Z",
"gradualRollout": {
"@odata.type":
"#microsoft.graph.windowsUpdates.rateDrivenRolloutSettings",
"durationBetweenOffers": "P1D",
"devicesPerOffer": 0
}
}
}
}

During a driver deployment


While a deployment is in progress, you can update its audience members, as well as
prevent the content from being offered to devices if they haven't already received it, by
setting the isRevoked property to true . This is the auditable way to pause a
deployment and will automatically populate the revokedBy and revokedDateTime
properties. To resume offering the content, create a new approval.

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

HTTP/1.1 204 No Content


Unenroll from driver management
When you unenroll a device from management by the service for a given update
category, the device is no longer managed by the deployment service and may start
receiving other updates from Windows Update based on its policy configuration. The
unenrolled device is removed from all audiences and deployments that contains content
for the given update category. The device remains registered with the service and is still
enrolled and receiving content for other update categories (if applicable).

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

HTTP/1.1 202 Accepted


Schedule a deployment using the
Windows Update for Business
deployment service
Article • 02/03/2023

When deploying an update using the deployment service, you can schedule the
deployment so that devices receive the update at a future date.

Scheduling features are compatible with deployments of Windows 10/Windows 11


feature updates.

Schedule a deployment to start at a future date


You can schedule a deployment to start at a future date by configuring its schedule
settings. In the following example, all devices assigned the deployment will be offered
the update on July 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",
}
}
}
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": null
},
"monitoring": null,
"userExperience": null
},
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}

Stage a deployment over a period of time


You can also schedule a deployment so that assigned devices are offered the update in
a gradual rollout that is staged over time. The update is offered to subsets of devices
assigned to the deployment at regular intervals, with the total duration of the rollout
determined by either an end date or offering rate. You can think of a gradual rollout as
similar to a recurring calendar event series.
Example: Stage a deployment at regular intervals
between start and end dates
One way to stage a deployment over time is to set the endDateTime of the deployment.
All devices assigned to the deployment will be offered the update within the window
between the startDateTime and endDateTime. If the startDateTime is not specified,
then the deployment will begin as soon as devices are assigned.

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)"
}

Example: Stage a deployment at regular intervals with a


specified number of devices at each offer
Another way to stage a deployment over time is to configure the offering rate using
devicesPerOffer . Devices assigned to the deployment will be offered the update
according to the specified rate until all devices have been offered the update.
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. 100 devices are offered the update at a time until all devices have been offered
the update.

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

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": "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.

Safeguards are compatible with deployments of Windows 11 and Windows 10 feature


updates. Safeguard holds against known issues are available for deployments of
Windows 11 and Windows 10 feature updates, and safeguard holds against likely issues
are available for deployments of Windows 11.

Apply all safeguards


By default, the deployment service applies all applicable safeguards to devices in a
deployment. To benefit from safeguards, you don't need to specify anything additional
when creating a deployment.

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

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": null,
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}

Opt out of safeguards against likely issues


You can opt out of safeguards against likely issues in a deployment by configuring
safeguard settings. If necessary, you can also opt out of safeguard holds for known
issues by using the disable safeguards policy.

The following example demonstrates how to create a deployment without safeguards


against likely issues. By specifying a safeguardProfile for the category of likelyIssues
under the list of safeguard profiles to disable, you are configuring the deployment to
offer the update to a device even if it is likely to have an update issue.

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

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",
"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.

Monitoring rules are compatible with deployments of Windows 10 feature updates.

Step 1: Create a monitoring rule


You can create a monitoring rule for a deployment by configuring the monitoring
settings. Each deployment can have one active monitoring rule at a time.

Monitoring rules consist of three components:

signal: The type of update issue to be monitored by the deployment service.


threshold: When this percentage of devices emit the specified signal, the
monitoring rule is triggered.
action: The action to take when the monitoring rule is triggered.

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

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",
"monitoring": {
"monitoringRules": [
{
"@odata.type":
"#microsoft.graph.windowsUpdates.monitoringRule",
"signal": "rollback",
"threshold": 5,
"action": "pauseDeployment"
}
]
},
"schedule": null,
"userExperience": null
},
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}

Step 2: Resume a deployment that was paused


by a monitoring rule
When a monitoring rule triggers, it provides the opportunity to investigate update
issues that may have lead to it being applied. After investigation, you may wish to
resume the deployment. There are two ways to do so: removing the monitoring rule or
updating the monitoring rule threshold.

Example: Resume deployment by removing a monitoring


rule
When a monitoring rule that pauses the deployment is triggered, one way to resume
the deployment is to remove the rule.

Below is an example of resuming the deployment by removing the rule.

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

HTTP/1.1 202 Accepted


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",
"monitoring": {
"monitoringRules": []
},
"schedule": null,
"userExperience": null
},
"createdDateTime": "String (timestamp)",
"lastModifiedDateTime": "String (timestamp)"
}

Example: Resume deployment by updating a monitoring


rule threshold
Another way to resume the deployment is to change the threshold of the relevant
monitoring rule. When the new threshold is reached, the action (in this case,
pauseDeployment ) will be triggered again.

Below is an example of resuming the deployment by changing the monitoring rule


threshold. This example also illustrates how to edit any existing monitoring rule, even if
its threshold has not yet been met, as well as how to create a monitoring rule on a
deployment that does not have one.

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

HTTP/1.1 202 Accepted


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",
"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

This documentation is about the Microsoft 365 Lighthouse API available in


Microsoft Graph. A similar offering, Azure Lighthouse, helps service providers deliver
managed services for Azure services by using comprehensive and robust
management tooling built into the Azure platform. To learn more, see What is
Azure Lighthouse.

Why integrate with Microsoft 365 Lighthouse?


As an MSP, you can use the Microsoft 365 Lighthouse API in Microsoft Graph to gain
insights into identified risks and take action to help get your customers into a healthy
and secure state.

Devices
You can use the Lighthouse API to perform the following device tasks:

Analyze device compliance trends to better understand how device compliance is


evolving over time for your customers.
Understand what device compliance policies have been created across your
customers and the status of the policies.
Threat management
You can use the Lighthouse API to perform the following threat management 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:

Discover risky users across your customers.


View credential user registration summary to understand what users across your
customers have registered for multi-factor authentication and self-service
password reset.

API reference
Looking for the API reference for this service?

See Microsoft 365 Lighthouse API in Microsoft Graph (preview).

7 Note

The Microsoft 365 Lighthouse API is defined in the OData subnamespace,


microsoft.graph.managedTenants .

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.

Why integrate with service health and


communications data?

Get service health and message center posts for a tenant


Customers can get current or historical health data of supported Microsoft services.
When experiencing problems with a Microsoft service, they can check its health status to
verify if an issue has been identified with a resolution in progress, before calling for
support or spending time troubleshooting.

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.

Integrate service communications data into custom


workflows
App developers can integrate active service health issues directly into custom
applications, allowing administrators to triage and share status information with
impacted audiences.

Apps can enable custom workflows for administrators to review, assign, and triage
change communications from the message center.

Build customer-facing dashboards


Create applications with customer-facing dashboards to show the health of Microsoft
services, and let customers keep track of upcoming changes and other important
announcements about the services.
Dashboards examples in Microsoft 365 admin
center
This section shows examples in the Microsoft 365 admin center that uses the service
communications API to build respective health dashboards. Sign in to the admin center
with an admin account, then click Health to see the following dashboards:

Service health
Message center

Service health dashboard


From the Service health dashboard, you can view the health of your subscribed
Microsoft services, which can include Office on the web, Yammer, Microsoft Dynamics
CRM, and mobile device management cloud services. See examples as demarcated in
figure 1.

Figure 1. Service health dashboard in Microsoft 365 admin center

Message center dashboard


From the Message center dashboard, you can view upcoming changes, including new
and changed features, planned maintenance, and other important announcements. See
examples as demarcated in figure 3.

Figure 2. Message center dashboard in Microsoft 365 admin center

Next steps
Try service communications sample queries in Graph Explorer.

Learn more about the service communications API in v1.0.

Learn more about the service communications API in beta.


Education API overview
Article • 06/22/2022

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

Why integrate with education scenarios?

Build applications that are aware of class roster


Most education software developers learn early on that class roster is one of the key
pieces of information they need to run their application, and it's typically locked away
inside a school Student Information System (SIS). Any time teachers bring a new
application into their classroom, they spend time manually importing roster data into
the app. Many independent software vendors (ISVs) address this by connecting with a
SIS to import roster data. With hundreds of Student Information Systems with
proprietary formats, this can become a challenge.

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:

Get all classes in a school


Get all users in a class
Get all the classes I teach

Use Microsoft Teams to create class assignments in an


assignments tab
You can use the assignment-related education APIs to integrate with assignments in
Microsoft Teams. Microsoft Teams in Microsoft 365 for Education is based on the same
education APIs, and provides a use case for what you can do with the APIs. Your app can
use these APIs to interact with assignments throughout the assignment lifecycle.

The assignment APIs provide the following key resources:


educationAssignment: The core object of the assignments API. Represents a task or
unit of work assigned to a student or team member in a class as part of their study.
educationSubmission: Represents the resources that an individual (or group)
submits for an assignment and the associated grade and feedback for that
assignment.
educationResource: Represents the learning object that is being assigned or
submitted. An educationResource is associated with an educationAssignment
and/or an educationSubmission.

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:

Add an assignment that links to your application


Assign outcomes like grades to individual students for assignments linked to your
application
Create a student dashboard to show which assignments are due by when

Enable school admins to manage identity and roster sync


using School Data Sync Management (preview)
School Data Sync helps to automate the process of importing and synchronizing
student identity and roster data from student information systems with Azure Active
Directory (Azure AD) and Microsoft 365. When the information is synchronized, you can
use the roster APIs to read the roster information into the applications.

If you're a system integrator setting up integration of a school's Student Information


System with School Data Sync, you can use the SDS management APIs in Microsoft
Graph to set up synchronization from either a CSV file or a supported SIS API connector.

School Data Sync management APIs support end-to-end scenarios for managing sync;
for example:

Create a synchronization profile that automatically starts a sync.


Manage sync lifecycle with pause, resume and reset operations.

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:

Use the roster APIs


Use the assignment APIs
Use the SDS management APIs

Try the education APIs in Graph Explorer

Explore the following education-related samples:

.NET sample for SSO & Rostering


Sample for profile management APIs
Education rubric overview
Article • 06/22/2022

Rubrics are an effective and widely-used way of grading assignments, and the education
API in Microsoft Graph supports them.

A grading rubric is a matrix of qualities, levels, and criteria, as follows:

Level Level

Quality Criterion Criterion

Quality Criterion Criterion

An example of a grading rubric might be:

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.

Good (2 points) Poor (1 point)

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.

Step 1 - Construct the upload URL


Build the URL to upload content following this specific format {resourcesFolderUrl}:/{Name of
new file}:/content . The following example shows an upload URL that contains the

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

Binary data for the file

Response
The following example shows the response.

HTTP

HTTP/1.1 201 Created


Content-type: application/json

{
"@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": {}
}

Step 3 - Construct the value for the fileUrl property


Build the value for the fileUrl property using the following format:
https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id} . Replace the {drive-

id} and {item-id} placeholders with the values described in the following table.

Placeholder Description Example

{drive-id} Drive ID b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wbOp_1uyhNwJMSSpseJneB7Z4F


from the
request URL
used in step
2.
Placeholder Description Example

{item-id} Item ID 01YT2AIJU7DAXTU6XLOJGYWYMTGM5JT5UQ


from the
response
body
obtained in
step 2.

The following example shows a fileUrl based on this format.

HTTP

https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wb
Op_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJU7DAXTU6XLOJGYWYMTGM5JT5UQ

Step 4 - Create educationAssignmentResource


This step shows how to upload a SharePoint resource to an assignment resources folder.

Use the fileUrl from the previous step in the request body to Create an
educationAssignmentResource.

Request

The following example shows the 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

The following example shows the 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.

For more details, see Create educationSubmissionResource.


Upload feedback files for education
submissions using the Microsoft Graph API
Article • 09/15/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 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.

Step 1: Construct the upload URL


Build the URL to upload content following this specific format: {resourcesFolderUrl}:/{Name of
new file}:/content . The following example shows an upload URL that contains the

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

Binary data for the file

Response
The following example shows the response.

HTTP

HTTP/1.1 201 Created


Content-type: application/json

{
"@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": {}
}

Step 3: Construct the value for the fileUrl property


Build the value for the fileUrl property using the following format:
https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id} . Replace the {drive-

id} and {item-id} placeholders with the values described in the following table.

Placeholder Description Example

{drive-id} Drive ID b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wbOp_1uyhNwJMSSpseJneB7Z4F


from the
request URL
used in step
2.
Placeholder Description Example

{item-id} Item ID 01YT2AIJU7DAXTU6XLOJGYWYMTGM5JT5UQ


from the
response
body
obtained in
step 2.

The following example shows a fileUrl based on this format.

HTTP

https://graph.microsoft.com/v1.0/drives/b!6SQl0y4WHkS2P5MeIsSGpKwfynEIaD1OvPVeH4wb
Op_1uyhNwJMSSpseJneB7Z4F/items/01YT2AIJU7DAXTU6XLOJGYWYMTGM5JT5UQ

Step 4: Create educationFeedbackResourceOutcome


This step shows how to upload a SharePoint resource to a feedback resources folder.

Use the fileUrl from the previous step in the request body to create an
educationFeedbackResourceOutcome.

Request

The following example shows the 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

The following example shows the 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.

For more details, see Create educationFeedbackResourceOutcome.


Teacher and student actions for
assignments and submissions
Article • 06/02/2023

This article describes student and teacher roles for assignments and submissions state
transitions, and related transition rules.

Get all the assignments and their respective


submissions that belong to a specific student
Make the following request to get the student's actions:

me/assignments?$expand=submissions with delegated permissions, or


users/id/assignments?$expand=submissions for application permissions.

See the code sample for a student account with Education assignment using Microsoft
Graph SDK

7 Note

For student roles, the isTeacher parameter needs to be set to false.

Get all the assignments for teacher and then


submissions for each assignment
Make the following request to get the teacher's actions:

me/assignments or users/id/assignments to get the assignments belonging to a teacher.


For each of the assignments, use classses/id/assignments/id/submissions to get the
submissions status (one assignment will contain n number of submissions, where n is
the number of students. It can be a single student, a group of students or the entire
class).

See the code sample for a teacher account with Education assignment using Microsoft
Graph SDK .

For a student, an assignment is actionable if the corresponding submission is in a


working, returned or reassigned state. For a teacher, an assignment is actionable if any of
the submissions of that assignment are in a submitted state.

State transition rules


The following state transition rules are applicable for both student and teacher roles:

A student turns in, and teacher returns or returns for revision.


A teacher returns submissions.
A student can turn in the assignment only when the submission is in working or
reassigned state.
The return for revision action makes the submission state as reassigned.

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.

Assignment states and transitions


An assignment represents a task or unit of work assigned to a student or team member
in a class as part of their study. Only teachers or team owners can create, copy, or
schedule assignments. These actions have an impact on assignment states. The
following table lists the assignment states and the APIs that are available to change the
state.

State Description REST API call Features


available to
edit

Draft Initial status POST /education/classes/{id}/assignments Resources,


when a new categories,
assignment rubrics
is created or
copied from
an existing
assignment.

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

Scheduled Status when PATCH /education/classes/{id}/assignments/{id} Resources,


the teacher POST categories,
scheduled /education/classes/{id}/assignments/{id}/publish rubrics
the
assignment
to publish at
a future
time.

Assigned "After the POST Submissions


publishing /education/classes/{id}/assignments/{id}/publish
process is POST
complete, /education/classes/{id}/assignments/{id}/activate
the
assignment
is moved to
an assigned
state,
becoming
available for
the
students, or
it stays in an
active state.

Pending Background PATCH /education/classes/{id}/assignments/{id}


processing
status when
a new
assignment
is being
copied from
an existing
one.

Inactive The POST


assignment /education/classes/{id}/assignments/{id}/deactivate
has no
additional
action items
for teachers
and
students.

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.

Assignment state transitions based on the allowed


actions

Current assignment state New action New state

Draft The teacher schedules the assignment Scheduled

Draft Publish Published

Draft Edited Draft

Draft Discarded

Published Publish finished Assigned

Published Publish failed Draft

Published Discarded

Scheduled Reach due date Published


Current assignment state New action New state

Scheduled Cancel schedule Draft

Scheduled Reschedule Scheduled

Assigned Discarded

Assigned Deactivated Inactive

Pending Copy completed Draft

Pending Discarded

Inactive Activated Assigned

7 Note

Only actions and state transitions listed in the table are allowed.

Sync vs. async operations over assignments API calls


The following table lists the API calls that affect the assignment state and operation
type.

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.

API Sync or Mechanism to get latest


async state

DELETE /education/classes/{id}/assignments/{id} Async Poll

POST Async Poll


/education/classes/{id}/assignments/{id}/publish

PATCH /education/classes/{id}/assignments/{id} Async Poll

POST /education/classes/{id}/assignments Async Poll

POST Async Poll


/education/classes/{id}/assignments/{id}/deactivate
API Sync or Mechanism to get latest
async state

POST Async Poll


/education/classes/{id}/assignments/{id}/activate

Limits
The following limits apply to all API calls:

The maximum number of assignment resources are 10 for the teacher.


The maximum size allowed for resources is 500 MB.
Throttling limits apply; for details, see Microsoft Graph throttling guidance.

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.

Submission states and transitions


A submission represents the resources that an individual or group turns in for an
assignment. Submissions are owned by an assignment and are automatically created
when an assignment is published.

The status is a read-only property in the submission. It changes based on the actions of
students and teachers.

State Description REST API call

Working Initial state POST /education/classes/{id}/assignments


after the POST
submission /education/classes/{id}/assignments/{id}/submissions/{id}/unsubmit
is created.

Submitted The state POST


after the /education/classes/{id}/assignments/{id}/submissions/{id}/submit
student
turns in the
assignment.

Returned The state POST


after the /education/classes/{id}/assignments/{id}/submissions/{id}/return
teacher has
returned an
assignment
to the
student.
State Description REST API call

Reassigned The state POST


after the /education/classes/{id}/assignments/{id}/submissions/{id}/reassign
teacher has
returned
the
assignment
to the
student for
revision.

The following diagram shows the state transition flow.

Submission state transitions based on allowed actions

Current submission state New action New state

Working Turn in Submitted

Working Return for revision Reassigned

Working Return Returned

Submitted Undo Turn in Working

Submitted Return Returned

Submitted Return for revision Reassigned


Current submission state New action New state

Returned Turn in Submitted

Returned Return Returned

Returned Return for revision Reassigned

Reassigned Turn in Submitted

Reassigned Return Returned

Reassigned Return for revision Reassigned

7 Note

Any action and state transition not listed in the table is not allowed.

Sync vs. async operations over submissions API calls


The following table lists the API calls that affect the submission state and the operation
type.

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.

API Sync Mechanism to


or get latest state
async

POST Async Poll


/education/classes/{id}/assignments/{id}/submissions/{id}/submit

POST Async Poll


/education/classes/{id}/assignments/{id}/submissions/{id}/unsubmit

POST Async Poll


/education/classes/{id}/assignments/{id}/submissions/{id}/return

POST Async Poll


/education/classes/{id}/assignments/{id}/submissions/{id}/reassign

Limits
The following limits apply to all API calls:

The maximum number of submission resources are 10 for the student.


The maximum size allowed for resources is 500 MB.
Throttling limits apply; for details, see Microsoft Graph throttling guidance.

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.

Step 1 - Get the team ID based on your team name


To find the team id, make a GET request with the team name. If you already have the
team id, skip this step.

Request
The following example shows the request.

HTTP

GET https://graph.microsoft.com/v1.0/teams?$filter=displayName eq 'English


Fall ''21'
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",
"@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
}
]
}

Step 2 - Get the channel ID based on channel name and


team ID
Make a GET request with the team ID obtained in the previous step and the channel
name. Skip this step if you already have the channel id.

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"
}
]
}

Step 3 - Construct the value for the


notificationChannelUrl property
Build the value for the notificationChannelUrl property using the following format:

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.

Placeholder Description Example


Placeholder Description Example

{team-id} The team ID 72a7baec-c3e9-4213-a850-f62de0adad5f


from the
response in
step 1. This is
the team that
the current
assignment
belongs to.

{channel- Item ID from 19:jb2-


id} the response [email protected]
body obtained
in step 2.

The following example shows a notificationChannelUrl based on this format.

HTTP

https://graph.microsoft.com/v1.0/teams/72a7baec-c3e9-4213-a850-
f62de0adad5f/channels/19:jb2-
[email protected]

Step 4 - Assign the value to the notificationChannelUrl


property for the assignment
You have now successfully built the url, it's time to assign the value to the property. You
can perform this operation by updating either the educationAssignment or
educationAssignmentDefaults resources.

Example 1: Update an educationAssignment

Request

The following is an example of the 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

The following 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

{
"@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
}
}
}

Example 2: Update educationAssignmentDefaults

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.

Use the following steps to join Microsoft Partner Network:

1. Go to Partner with Microsoft and select Become a partner.

2. Select one or more options to specify how you would like to partner with
Microsoft, and choose Next.

3. Specify your company work account 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.

7. Sign in with your Microsoft Partner Network account.

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:

Demo EDU dev tenant


Demo EDU tenant

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.

With this tenant, you can:

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.

To get an EDU developer tenant:

1. Go to Partner Sign Up and choose Microsoft Education Integration.

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.

3. After you provide all the required information, choose Submit.

You will receive an email notification about you tenant request.

See also
See the following resources to get started with your developer tenant:

Microsoft 365 Dev Center


Create a Teams app
Create a progressive web apps

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.

Create a new demo education tenant


1. Go to the My environments tab.

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

3. Select the tenant type from the following:

Quick tenant: A pre-provisioned custom Microsoft 365 tenant. These tenants


contain the same robust demo content and add-on options (such as EMS,
PSTN calling, and so on) that custom tenants have but without the wait. The
Microsoft 365 tenant is immediately available; however, the add-ons content
is provisioned only upon request.
Custom tenant: Only available for Microsoft users (@microsoft.com). With a
custom tenant, you can customize the following: Tenant name,
Country/Region, Notification email, any of the demo personas. Custom
tenants will not start the provisioning process until you choose Finish.
Standard Microsoft 365 tenants take approximately 12-48 hours to proviion
(not including add-ons). Dynamics 365 tenants take approximately 24-60
hours to provision.

4. Select the tenant period from the following.

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.

After one year, you need to get new codes to renew .

5. Look for Microsoft Education Demo Content and choose Create tenant.

6. Accept the terms of use.

Important: You must not use a demo EDU tenant for development purposes.

7. When the tenant is created, the tenant details will be displayed.

Set up user licenses


For information about tenant licensing and user permissions, see the following:

Understand subscriptions and licenses


Assign licenses to users
Unassign licenses from users
Buy or remove licenses from your subscription

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:

1. In the left pane, choose + Add Profile to create a sync profile.

2. On the Choose connection type page, complete the form.

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.

4. Choose a future stop date, and then choose Next.

In a production scenario, you would choose to sync existing users.


For more details about the sync process, see How to deploy School Data Sync
by using 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.

Install Microsoft Teams


To install Microsoft Teams, open a private browser window and go to
teams.microsoft.com/download , or go to teams.microsoft.com to sign in online.

When prompted by the installer, sign in with your Office 365 Global Admin account
credentials.

After the installation finishes, complete the welcome wizard.

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.

3. Enter a name for your team.

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:

1. Open a private web browser, go to developer.microsoft.com/en-us/graph/graph-


explorer, choose Sign in to Graph Explorer, and enter your Office 365 Global
Admin account credentials.

2. To access the rostering API, grant the corresponding permissions to Graph


Explorer. Go to Modify permissions, search for EduRoster.ReadBasic, and choose
Consent.

You might have to wait for the permissions to update before you can run all
queries.

3. To get a list of your schools, in the query field, enter


https://graph.microsoft.com/v1.0/education/schools and choose Run query.

4. To get a list of classes, in the query field, enter


https://graph.microsoft.com/v1.0/education/classes and choose Run query.

5. Take the first class ID 740202c8-5db7-4496-a055-9f3c9fd98207 to get that class's


assignments. In the query field, enter
https://graph.microsoft.com/v1.0/education/classes/740202c8-5db7-4496-a055-

9f3c9fd98207/assignments , and choose Run query.

6. To access the assignments API, grant the corresponding permissions to Graph


Explorer. Go to Modify permissions, search for EduAssignments.Read,
EduAssignments.ReadBasic, EduAssignments.ReadWrite and
EduAssignments.ReadWriteBasic, and choose Consent.

7. Run the query to get the assignments.


8. Now you can try to create a new assignment. In the query field, enter
https://graph.microsoft.com/v1.0/education/classes/740202c8-5db7-4496-a055-
9f3c9fd98207/assignments . Make sure that POST is selected for the request type.

9. In the Request body field, paste the following JSON.

```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.

Get data from assignments and grades


Get links to assignments and submissions
Integrate your Teams app with education assignments
Update assignment and grade data
Embed a Teams app in an assignment
Download all resources from a set of assignments
I have a web app that needs to create assignments with links back to my website
Get assignmment and grade
information for education solutions
Article • 01/19/2023

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.

Get classes and members information


Assignment and grade information is part of the team in Microsoft Teams. You can get
information about classes, members, and roles (student or teacher) in a team by using
the following APIs:

List classes of an educationSchools: Returns a list of all classes in your education


tenant.
List members of an educationClass: Lists information about members of a specific
class.

After you get the relevant class and member information, you can get the assignment
and grade information that you need.

Get class assignment information


All assignments and students' information are linked to class and submission
information, respectively. You can use the following APIs to retrieve information about
class assignments:

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.

Get student assignment information


A student is often in multiple classes within a school, and you often need to see the data
for the student across classes. You can use the following API to see student data across
classes:

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.

Updates to the data


Over the course of the school year, there will be updates to assignments as teachers and
students continue to work on them. All education APIs support delta query, allowing
you to track changes since the last time the API endpoint was queried.

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.

Create a Microsoft Teams app


Microsoft Teams offers a collection of apps that are provided by Microsoft or external
services. The apps can be tabs, bots, message extensions, or resources.

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 .

Request to enable your Teams app for


assignment flows
After you create and publish your Teams app, before you can integrate with
assignments, your app must be enabled. To request to have your app enabled, complete
this form .

Add your Teams app to an assignment


Your Teams app can be added as an assignment resource.

1. Get the application id using this endpoint. Do not supply a request body.

HTTP

GET /appCatalogs/teamsApps?$filter=displayName eq 'APPLICATION NAME'


2. Attach the Teams app to an assignment.

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

The following is an example of the 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/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.

Get class and member information


All assignments and grading information are part of a team in Microsoft Teams. You can
get information about classes, members, and roles (student or teacher) in a team by
using the following Teams APIs:

List classes of an educationSchools: Returns a list of all classes in your education


tenant.
List members of an educationClass: Lists information about members of a specific
class.

After you get the relevant class and member information, you can get the assignment
and grade information you need.

Get a deep link for the assignment


The assignment webUrl property returns the authenticated deep link to selected
assignments. If the user is within Teams, the assignments will open directly with this
deep link URL.

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.

Get a deep link for the submission


The submission webUrl property returns an authenticated deep link to a submission.
Currently, the webUrl property for submissions is only available in the beta endpoint.

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.

Get class and member information


All the assignments and grading information are part of the team in Microsoft Teams.
You can get information about classes, members, and roles (student or teacher) in a
team by using the following Teams APIs:

List classes of an educationSchools: Returns a list of all classes in your education


tenant.
List members of an educationClass: Lists information about members of a specific
class.

After you get the relevant class and member information, you can get the assignment
and grade information you need.

Assignment and submission information


All assignment and student information is linked to class and submission information,
respectively. The following APIs retrieve information about class assignments and
submissions:

educationAssignment resource type: Lists all the methods available for


assignments in a class. A user can get all the educationAssignmentResource
objects associated within an assignment.
educationSubmission resource type: A submissionId is created for every student
for whom an assignment is published. You can use this API to get the submission
status - for example, whether it was turned in and graded, (resources) submitted
by the student, and the grade (outcome) for the submission.
Update grade (outcome) data
Users can update the properties of an educationOutcome object. Existing properties
that are not included in the request body will maintain their previous values. Only
teachers can perform this operation.

The following example describes on how to update a points outcome.

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"
}
}
}
}

This request returns an updated educationOutcome object in the response body.

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.

Get class assignment information


Assignment information is linked to a class. You can use the Get educationAssignment
API to get information about class assignments. You can then use the OData query
parameters to customize the response.

Get assignment and submission resource


information
Assignments and submissions are an important part in the interaction between teachers
and students. You can use the following APIs to get information about assignment and
submission resources:

Get educationAssignmentResource to retrieve the properties of an education


assignment resource associated with an assignment.
Get educationSubmissionResource to retrieve the properties of a specific resource
associated with a submission.

Get submission feedback information


The education API in Microsoft Graph uses feedback resource folders as a destination
for feedback files. To get details about the user's submission feedback, see Upload
feedback files for education submissions.

You can use the List outcomes API to get a list of education outcome objects.

Download files from SharePoint


Before you can download the SharePoint resources, you need the driveId and itemId
that are related to each assignment resource. You can use the List
educationAssignmentResources response object to extract information about the
corresponding driveId and itemId from the fileUrl property.

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.

Install the application in your team


Before you can embed an application in an assignment, you need to make sure that the
app is installed in your team. You can use the following APIs to get information about
the apps installed in a team:

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:

Add an app to a team: Install an app to the specified team.

Create the new assignment


An assignment represents a task or unit of work assigned to a student or team member
in a class as part of their study. You can use the Create educationAssignment API to
create a new assignment for the class.

Add the app resource


An education Teams app resource allows education service users to create and share
assignments with embedded Teams applications. You can use the Create
educationAssignmentResource API to create and load the app resource into an
assignment. This operation requires you to provide an educationTeamsAppResource in
the request body.

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

Do not use extensions to store sensitive personally identifiable information, such as


account credentials, government identification numbers, cardholder data, financial
account data, healthcare information, or sensitive background information.

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?

Why add custom data to Microsoft Graph?


As an ISV developer, you might decide to keep your app lightweight and store
app-specific user profile data in Microsoft Graph by extending the user resource.
Alternatively, you might want to retain your app's existing user profile store, and
add an app-specific identifier to the user resource.
As an enterprise developer, the in-house applications that you build might rely on
your organization's HR-specific data. Integration within multiple applications can
be simplified by storing this custom data in Microsoft Graph.

Custom data options in Microsoft Graph


Microsoft Graph offers four types of extensions for adding custom data.

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.

Add or update data in extension attributes


The following example shows how to store data in extensionAttribute1 and delete
existing data from extensionAttribute13 through an update operation with a PATCH
method.

HTTP

HTTP

PATCH https://graph.microsoft.com/v1.0/users/071cc716-8147-4397-a5ba-
b2105951cc0b

{
"onPremisesExtensionAttributes": {
"extensionAttribute1": "skypeId.adeleVance",
"extensionAttribute13": null
}
}

The request returns a 204 No Content response object.

Read the extension attributes


Request

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
}
}
]
}

Considerations for using extension attribute properties


The onPremisesExtensionAttributes object can be updated only for objects that aren't
synced from on-premises AD.

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.

Directory (Azure AD) extensions


Directory extensions provide developers with a strongly typed, discoverable and
filterable extension experience for directory objects.

Directory extensions are first registered on an application through the Create


extensionProperty operation and must be explicitly targeted to specific and supported
directory objects. After the application has been consented to by a user or an admin, the
extension properties become immediately accessible in the tenant. All authorized
applications in the tenant can read and write data on any extension properties defined
on an instance of the target directory object.

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.

Define the directory extension

Before you can add a directory extension to a resource instance, you must first define
the directory extension.

Request

In the following request, 30a5435a-1871-485c-8c7b-65f69e287e7b is the object ID of the


application that owns the directory extension. On the beta endpoint, you can create
directory extensions that store a collection of values.
HTTP

HTTP

POST https://graph.microsoft.com/v1.0/applications/30a5435a-1871-485c-
8c7b-65f69e287e7b/extensionProperties

{
"name": "jobGroupTracker",
"dataType": "String",
"targetObjects": [
"User"
]
}

Response

A directory extension property named


extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker is created with an

extension name that follows the following naming convention: extension_{appId-


without-hyphens}_{extensionProperty-name}.

HTTP

HTTP/1.1 201 Created


Content-type: application/json

{
"@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"
]
}

Add a directory extension property to a target object


After defining the directory extension, you can now add it to an instance of a target
object type. You can store data in the directory extension when creating a new instance
of the target object or when updating an existing object. The following example shows
how to store data in the directory extension when creating a new user object.

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.

Retrieve a directory extension


The following example shows how the directory extensions and associated data are
presented on a resource instance. The extension property will be returned by default
through the beta endpoint, but only on $select through the v1.0 endpoint.

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
}
]
}

Update or delete directory extensions

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"
}

The request returns a 204 No Content response code.


Considerations for using directory extensions
If you accidentally delete a directory extension definition, any data that's stored in the
associated property becomes undiscoverable. To resolve this, create a new directory
extension definition on the same owner app and with exactly the same name as the
deleted definition.

When a definition object is deleted before the corresponding extension property is


updated to null , the property will still count against the 100-limit for the object.

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.

Define a schema extension

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"
}
]
}

Add a schema extension to a resource instance


After defining the schema extension, you can now add the extension property to an
instance of a target object type. You can store data in the schema extension when
creating a new instance of the target object or when updating an existing object. The
following example shows how to store data in the schema extension property when
creating a new user object.

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

Update or delete a schema extension property


Use the PATCH operation to update a schema extension or delete an existing schema
extension. To delete the extension property and its associated value from the resource
instance, set its value to null .

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
}
}

The request returns a 204 No Content response object.

Retrieve the schema extension property


To read the schema extension properties on a resource instance, specify the extension
name in a $select request.

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
}
}

Considerations for using schema extensions


A schema extension must have an owner app. Ownership of the schema extension can't
be reassigned to another app.

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.

Create an open extension


The following example shows an open extension definition with three properties and
how the custom properties and associated data are presented on a resource instance.

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.

Update an existing open extension

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"
}

This request returns a 204 No Content response code.

Retrieve the open extensions

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"
}

Considerations for using open extensions


Deleting a creator app doesn't affect the open extension and the data it stores.

Comparison of extension types


The table below contrasts and compares the extension types, which should help you
decide which option is most appropriate for your scenario.

Capability Extension Directory Schema Open


attributes 1-15 extensions extensions extensions
Capability Extension Directory Schema Open
attributes 1-15 extensions extensions extensions

Supported resource user user user user


types device group group group
administrativeUnit administrativeUnit contact
application contact device
device device event1 (both
organization event (both user user and
and group group
calendars) calendars)
message message
organization organization
post post
todoTask
todoTaskList

Strongly typed No Yes Yes No

Filterable Yes Yes Yes No

Can store a No Yes No No


collection2

Managed via Microsoft Microsoft Graph Microsoft Graph Microsoft


Graph Graph
Exchange
admin center

Sync data from on- Yes, for users Yes No No


premises to
extensions using
AD connect

Create dynamic Yes Yes No No


membership rules
using custom
extension
properties and data

Usable for Yes Yes No No


customizing token
claims

Available in Azure Yes Yes Yes Yes


AD B2C
Capability Extension Directory Schema Open
attributes 1-15 extensions extensions extensions

Limits 15 100 extension Maximum of Two open


predefined values per five definitions extensions per
attributes per resource instance per owner app creator app
user or device 100 extension per resource
resource values per instance3
instance resource instance Max. of 2
(directory objects Kb per open
only) extension3
For
Outlook
resources,
each open
extension is
stored in a
MAPI named
property4

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.

Permissions and privileges


The same privileges that your app requires to read from or write to a resource instance
are also required to manage any extensions data on that resource instance. For example,
for an app to update any user's profile with custom app data, the app must have been
granted the User.ReadWrite.All Microsoft Graph permission.

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

This article demonstrates how to use open extensions.

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.

1. Add roaming profile information


The user signs in to the app and configures the look and feel of the app. These app
settings should roam so that the user gets the same experience on whatever device they
sign in to the app from. The app calls Microsoft Graph by running the following request
to add the roaming profile information to a user resource.

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

HTTP/1.1 201 Created


Content-Type: application/json

{
"@odata.type": "#microsoft.graph.openTypeExtension",
"extensionName": "com.contoso.roamingSettings",
"id": "com.contoso.roamingSettings",
"theme": "dark",
"color": "purple",
"lang": "Japanese"
}

2. Retrieve roaming profile information


When the user signs in to the app from another device, the app calls Microsoft Graph to
retrieve the user's profile details and expand the extensions navigation property to get
their roaming settings.

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"
}
]
}

3. Change roaming profile information


The user can choose to change their roaming profile information. The app calls
Microsoft Graph by running the following query.

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

4. Delete a user's roaming profile


The user decides that they don't want a roaming profile anymore, so they delete it and
the app calls Microsoft Graph by running the following request.

Request

HTTP

HTTP

DELETE
https://graph.microsoft.com/v1.0/me/extensions/com.contoso.roamingSettin
gs

Response

HTTP/1.1 204 No content

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

This article demonstrates how to use schema extensions.

Imagine you're a developer in a Learning Management Software company called "Graph


Learn" that builds training courses and materials for businesses. You use the
collaborative experience of Microsoft 365 groups to deliver course content and record
exercises among participants for both online courses and instructor-led courses. You
want to make the Microsoft 365 groups used for training courses easily identifiable as
training courses, which will allow other developers to discover your groups and build
rich experiences on top of your learning courses.

For this scenario, this article will show you how to:

1. View available schema extension definitions that you could use.


2. Register a schema extension definition that targets groups for training courses.
3. Create a new group with custom data based on the schema extension definition
that you registered.
4. Add, update, or remove custom data in an existing group based on a schema
extension definition.
5. Read a group and the extension data.

7 Note

Apart from groups, schema extensions are also supported and can be managed for
other resource types.

1. View available schema extensions


First, as a developer, you might want to find any other schema extension definitions that
our app could reuse.

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"
}
]
}
]
}

2. Register a schema extension definition that


describes a training course
If you can't find a schema extension that is appropriate for your needs, you can create
and register a new extension definition for training courses on the group resource.
When creating a schema extension definition, you should provide a string for the id
property. Assuming you've verified your vanity domain graphlearn.com with your tenant,
you'll concatenate the verified domain name ( graphlearn ) with a name for the schema
extension ( courses ), and assign id with the resultant string, graphlearn_courses . This id
becomes the name of the schema extension property on a group. See an example of the
other way to assign id in the request that requires you to provide only a schema name.

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

HTTP/1.1 201 Created


Content-Type: application/json

{
"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"
}
]
}

3. Create a new group with extended data


The following request creates a new group and uses the graphlearn_courses schema
extension to extend the group with custom data.

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

HTTP/1.1 201 Created


Content-Type: application/json

{
"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"
}

4. Add, update, or remove custom data in an


existing group
You can now extend and add custom data to the group you created by updating the
graphlearn_courses complex type as follows.

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

HTTP/1.1 204 No Content

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 .

5. Get a group and its extension data


A handy way to look for a group (or groups) is to use $filter to match for specific
extension property values, such as an extension name or ID.
Then, to get the custom data in a group, use $select to include the extension by name
(in this case by graphlearn_courses ).

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

Why integrate with OneDrive file storage in the


cloud?

Tap into an ecosystem with billions of files


OneDrive users can access their files from any device, online or offline, and share files
with people inside or outside their organization. OneDrive enables real-time
coauthoring in familiar apps like Word, Excel, and PowerPoint. Files light up with rich
thumbnails for hundreds of formats, video streaming, analytics, and more, powered by
Microsoft Graph. Data in OneDrive is protected with advanced encryption, compliance,
and security features that customers trust.

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.

Store your app's files in a powerful cloud


When you store your files in OneDrive, your app can take advantage of the features of
the Microsoft cloud and your users can access their files anywhere. Use the file picker
SDK to quickly open, download, save, or share files stored in OneDrive from within your
own app, using the same experience OneDrive users are familiar with. Get information
about selected files directly from the picker SDK, or use Microsoft Graph APIs directly to
interact more deeply with files. Use special folders to store files in well-known locations
on OneDrive, like Documents and Camera Roll , or give your app its own personal folder.

Bring your app straight to users within OneDrive


OneDrive customers can use or launch your app directly from within OneDrive to open,
edit, or preview files. Use OneDrive's file handler extensions to provide icons and
previews for your own custom file extensions, add your app to the New button or even
add your own custom actions to the menu bar to launch your app.

Work with content in formats your app understands


Your app can get file content in the format that is most convenient for you. Your app can
display custom-sized thumbnails for hundreds of different file formats. You can
download files in a variety of alternative formats, like PDF. You can even embed the
OneDrive file previewers within your app by using the preview API (beta).

Work with file content and metadata without


downloading the binary
With Microsoft Graph, you can access rich content through REST APIs without having to
download the binary. Explore extracted metadata from photo, audio, and video files. Use
the Excel API to work directly with the raw data stored in an Excel workbook. Use the
Notes API to access the contents of OneNote notebooks.

React to file changes


With webhooks, your app can get notified when files change so you can quickly react.
Use the delta API to see what changed since the last time your app synchronized with
the cloud.

API reference
Looking for the API reference for this service?

OneDrive file storage API in Microsoft Graph v1.0


OneDrive file storage API in Microsoft Graph beta

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.

URL example Description


URL example Description

/drive/root:/Documents/MyFile.xlsx:/content Specified by path relative to the root of a


drive.

/drive/special/documents:/MyFile.xlsx:/content Specified by filename in the documents


special folder.

/drive/items/0123456789AB/content Specified by item-id.

/drives/AB0987654321/items/0123456789AB/content Specified by drive-id and item-id.

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.

OneDrive reserved characters


The following characters are OneDrive reserved characters and can't be used in
OneDrive folder and file names.

onedrive-reserved = "/" / "\" / "*" / "<" / ">" / "?" / ":" / "|"


onedrive-business-reserved
= "/" / "\" / "*" / "<" / ">" / "?" / ":" / "|" / "#" /
"%"

7 Note

Folder names can't end with a period ( . ).


File or folder names cannot begin with a tilde ('~').

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.

pchar = unreserved / pct-encoded / sub-delims / ":" / "@"


pct-encoded = "%" HEXDIG HEXDIG
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="

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:

" " -> %20

"#" -> %23

Common URL encoding mistakes


You can't encode an entire URL in one call, because the encoding rules for each segment
of a URL are different. Without proper encoding, the unencoded URL will be ambiguous
for which segments contain which content. As such, you need to encode the URL path
when building your URL string.

For example, instead of writing this:

string url = url_encode("https://graph.microsoft.com/v1.0/me/drive/root:/" +


path + ":/children")

Write this:

string url = "https://graph.microsoft.com/v1.0/me/drive/root:/" +


url_path_encode(path) + ":/children")
However, not all URL encoding libraries respect all the requirements of standard URL
path encoding.

.NET / C-Sharp / Visual Basic


The .NET classes for HttpUtility and Uri include various methods for URL encoding.
However, none of those methods properly encode all reserved characters for the path
component of the URL (including HttpUtility.UrlPathEncode ).

Instead of using those methods, you should use UriBuilder to construct a properly
escaped URL.

C#

UriBuilder builder = new UriBuilder("https://graph.microsoft.com");


builder.Path = "/v1.0/me/drive/root:/Documents/My Files/#nine.docx";
Uri url = builder.Uri;

Objective-C / iOS
For Objective-C, iOS and Mac OS X development, use the
stringByAddingPercentEncodingWithAllowedCharacters method and [NSCharacterSet

URLPathAllowedCharacterSet] to properly encode the path component of the URL.

Objective-C

NSString *root = @"https://graph.microsoft.com/v1.0/me/drive/root:/";


NSString *path = @"Documents/My Files/#nine.docx";
NSString *encPath = [path
stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet
URLPathAllowedCharacterSet]];
NSURL *url = [[NSURL alloc] initWithString:[root
stringByAppendingString:encPath]];

Android
Use the Uri.Builder class to construct a properly encoded URL.

Java

Uri.Builder builder = new Uri.Builder();


builder.
scheme("https").
authority("graph.microsoft.com").
appendPath("v1.0").
appendPath("me").
appendPath("drive").
appendPath("root:").
appendPath("Documents").
appendPath("My Files").
appendPath("#nine.docx");
String url = builder.build().toString();

JavaScript
Use escape() in JavaScript to properly encode a path component.

JavaScript

var root = "https://graph.microsoft.com/v1.0/me/drive/root:";


var path = "/Documents/My Files/#nine.docx";
var url = root + escape(path);

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

To address each of Adele's files, you use percent encoding, as follows:

Path Encoded URL for path

\Adele's Files /root:/Adele's%20Files

\...\doc (1).docx /root:/Adele's%20Files/doc%20(1).docx

\...\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

Dynamics 365 Business Central is an all-in-one business management solution that is


easy to use and adapt, helping you connect your business and make smarter decisions.
It provides an end-to-end view of your business, enabling you to manage your
financials, automate and secure your supply chain, sell smarter and improve customer
service, keep projects on time and under budget, and optimize your operations.
https://www.youtube-nocookie.com/embed/na1kFk53cbk

Why integrate with Dynamics 365 Business


Central?
By integrating your apps with Dynamics 365 Business Central, you can create
experiences that span your business needs. You can create solutions that empower your
users to perform key business tasks and functions. You can use Microsoft Graph to
access and manage your financials, work with business contacts, create and send sales
and purchasing documents, and gain insights from financial reports.

Synchronize your business applications


Many companies use different, disconnected business applications to manage various
functions of the business. Microsoft Graph enables you to connect the data to bring
these applications together. This makes it easy to connect your payroll application to
employee records, connect your expense application to vendor records, and have your
CRM application keep your customer records up to date. Connect your data to keep
your applications in sync.

Create custom apps to manage your business processes


Every business is different and can have specialized business processes. These processes
can be streamlined with custom apps tailored to the process. Microsoft Graph makes it
easy to integrate these apps with your financial data. Building a sales or field service app
that creates sales documents, an expense app that creates purchasing documents, or a
payroll app that creates general ledger journals becomes possible, keeping all your
documents in your financial system.
Gain insights from your financial data
Microsoft Graph provides access to your financial reports. Connect BI tools and apps to
your balance sheet, cash flow statement, payables and receivables aging reports, and
trial balance reports to create BI dashboards and ensure that users have access to the
information they need.

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?

Dynamics 365 Business Central API in Microsoft Graph beta


Azure AD identity and access
management API overview
Article • 01/27/2023

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.

Why use the Azure AD APIs?


More than 15 million organizations use Azure AD while subscribing to Microsoft cloud
services like Microsoft 365, Microsoft Azure, and Enterprise Mobility Suite.

Enterprise developers use Microsoft Graph to integrate Azure AD identity management


and other services to automate administrative workflows, such as employee onboarding
(and termination), profile maintenance, license deployment, and more.

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.

Manage users and groups


You can use Azure AD APIs in Microsoft Graph to:

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 directory roles


You can assign users to predefined Azure AD administrative directory roles, which grants
permission to perform specific tasks.

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.

Partner tenant management


Microsoft partners that resell and manage Microsoft Online Services (such as Microsoft
365, Microsoft Azure, and CRM Online) can view the organization tenants they currently
manage.

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.

Today, Microsoft Graph gives easy access to customers of Azure AD Premium P2 to


query risk events detected by Identity Protection, including the risk event’s type,
severity, date, time, location, impacted user, and more. Customers can then use those
events in SIEM systems and security applications.

Review access to organizational resources


Review access to groups, applications, and even privileged roles in your organization.
Access reviews is featured in Azure AD Premium P2.

Activate users into privileged roles


Use the Privileged Identity Management (PIM) API to activate administrator privilege on
demand. Enforce mandatory justification of role activation, and multifactor
authentication for actors in privileged roles.

API reference
Looking for the API reference for this service?

Azure AD identity and access management API in Microsoft Graph v1.0


Azure AD identity and access management API in Microsoft Graph beta

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

Assign custom security attributes


Example 1: Assign a custom security attribute with a
string value to a user
The following example shows how to use the Update user API to assign a custom
security attribute with a string value to a user.

Attribute set: Engineering


Attribute: ProjectDate
Attribute data type: String
Attribute value: "2022-10-01"

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

HTTP/1.1 204 No Content

Example 2: Assign a custom security attribute with a


string value to a service principal
The following example shows how to use the Update user API to assign a custom
security attribute with a string value to a service principal.

Attribute set: Engineering


Attribute: ProjectDate
Attribute data type: String
Attribute value: "2022-10-01"

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

HTTP/1.1 204 No Content

Example 3: Assign a custom security attribute with a


multi-string value to a user
The following example shows how to use the Update user API to assign a custom
security attribute with a multi-string value to a user.

Attribute set: Engineering


Attribute: Project
Attribute data type: Collection of Strings
Attribute value: ["Baker","Cascade"]

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

HTTP/1.1 204 No Content

Example 4: Assign a custom security attribute with an


integer value to a user
The following example shows how to use the Update user API to assign a custom
security attribute with an integer value to a user.

Attribute set: Engineering


Attribute: NumVendors
Attribute data type: Integer
Attribute value: 4

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/1.1 204 No Content

Example 5: Assign a custom security attribute with a


multi-integer value to a user
The following example shows how to use the Update user API to assign a custom
security attribute with a multi-integer value to a user.

Attribute set: Engineering


Attribute: CostCenter
Attribute data type: Collection of Integers
Attribute value: [1001,1003]
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(Int32)",
"CostCenter":[1001,1003]
}
}
}

Response

HTTP

HTTP/1.1 204 No Content

Example 6: Assign a custom security attribute with a


Boolean value to a user
The following example shows how to use the Update user API to assign a custom
security attribute with a Boolean value to a user.

Attribute set: Engineering


Attribute: Certification
Attribute data type: Boolean
Attribute value: true

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

HTTP/1.1 204 No Content

Update custom security attribute assignments

Example 1: Update a custom security attribute assignment


with an integer value for a user
The following example shows how to use the Update user API to update a custom
security attribute assignment with an integer value for a user.

Attribute set: Engineering


Attribute: NumVendors
Attribute data type: Integer
Attribute value: 8

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

HTTP/1.1 204 No Content

Example 2: Update a custom security attribute


assignment with a Boolean value for a user
The following example shows how to use the Update user API to update a custom
security attribute assignment with a Boolean value for a user.

Attribute set: Engineering


Attribute: Certification
Attribute data type: Boolean
Attribute value: false

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

HTTP/1.1 204 No Content

List custom security attribute assignments

Example 1: Get the custom security attribute assignments


for a user
The following example shows how to use the Get user API to get the custom security
attribute assignments for a user.

Attribute #1

Attribute set: Engineering


Attribute: Project
Attribute data type: Collection of Strings
Attribute value: ["Baker","Cascade"]

Attribute #2

Attribute set: Engineering


Attribute: CostCenter
Attribute data type: Collection of Integers
Attribute value: [1001]

Attribute #3

Attribute set: Engineering


Attribute: Certification
Attribute data type: Boolean
Attribute value: true

Attribute #4

Attribute set: Marketing


Attribute: EmployeeId
Attribute data type: String
Attribute value: "QN26904"

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
}

Example 2: List all users with a custom security attribute


assignment that equals a value
The following example shows how to use the List users API to list all users with a custom
security attribute assignment that equals a value. The example retrieves users with a
custom security attribute named AppCountry with a value that equals Canada . The filter
value is case sensitive. You must add ConsistencyLevel=eventual in the request or the
header. You must also include $count=true to ensure the request is routed correctly.

User #1

Attribute set: Marketing


Attribute: AppCountry
Attribute data type: Collection of Strings
Attribute value: ["India","Canada"]

User #2

Attribute set: Marketing


Attribute: AppCountry
Attribute data type: Collection of Strings
Attribute value: ["Canada","Mexico"]

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"
}
}
}
]
}

Example 3: List all users with a custom security attribute


assignment that starts with a value
The following example shows how to use the List users API to list all users with a custom
security attribute assignment that starts with a value. The example retrieves users with a
custom security attribute named EmployeeId with a value that starts with GS . The filter
value is case sensitive. You must add ConsistencyLevel=eventual in the request or the
header. You must also include $count=true to ensure the request is routed correctly.

User #1

Attribute set: Marketing


Attribute: EmployeeId
Attribute data type: String
Attribute value: "KX19476"

User #2

Attribute set: Marketing


Attribute: EmployeeId
Attribute data type: String
Attribute value: "GS46982"
Request

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"
}
}
}
]
}

Example 4: List all users with a custom security attribute


assignment that does not equal a value
The following example shows how to use the List users API to list all users with a custom
security attribute assignment that does not equal a value. The example retrieves users
with a custom security attribute named AppCountry with a value that does not equal
Canada . The filter value is case sensitive. You must add ConsistencyLevel=eventual in the
request or the header. You must also include $count=true to ensure the request is
routed correctly.

User #1

Attribute set: Marketing


Attribute: AppCountry
Attribute data type: Collection of Strings
Attribute value: ["France"]

All other users

AppCountry attribute not added

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
}
]
}

Remove custom security attribute assignments

Example 1: Remove a single-valued custom security


attribute assignment from a user
The following example shows how to use the Update user API to remove a custom
security attribute assignment that supports a single value from a user.

Attribute set: Engineering


Attribute: ProjectDate
Attribute value: 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

Example 2: Remove a multi-valued custom security


attribute assignment from a user
The following example shows how to use the Update user API to remove a custom
security attribute assignment that supports multiple values from a user.

Attribute set: Engineering


Attribute: Project
Attribute value: []

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

HTTP/1.1 204 No Content

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

Microsoft Graph PIM API enables organizations to manage privileged access to


resources in Azure Active Directory (Azure AD). It also helps to manage the risks of
privileged access by limiting when access is active, managing the scope of access, and
providing an auditable log of privileged access.

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:

Removing existing or adding more group members also removes administrators.


Adding more roles to the group members instead of assigning roles to individual
users.

Assigning eligibility instead of a persistently active User Administrator privilege allows


the company to enforce just-in-time access, which grants temporary permissions to
carry out the privileged tasks. After defining the role eligibility, the eligible group
member then activates their assignment for a temporary period. All records of role
activations will be auditable by the company.

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).

Step 1: Create a test user


Create a user who must reset their password at first sign in. From this step, record the
value of the new user's id for use in the next step. After creating the user, visit the Azure
portal and enable multifactor authentication (MFA) for the user. For more information
about enabling MFA, see the See also section.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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]"
}

Step 2: Create a security group that can be


assigned an Azure AD role
Create a group that’s assignable to an Azure AD role. Assign yourself as the group
owner and both you and Aline (the user created in Step 1) as members.

Request: Create a role-assignable group


Replace 1ed8ac56-4827-4733-8f80-86adc2e67db5 with your ID and 7146daa8-1b4b-4a66-
b2f7-cf593d03c8d2 with the value of Aline's ID.

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:

Create a unifiedRoleEligibilityScheduleRequest object that identifies the group IT


Helpdesk (User) as eligible for the User Administrator role for one year. Azure AD
extends this eligible assignment to the group members, that is, you and Aline.
Scope the eligible assignment to your entire tenant. This allows the user admin to
use their privilege against all users in your tenant, except higher privileged users
such as the Global Administrator.

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": {}
}

Step 4: Confirm the user's current role


assignments
While the group members are now eligible for the User Administrator role, they're still
unable to use the role. This is because they're yet to activate their eligibility. You can
confirm by checking the user's current role assignments.

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.

Step 5: User self-activates their eligible


assignment
An incident ticket CONTOSO: Security-012345 has been raised in Contoso's incident
management system and the company requires that all employee's refresh tokens be
invalidated. As a member of IT Helpdesk, Aline is responsible for fulfilling this task.

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.

For principalId, supply the value of your (Aline's) id.


The roleDefinitionId is the id of the role you're eligible for, in this case, the User
Administrator role.
Enter the details of the ticket system that provides an auditable justification for
activating the request.

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"
}
}

You may confirm your assignment by running GET


https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignmentScheduleReq

uests/filterByCurrentUser(on='principal') . The response object returns your newly


activated role assignment with its status set to Granted . With your new privilege, carry
out any allowed actions within five hours your assignment is active for. This includes
invalidating all employees' refresh tokens. After five hours, the active assignment expires
but through your membership in the IT Support (Users) group, you still remain eligible
for the User Administrator role.

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.

Step 6: Clean up resources


Sign in as the Global Administrator and delete the following resources that you created
for this tutorial: the role eligibility request, IT Support (Users) group, and the test user
(Aline Dupuy).

Revoke the role eligibility request

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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

HTTP/1.1 204 No Content

Delete the test user

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

HTTP/1.1 204 No Content


See also
Tutorial: Assign Azure AD roles in Privileged Identity Management using Microsoft
Graph PowerShell
Overview of role management through PIM
Manage users' authentication methods
using Microsoft Graph
Article • 01/27/2023

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.

In this tutorial, you'll learn how to:

" Authenticate to Azure AD with the right roles and permissions


" Check the user's authentication methods
" Add new phone numbers for the user
" Remove a phone number from the user
" Reset the user's password

Step 1: Authenticate to Azure AD with the right


roles and permissions
Using your favorite tool for interacting with Microsoft Graph, sign in using an account
with one of these roles:

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.

Step 2: Check the user's authentication


methods
Make a call to see the user's authentication methods. Take the URL to see a user's profile
and add /authentication/methods :

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
}
]
}

Step 3: Add new phone numbers for the user


From the previous step, a new user (Avery) only has a password registered. To assign a
new phone number for Avery to use, make a POST request with the phone type and
number in the body. To tell the system that a phone number is being added, you'll also
need to change the end of the URL from methods to phoneMethods .

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"
}
]
}

Confirm that you can see both numbers as expected.

Step 4: Remove a phone number from the user


In this scenario, Avery is now working from home you need to remove their office
number from their account. You need to call DELETE on the office phone URL, which you
can create by appending the office phone's ID to the phone methods URL. Look at
Avery's list of phones above: the office phone ID starts with "e37f".

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.

Step 5: Reset the user's password


In this scenario, Avery has forgotten their password and you need to reset it for them. To
reset, you'll make a POST to their password's URL (see the ID starting with "28c1" above
in Avery's list of authentication methods), specifying the "resetPassword" action. Provide
the new password in the request body.

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?

See Azure AD authentication methods API overview

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 ,

Policy.ReadWrite.ConditionalAccess , and User.ReadWrite.All .

Step 1: Create a user account


For this tutorial, you create a user account that is used to test risk detections. In the
request body, change contoso.com to the domain name of your tenant. You can find
tenant information on the Azure Active Directory overview page.

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]"
}

Step 2: Trigger a risk detection


Trigger a risk detection
One way to trigger a risk detection on a user account is to sign in to the Azure portal
anonymously. In this tutorial, the Tor browser is used to sign in anonymously.

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.

List risk detections


When you signed in to the Azure portal using the anonymous browser, an
anonymizedIPAddress risk event was detected. You can use the $filter query parameter

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

It may take a few minutes for the event to be returned.

Step 3: Create a conditional access policy


You can leverage conditional access policies in your organization to allow users to self-
remediate when risk is detected. Self-remediation enables your users to unblock
themselves to access their resources securely after completing the policy prompt. In this
step, you create a conditional access policy that requires the user to sign in using MFA if
a medium or high risk detection occurs.

Set up multi-factor authentication


When setting up an account for MFA, you can choose from several methods for
authenticating the user. Choose the best method for your situation to complete this
tutorial.

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.

Sign in and complete multi-factor authentication


By signing in to the anonymous browser, a risk is detected, but it is remediated by
completing MFA.

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.

List risk detections


Because MFA was completed. Now, when you list risk detections the riskState shows the
event as remediated .

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
}
}
}

Step 4: Block the user from signing in


(optional)
Instead of providing the opportunity for the user to self-remediate, you can block the
user from signing in. In this step, you create a new conditional access policy that blocks
the user from signing in if a medium or high risk detection occurs. The difference in
policies is that the builtInControls is set to block .

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 .

Step 5: Dismiss risky users


If you believe the user is not at risk, and you don’t want to enforce a conditional access
policy, you can manually dismiss the risky user.
Dismiss the risky user

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

HTTP/1.1 204 No Content

List risky users


After dismissing the risk user, you can see in the response when listing risky users that
the MyTestUser1 user account now has a risk level of none and a riskState of dismissed .

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]"
}
]
}

Step 6: Clean up resources


In this step, you remove the resources that you created.

Delete the user account


Delete the MyTestUser1 user account.

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.

What is Identity Protection?


What is Conditional Access?
How it works: Azure Multi-Factor Authentication
Simulating risk detections in Identity Protection
conditionalAccessPolicy
riskDetection
riskyUser
user
Configure the arguments for built-in
Lifecycle Workflow tasks
Article • 05/16/2023

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.

Configure arguments for tasks


Task taskDefinitionId arguments
description

Send 70b29d51-b59a- name: cc


welcome 4773-9280- value: A valid user ID (String) for the user you want to cc in the
email to 8841dfd3f2ea email.
new hire
name: customSubject
value: A custom subject header 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.
Task taskDefinitionId arguments
description

Generate 1b555e50-7f65- name: tapLifetimeMinutes


Temporary 41d5-b514- value: 10 upto 43000
Access Pass 5894a026d10d
and send name: tapIsUsableOnce
via email to value: true or false
user's
manager Prerequisites:

1. The user must be assigned a manager.


2. The user's manager must have their mail enabled.
3. The temporary access pass (TAP) policy must be enabled
in the tenant and the user enabled to use the TAP
authentication method. For more information, see
temporaryAccessPassAuthenticationMethodConfiguration
resource type.

Add user to 22085229-5809- name: groupID


groups 45e8-97fd- value: a valid group ID or a comma-separated list of groups to
270d28d66910 which the user will be added as a member. For example,
"06269010-2d8e-48e4-8f0e-33580720c9e1, 06bba22c-775e-42d8-
b451-4221af061af0, 182f68db-6513-4e79-9ec2-a7e89a460e7f"

Add user to e440ed8d-25a1- name: teamID


teams 4618-84ce- value: a valid group ID or a comma-separated list of teams to
091ed5be5594 which the user will be added as a member. For example,
"06269010-2d8e-48e4-8f0e-33580720c9e1, 06bba22c-775e-42d8-
b451-4221af061af0, 182f68db-6513-4e79-9ec2-a7e89a460e7f"

Enable user 6fc52c9d-398b- None


account 4305-9763-
15f42c1676fc

Run a 4262b724-8dba- name: CustomTaskExtensionID


custom task 4fad-afc3- value: The ID of the custom task extension
extension 43fcbb497a0e

Disable user 1dfdfcc7-52fa- None


account 4c2e-bf3a-
e3919cc12950

Remove 1953a66c-751c- name: groupID


user from 45e5-8bfe- value: a valid group ID or a comma-separated list of groups
selected 01462c70da3c that the user is a member of. For example, "06269010-2d8e-
group 48e4-8f0e-33580720c9e1, 06bba22c-775e-42d8-b451-
4221af061af0, 182f68db-6513-4e79-9ec2-a7e89a460e7f"
Task taskDefinitionId arguments
description

Remove b3a31406-2a15- None


users from 4c9a-b25b-
all groups a658fa5f07fc

Remove 06aa7acb-01af- name: teamID


user from 4824-8899- value: a comma-separated list of teams that the user is a
teams b14e5ed788d6 member of. For example, "06269010-2d8e-48e4-8f0e-
33580720c9e1, 06bba22c-775e-42d8-b451-4221af061af0,
182f68db-6513-4e79-9ec2-a7e89a460e7f"

Remove 81f7b200-2816- None


user from 4b3b-8c5d-
all teams dc556f07b024

Remove all 8fa97d28-3e52- None


license 4985-b3a9-
assignments a1126f9b8b4e
from user

Delete user 8d18588d-9ad3- None


4c0f-99d0-
ec215f0e3dff

Send email 52853a3e-f4e5- name: cc


to manager 4eb8-bb24- value: A valid user ID (String) for the user you want to cc in the
before user 1ac09a1da935 email.
last day
name: customSubject
value: A custom subject header 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.
Task taskDefinitionId arguments
description

Send email 9c0a1eaf-5bda- name: cc


on users last 4392-9d9e- value: A valid user ID (String) for the user you want to cc in the
day 6e155bb57411 email.

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.

Send 6f22ddd4-b3a5- name: cc


offboarding 47a4-a846- value: A valid user ID (String) for the user you want to cc in the
email to 0d7c201a49ce email.
users
manager name: customSubject
after their value: A custom subject header for the email being sent.
last day

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

Example 1: Configure a task to send the offboarding email


to a user's manager after the user's last day of work
The following examples shows a task configuration to send the offboarding email to a
user's manager after the user's last day of work. This task is identified by
taskDefinitionId 6f22ddd4-b3a5-47a4-a846-0d7c201a49ce .

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": []
}

Example 2: Configure a task to add a user to teams


The following examples shows a task configuration to add a user to a Teams team. This
task is identified by taskDefinitionId e440ed8d-25a1-4618-84ce-091ed5be5594 .

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.

Grant yourself the following LifecycleWorkflows.ReadWrite.All delegated


permission.

You must have two user accounts to use for this tutorial, one for the new hire and
another for their manager.

User property Description Set on

mail Used to notify manager of the new employee's Employee,


temporary access pass (TAP). Both the manager and Manager
employee should have active mailboxes to receive emails.
User property Description Set on

manager This attribute that is used by the lifecycle workflow. Employee

employeeHireDate Used to trigger the workflow. Set to today's date. Employee

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.

Create a "joiner" workflow

Request
The following request creates a pre-hire workflow with the following settings:

It can be run on-demand but not on schedule.


The workflow runs two days before the employee's employeeHireDate, and if they
are in the "Sales" department.
Only one task runs in this workflow: to generate the TAP and send it to the new
hire's manager.

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

HTTP/1.1 201 Created


Content-Type: application/json

{
"@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
}
}
}

Run the workflow

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

HTTP/1.1 204 No Content

Check tasks and workflow status


At any time, you can monitor the status of the workflows and the tasks at three levels.

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"
}
]
}
}
]
}

[Optional] Schedule the workflow to run


automatically
After running your workflow on-demand and checking that everything is working fine,
you may want to enable the workflow so that it can run automatically on a tenant-
defined schedule. To enable the workflow schedule, you may run the following request.

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

HTTP/1.1 204 No Content

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:

1. Remove all licenses for user


2. Remove user from all Teams
3. Delete user account

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.

Create a "leaver" workflow

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

HTTP/1.1 201 Created


Content-Type: application/json

{
"@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
}
}
}

Run the workflow

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

HTTP/1.1 204 No Content

Check tasks and workflow status


At any time, you can monitor the status of the workflows and the tasks at three levels.

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": []
}
}
]
}

[Optional] Schedule the workflow to run


automatically
After running your workflow on-demand and checking that everything is working fine,
you may want to enable the workflow so that it can run automatically on a tenant-
defined schedule. To enable the workflow schedule, you may run the following request.
HTTP

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

HTTP/1.1 204 No Content

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 tutorial provides step-by-step guidance for completing a real-time employee


termination with Lifecycle Workflows using Microsoft Graph.

This post off-boarding scenario will run a workflow on-demand and accomplish the
following tasks:

1. Remove all licenses for user


2. Remove user from all Teams
3. Delete user account

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.

Create a "leaver" workflow

Request
The following request creates an offboarding workflow with the following settings:

It can be run on-demand but not on schedule.


The workflow doesn't include execution conditions. Execution conditions, even
when defined, are bypassed for workflows that are run on-demand.
Three workflow tasks are enabled to run in sequence: the user is removed from all
groups, 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": "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

HTTP/1.1 201 Created


Content-Type: application/json

{
"@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"
}
}

Run the workflow

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

HTTP/1.1 204 No Content

Check tasks and workflow status


At any time, you can monitor the status of the workflows and the tasks at three levels.

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.

Permission type Permissions (from least to most privileged)

Delegated (work or school account) User.Read.All and User-LifeCycleInfo.ReadWrite.All

Delegated (personal Microsoft account) Not supported.

Application User.Read.All and User-LifeCycleInfo.ReadWrite.All

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:

Azure AD entitlement management requires specific licenses. For more


information, see License requirements. The following licenses are required in your
tenant:
Azure AD Premium P2
Enterprise Mobility + Security (EMS) E5 license
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: User.ReadWrite.All ,
Group.ReadWrite.All , and EntitlementManagement.ReadWrite.All .
Step 1: Create a user account and a group
In this step, you create a group named Marketing resources in the directory that is the
target resource for entitlement management. You also create a user account that is set
up as an internal requestor.

Create a user account


For this tutorial, you create a user account that is used to request access to the
resources in the access package. When you make these calls, change
contoso.onmicrosoft.com to the domain name of your tenant. You can find tenant

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"
}

Step 2: Add resources to a catalog and create


an access package
An access package is a bundle of resources that a team or project needs and is governed
with policies. Access packages are defined in containers called catalogs. Catalogs can
reference resources, such as groups, apps and sites, that are used in the access package.
In this step, you create a Marketing Campaign access package in the General catalog. If
you have a different catalog, use its name in the next section.

Get the catalog identifier


To add resources to the catalog, you must first get the identifier of it. If you are using
the General catalog, run the following request to get its identifier. If you are using a
different calalog, change the filter value in the request to the name of your catalog.
Record the value of the id property that is returned to use later in this tutorial.

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.

Add the group to the catalog


To add the group that you created to the catalog, provide the following property values:

catalogId - the id of the catalog that you are using


displayName - the name of the group
description - the description of the group
originId - the id of the group that you created

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": ""
}

Get catalog resources


In later steps in this tutorial, you need the id that was assigned to the group resource in
the catalog. This identifier, which represents the group as a resource in the catalog, is
different than the identifier of the group itself in Microsoft Graph. This is because a
catalog can have resources which aren't represented in Microsoft Graph.
In the request, provide the id of the catalog that you are using. Record the value of the
id property for the group catalog resource.

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"
}
]
}

Get resources roles


The access package assigns users to the roles of a resource. The typical role of a group
is the member role. Other resources, such as SharePoint Online sites and applications,
might have many roles. The typical role of a group used in an access package is the
member role. You'll need the member role when you add a resource role to the access
package later in this tutorial.

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.

Create the access package


At this point, you have a catalog with a group resource, and you know that you'll use the
resource role of group member in the access package. The next step is to create the
access package. After you have the access package, you can add the resource role to it,
and create a policy for how users can request access to that resource role. You use the id
of the catalog that you recorded earlier to create the access package. Record the id of
the access package to use later in this tutorial.

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"
}

Add a resource role to the access package


Add the Member role of the group resource to the access package. In the request,
provide the id of the access package. In the request body provide the id of the group
catalog resource for accessPackageResource, and provide the originId of the Member
role that you previously recorded.

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.

Create an access package policy


Now that you created the access package and added resources and roles, you can
decide who can access it by creating an access package policy. In this tutorial, you
enable the Requestor1 account that you created to request access to the resources in
the access package. For this task, you need these values:

id of the access package for the value of the accessPackageId property


id of the Requestor1 user account for the value of the id property in
allowedRequestors

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": []
}
}

Step 3: Request access


In this step, the Requestor1 user account requests access to the resources in the access
package.

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
}

Step 4: Validate that access has been assigned


In this step, you confirm that the Requestor1 user account was assigned the access
package and that they are now a member of the Marketing resources group.

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
}

Get access package assignments


You can also use the id of the access package policy that you created to see that
resources have been assigned to the Requestor1 user account.

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"
}
]
}
]
}

Get the members of the group


After the request has been granted, you can use the id that you recorded for the
Marketing resources group to see that the Requestor1 user account has been added to
it.

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.

Remove an access package assignment


You must remove any assignments to the access package before you can delete it. Use
the id of the assignment request that you previously recorded to delete it.

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
}

Delete the access package assignment policy


Use the id of the assignment policy that you previously recorded to delete it. Make sure
all assignments are removed first.

Request

HTTP

HTTP

DELETE
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackageAssignmentPolicies/6c1f65ec-8c25-4a45-83c2-a1de2a6d0e9f

Response

HTTP

No Content - 204

Delete the access package


Use the id of the access package that you previously recorded to delete it.

Request

HTTP

HTTP

DELETE
https://graph.microsoft.com/beta/identityGovernance/entitlementManagemen
t/accessPackages/cf54c6ca-d717-49bc-babe-d140d035dfdd
Response

HTTP

No Content - 204

Delete the user account


Delete the Requestor1 user account.

Request

HTTP

HTTP

DELETE https://graph.microsoft.com/v1.0/users/ce02eca8-752b-4ecf-ac29-
aa9bccd87606

Response

HTTP

No Content - 204

Delete the group


Delete the Marketing resources group.

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:

Working with the Azure AD entitlement management API


accessPackageCatalog
accessPackageResourceRequest
accessPackage
accessPackageResourceRoleScope
accessPackageAssignmentPolicy
accessPackageAssignmentRequest
group
user
Overview of the access reviews API
Article • 01/27/2023

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.

Participants in an access review


Access reviews are about attesting or recertifying a principal's continued access to a
resource. Principals can be individual users, groups, or applications.

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.

Building blocks of the access review API


The access reviews API is structured logically and is composed of the following building
blocks.

1. Access reviews schedule definition


This is the logical blueprint that contains the settings of an access review and its
instances. These settings include:

The resources being accessed.


The principals that access the resource.
The reviewers who attest to the need for the principals to maintain access to
resources.
The frequency of the access review.
The stages of the access review (for a multi-stage access review) and the whether
decisions from preceding stage can be provided to reviewers in subsequent stages.
Default decisions to apply if decisions aren't recorded.
Whether to apply recommendations for decisions that are based on various
insights (preview).

2. Access review instance


Represents a single review activity, or occurrence, against which reviewers make
decisions. An access review definition may have multiple instances as is the case in
recurring reviews. One-off reviews have exactly one instance. For a multi-stage access
review, each instance contains up to three stages.

3. Decision item recorded for a review


Represents a decision that a reviewer made on an instance, including the time stamp
and justification for the decision. Each review instance has as many decisions as the
number of principals under review. If there are no decisions taken, that is, reviewers
haven't responded to the review, there will be no decision objects for the instance.

System-generated recommended decisions can be provided for each decision item.


These are based on the last sign in date of the principal whose access is under review.
This feature gives reviewers visibility into dormant accounts in the organization, and
recommends the decisions to apply about the principal's continued access.

Access reviews also support auditing the decisions that were made on each access
review instance, with the decisions also downloadable for offline auditing.

Scope of calling the access reviews API


The access reviews API supports both delegated and application contexts.

In a delegated (user) context, an application calls the access reviews API on behalf of a
user. Typical scenarios include:

An administrator uses a script to create, read, or update an access review.


A resource owner uses an app or a script to create an access review for a resource
they own.
An administrator automatically collects all decisions for one or more access
reviews.

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:

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 or Identity Governance
Administrator role.
[Optional] Open a new incognito, anonymous, or InPrivate browser window.
You'll sign in later in this tutorial.
Grant yourself the following delegated permissions: AccessReview.ReadWrite.All ,
Group.ReadWrite.All .
7 Note

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.

Step 1: Create test users in your tenant


Create three new test users by running the request below three times, changing the
values of the displayName, mailNickname, and userPrincipalName properties each
time. Record the IDs of the three new test users.

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]"
}

Step 2: Create a security group, assign owners,


and add members
Create a security group named Building security that is the target of the access reviews
in this tutorial. Assign to this group one group owner and two members.

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.

In this call, replace:

d3bcdff4-4f80-4418-a65e-7bf3778c5dca with the ID of your group owner.


3b8ceebc-49e6-4e0c-9e14-c906374a7ef6 and bf59c5ba-5304-4c9b-9192-e5a4cb8444e7

with the IDs of the two 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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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.

Step 3: Create an access review for the security


group

Request
In this call, replace the following values:

eb75ccd2-59ef-48b7-8f76-cc3f33f899f4 with the ID of the Building security group.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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.

Step 4: List instances of the access review


Once the status of the access review is marked as InProgress , run the following query
to list all instances of the access review definition. Because you created a one-time
access review in Step 3, the request returns only one instance with an ID like the
schedule definition's ID.

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": []
}
]
}

Step 5: Who was contacted for the review?


You can confirm that all members of the Building security group were contacted to post
their review decisions for this instance of the access review.
Request
In this call, replace 2d56c364-0695-4ec6-8b92-4c1db7c80f1b with the ID of your access
review schedule definition.

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.

Step 7: Self-review a pending access decision


In Step 3, you configured the access review as self-reviewing. This configuration requires
that both members of the Building security group self-attest to their need to maintain
their access to the group.

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

List your access reviews decision items


In this call, replace 2d56c364-0695-4ec6-8b92-4c1db7c80f1b with the ID of your access
review schedule definition.

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

In this call, replace 2d56c364-0695-4ec6-8b92-4c1db7c80f1b with the ID of your access


review schedule definition and c7de8fba-4d6a-4fab-a659-62ff0c02643d with the ID of the
pending decision item returned in the previous step.

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

HTTP/1.1 204 No Content

Verify the decisions


To verify the decisions you've recorded for your access review, list your access review
decision items. While the access review period hasn't expired nor the decisions applies,
the applyResult will be marked as New and you're allowed to change the decision.

You can now sign out and exit the incognito browser session.

Method 2: Use the My Access portal


Reviewers can also visit the My Access portal portal to check their pending access
review instances.

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.

Congratulations! You've created an access review and self-attested to your need to


maintain access. You only self-attested once, and will maintain access until it's removed
through either a Deny decision of another access review instance, or through another
internal process.

Step 9: Clean up resources


Delete the resources that you created for this tutorial—the Building security group, the
access review schedule definition, and the three test users.

Delete the security group

Request

In this call, replace eb75ccd2-59ef-48b7-8f76-cc3f33f899f4 with the id of Building


security.

HTTP

HTTP

DELETE https://graph.microsoft.com/beta/groups/eb75ccd2-59ef-48b7-8f76-
cc3f33f899f4

Response

HTTP
HTTP/1.1 204 No Content

Delete the access review definition


In this call, replace 2d56c364-0695-4ec6-8b92-4c1db7c80f1b with the ID of your access
review definition. Because the access review schedule definition is the blueprint for the
access review, deleting the definition will remove the settings, instances, and decisions.

Request

HTTP

HTTP

DELETE
https://graph.microsoft.com/beta/identityGovernance/accessReviews/defini
tions/2d56c364-0695-4ec6-8b92-4c1db7c80f1b

Response

HTTP

HTTP/1.1 204 No Content

Delete the three test users


In this call, replace 3b8ceebc-49e6-4e0c-9e14-c906374a7ef6 with the ID of one of your
test users. Repeat this step twice with the IDs of the other two users to delete them.

Request

HTTP

HTTP

DELETE https://graph.microsoft.com/beta/users/3b8ceebc-49e6-4e0c-9e14-
c906374a7ef6
Response

HTTP

HTTP/1.1 204 No Content

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:

A working Azure AD tenant with an Azure AD Premium P2 or EMS E5 license


enabled.
An account in a different Azure AD tenant or a social identity that you can invite as
a guest user (B2B user).
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: User.Invite.All ,
AccessReview.ReadWrite.All , Group.ReadWrite.All , User.ReadWrite.All .

Step 1: Create a test user in your tenant


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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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"
}

Step 2: Invite a guest user into your tenant


Invite a guest user with the email address [email protected] to your tenant.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#invitations/$entity",
"invitedUser": {
"id": "baf1b0a0-1f9a-4a56-9884-6a30824f8d20"
}
}

Step 3: Create a new Microsoft 365 group and


add the guest user
In this step:

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:

cdb555e3-b33e-4fd5-a427-17fadacbdfa7 with your ID. To retrieve your ID, run GET


on https://graph.microsoft.com/v1.0/me .
baf1b0a0-1f9a-4a56-9884-6a30824f8d20 with [email protected]'s ID from the

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
"id": "59ab642a-2776-4e32-9b68-9ff7a47b7f6a",
"displayName": "Feelgood Marketing Campaign",
"groupTypes": [
"Unified"
]
}

You now have a Microsoft 365 group with a guest user.


Step 4: Create an access review for all Microsoft
365 groups with guest users
When you create a recurring access review series for all Microsoft 365 groups with guest
users, you schedule a periodic review of the guests' access to the Microsoft 365 group.
In this case, the Feel good Marketing Campaign group.

The access review series uses following settings:

It's a recurring access review and reviewed quarterly.


The group owners decide whether guest users should maintain their access.
The review scope is limited to only Microsoft 365 groups with guest users.
A backup reviewer. They can be a fallback user or a group that can review the
access in case the group doesn't have any owners assigned.
autoApplyDecisionsEnabled is set to true . In this case, decisions are applied
automatically once the reviewer completes the access review or the access review
duration ends. If not enabled, a user must apply the decisions manually after the
review completes.
Apply the removeAccessApplyAction action to denied guest users to remove
them from the group. The guest user can still sign in to your tenant, but won't
access the group.

Request
In this call, replace the following values:

c9a5aff7-9298-4d71-adab-0a222e0a05e4 with the ID of Aline who you're designating

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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"
}
]
}
}

Step 5: List instances of the access review


The following query lists all instances of the access review definition. If there are more
than one Microsoft 365 groups with guest users in your tenant, this request will return
one instance for every Microsoft 365 group with guest users.

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

has a guest user.

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.

Step 6: Get decisions


Get the decisions taken for the instance of an access review.

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:

Every three months a new review instance will be created.


Reviewers will be required to apply new decisions for new instances.

Step 7: Clean up resources


Delete the resources that you created for this tutorial—Feel good marketing campaign
group, the access review schedule definition, the guest user, and the test user.

Delete the Microsoft 365 group

Request

In this call, replace 59ab642a-2776-4e32-9b68-9ff7a47b7f6a with the ID of your Feel good


marketing campaign Microsoft 365 group.

HTTP

HTTP

DELETE https://graph.microsoft.com/v1.0/groups/59ab642a-2776-4e32-9b68-
9ff7a47b7f6a

Response
HTTP

HTTP/1.1 204 No Content


Content-type: text/plain

Delete the access review definition


In this call, replace c22ae540-b89a-4d24-bac0-4ef35e6591ea with the ID of your access
review definition. Since the access review schedule definition is the blueprint for the
access review, deleting the definition will remove the related settings, instances, and
decisions.

Request

HTTP

HTTP

DELETE
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/c22ae540-b89a-4d24-bac0-4ef35e6591ea

Response

HTTP

HTTP/1.1 204 No Content


Content-type: text/plain

Remove the guest user


In this call, replace baf1b0a0-1f9a-4a56-9884-6a30824f8d20 with the ID of the guest user,
[email protected].

Request

HTTP

HTTP
DELETE https://graph.microsoft.com/v1.0/users/baf1b0a0-1f9a-4a56-9884-
6a30824f8d20

Response

HTTP

HTTP/1.1 204 No Content


Content-type: text/plain

Delete the test user


In this call, replace c9a5aff7-9298-4d71-adab-0a222e0a05e4 with the ID of your test user.

Request

HTTP

HTTP

DELETE https://graph.microsoft.com/v1.0/users/c9a5aff7-9298-4d71-adab-
0a222e0a05e4

Response

HTTP

HTTP/1.1 204 No Content


Content-type: text/plain

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:

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 Privileged Role Administrator role.
Principals with active or eligible assignments to a privileged role. These
assignments will be the scope of your access review. To assign privileged roles, see
Tutorial: Use the Privileged Identity Management (PIM) API to assign Azure AD
roles.
In this tutorial, the User Administrator role is the resource in review. A security
group and an individual user have been assigned the role.
Grant yourself the following delegated permission: AccessReview.ReadWrite.All .
7 Note

The response objects shown in this tutorial might be shortened for readability.

Step 1: Create an access review of privileged


role assignments
In this tutorial, we create a recurring access review of both active and eligible
assignments to the User Administrator role. An accessReviewScheduleDefinition can be
used to define the access review of multiple principal types (users and groups, or service
principals) to only one privileged role. To review access to multiple privileged roles,
create separate accessReviewScheduleDefinition objects.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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.

Step 3: Retrieve access review decisions before


recording any decisions
Before you can post decisions, let us first inspect the items waiting for your decision.

Request
In the following request, replace the following values:

57457d7c-af59-470c-ae71-aa72c657fe0f with the value of the access review that you

created in Step 1.
ad0dd148-5d16-4cfd-86e9-ab502f819aaf with the value of the access review instance

you'd like to retrieve decisions for.

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.

Step 4: Record decisions


You'll now record decisions for the access review.

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.

In the following requests, replace the following values:

57457d7c-af59-470c-ae71-aa72c657fe0f with the value of the access review that you


created in Step 1
ad0dd148-5d16-4cfd-86e9-ab502f819aaf with the value of the access review instance
you'd like to retrieve decisions for
4d79fbf6-36e6-430b-ba0a-2a727a480303 with the value of the access review instance

scoped to Aline's access


62fd1c5b-04b8-4703-9fd7-dce6232c3775 with the value of the access review instance

scoped to the IT Helpdesk group's access


Approve the security group's role assignment

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

HTTP/1.1 204 No Content

Deny the individual user their role assignment

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

HTTP/1.1 204 No Content

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 .

The reviewedBy object contains your details as the reviewer.


The applyResult is New meaning the decisions haven't been applied.

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

HTTP/1.1 204 No Content

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.

Define the scope of the access review history data


In the following request, an empty decisions object means all decisions related to the
scope of the access review will be included in the 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
}
]
}

Retrieve the instances of the access review history

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
}
]
}

Generate a link to download the history report from the


instance of the access review history

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.

Step 7: Clean up resources


Delete the accessReviewScheduleDefinition object that you created for this tutorial.
Because the access review schedule definition is the blueprint for the access review,
deleting the definition will remove the settings, instances, decisions.

Request

HTTP

HTTP

DELETE
https://graph.microsoft.com/v1.0/identityGovernance/accessReviews/defini
tions/57457d7c-af59-470c-ae71-aa72c657fe0f

Response
HTTP

HTTP/1.1 204 No Content

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.

The resources to review are configured in the scope property of the


accessReviewScheduleDefinition resource. This property is of the type
accessReviewScope, an abstract type that the following API resources that can be used
to configure the access review scope inherit from.

Resource Description Example scenarios

accessReviewQueryScope Inherits from Membership of


accessReviewScope. Best users assigned
applicable when reviewing the to a group,
full set or subset of principals either direct
who have access to a resource members or
or group of related resources. direct and
transitive
members.
Guest user
access to one
group.
Guest user
access to all
Microsoft 365
groups in a
tenant.
Service
principals
assigned to
privileged roles.
User and service
principal access
to Entitlement
Management
access
packages.
Resource Description Example scenarios

accessReviewInactiveUsersQueryScope Inherits from Group


accessReviewQueryScope. membership of
Used when only inactive users only inactive
are reviewed. Their inactive users.
status is specified by the
inactiveDuration property.

principalResourceMembershipsScope Inherits from Reviewing


accessReviewScope. Best access of three
applicable to review principals' specific
access to resources where you principals
configure unique pools of across one
principals and resources. Microsoft 365
group and one
privileged Azure
AD role.

In this article, you'll learn how to scope your access review using these three derived
resource types.

Use accessReviewQueryScope and


accessReviewInactiveUsersQueryScope to
configure scope
To configure the scope by using the accessReviewQueryScope type, set the values of its
query, queryRoot, and queryType properties. For descriptions of these properties, see
accessReviewQueryScope resource type.

accessReviewInactiveUsersQueryScope requires all the properties of


accessReviewQueryScope and includes an inactiveDuration property.

Example 1: Review all users assigned to a group


The following example scopes the review to both direct and transitive members of the
group who are users. The transitive members are members of the nested groups.

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.

To review only inactive users assigned to the group:

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.

Example 2: Review all guest users assigned to a group


The following example scopes the review to both direct and transitive members of the
group who are guest users. The transitive members are members of the nested groups.

HTTP

"scope": {
"@odata.type": "#microsoft.graph.accessReviewQueryScope",
"query": "/groups/{groupId}/transitiveMembers/?$filter=(userType eq
'Guest')",
"queryType": "MicrosoftGraph"
}

Example 3: Review all users and groups assigned to a


group
The following example scopes the review to only direct members of the group who are
either users or other groups. In this scope:

The direct users are included in the review.


The direct groups are included in the review.
The transitive members of the groups, that is, members of nested groups, aren't
included in the review.

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.

Example 4: Review all users assigned to all Microsoft 365


groups
The following example creates a review of all Microsoft 365 groups in the tenant. The
review is scoped to only direct members of the group.

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.

Example 5: Review all guest users assigned to all


Microsoft 365 groups
The following example scopes the review to direct members of all Microsoft 365 groups
who are guest users.

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"
}

Additionally, because this review is applied on inactive users, use the


accessReviewInactiveUsersQueryScope resource and specify the @odata.type type
property with the value #microsoft.graph.accessReviewInactiveUsersQueryScope .
Dynamic groups and role-assignable groups aren't included in this review.

Example 6: Review all guest users assigned to all teams


The following example scopes the review to direct members of all teams who are 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.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.

Review all inactive guest users assigned to all Teams

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"
}

Additionally, because this review is applied on all teams, configure the


instanceEnumerationScope property to specify all teams. 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.

Example 7: Review all assignment to Entitlement


Management access packages
HTTP

"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"
}

Example 8: Review all service principals assigned to a


privileged role
HTTP

"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"
}

Example 9: Review all users assigned to a privileged role

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"
}

Review all users with eligible assignment to a privileged role

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"
}

Review all users with active assignment to a privileged role

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.

Example 10: Review all inactive guest users assigned to all


groups
The following example scopes the review to direct members of all groups who are
inactive guest users. The guest users are considered inactive users when the period of
their inactivity is 30 days from the start date of the access review instance.
HTTP

"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"
}
]
}

Example 11: Review all users assigned to a team, including


B2B direct connect users in a team with shared channels
In this example, the access review scope is all users who are members of a team, or
assigned to a shared channel within the team. These members include internal users,
direct and transitive users, B2B collaboration users, and B2B direct connect users.

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.

Example 12: Review all guest users assigned to a directory


role
HTTP

"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": []

To configure a self-review, do not specify the reviewers property, or supply an empty


object to the property.

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.

Example 2: A specific user as the reviewer


HTTP
"reviewers": [
{
"query": "/users/{userId}",
"queryType": "MicrosoftGraph"
}
]

Example 3: Members of a group as reviewers


HTTP

"reviewers": [
{
"query": "/groups/{groupId}/transitiveMembers",
"queryType": "MicrosoftGraph"
}
]

Example 4: Group owners as reviewers


When the access review is scoped to a group, for example, Example 1: Review all users
assigned to a group, Example 2: Review all guest users assigned to a group, and
Example 3: Review all users and groups assigned to a group.

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"
}
]

Example 5: People managers as reviewers


HTTP

"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.

Example 6: Application owners as reviewers


HTTP

"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.

Role management policies


In Microsoft Graph, the Azure AD role settings are called rules. These rules are grouped
in and assigned to Azure AD roles through containers called policies. Each policy is read-
only.

The policies are defined through the unifiedRoleManagementPolicy resource type.

Role management policy rules


While each policy is read-only, it contains 17 pre-defined rules that can be updated.
These rules are managed through the rules relationship of the
unifiedRoleManagementPolicy resource type.

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.

Mapping of rule IDs to Azure portal settings


Activation rules
The following image shows the activation role settings on the Azure portal, mapped to
rules and resource types in the PIM API in Microsoft Graph.

Number Azure portal Microsoft Graph Rule ID / Derived resource type Enforced
UX for caller
Description

1 Activation Expiration_EndUser_Assignment / End user


maximum unifiedRoleManagementPolicyExpirationRule
duration
(hours)
Number Azure portal Microsoft Graph Rule ID / Derived resource type Enforced
UX for caller
Description

2 On activation, Enablement_Admin_Eligibility / Admin


require: None, unifiedRoleManagementPolicyEnablementRule
Azure AD
Multi-Factor
Authentication

Require ticket
information
on activation

Require
justification on
activation

3 On activation, AuthenticationContext_EndUser_Assignment / End user


require: Azure unifiedRoleManagementPolicyAuthenticationContextRule
AD
Conditional
Access
authentication
context
(Preview)

4 Require Approval_EndUser_Assignment / End user


approval to unifiedRoleManagementPolicyApprovalRule
activate

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

5 Allow permanent eligible Expiration_Admin_Eligibility / Admin


assignment unifiedRoleManagementPolicyExpirationRule

Expire eligible assignments


after

6 Allow permanent active Expiration_Admin_Assignment / Admin


assignment unifiedRoleManagementPolicyExpirationRule

Expire active assignments


after

7 Require Azure Multi-Factor Enablement_Admin_Assignment / Admin


Authentication on active unifiedRoleManagementPolicyExpirationRule
assignment

Require justification on
active assignment

Require ticket information


on activation
Number Azure portal UX Microsoft Graph Rule ID / Derived Enforced
Description resource type for caller

8 Require Azure Multi-Factor Enablement_EndUser_Assignment / End user


Authentication on active unifiedRoleManagementPolicyExpirationRule
assignment

Require justification on
active assignment

Require ticket information


on activation

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.

Number Azure portal UX Microsoft Graph Rule ID / Derived resource Enforced


Description type for caller

9 Send notifications when Notification_Admin_Admin_Eligibility / Admin


members are assigned unifiedRoleManagementPolicyNotificationRule
as eligible to this role:
Role assignment alert
Number Azure portal UX Microsoft Graph Rule ID / Derived resource Enforced
Description type for caller

10 Send notifications when Notification_Requestor_Admin_Eligibility / Assignee


members are assigned unifiedRoleManagementPolicyNotificationRule /
as eligible to this role: Requestor
Notification to the
assigned user (assignee)

11 Send notifications when Notification_Approver_Admin_Assignment / Approver


members are assigned unifiedRoleManagementPolicyNotificationRule
as eligible to this role:
request to approve a
role assignment
renewal/extension

12 Send notifications when Notification_Admin_Admin_Assignment / Admin


members are assigned unifiedRoleManagementPolicyNotificationRule
as active to this role:
Role assignment alert

13 Send notifications when Notification_Requestor_Admin_Assignment / Assignee


members are assigned unifiedRoleManagementPolicyNotificationRule /
as active to this role: Requestor
Notification to the
assigned user (assignee)

14 Send notifications when Notification_Approver_Admin_Eligibility / Approver


members are assigned unifiedRoleManagementPolicyNotificationRule
as active to this role:
Request to approve a
role assignment
renewal/extension

15 Send notifications when Notification_Admin_EndUser_Assignment / Admin


eligible members unifiedRoleManagementPolicyNotificationRule
activate this role: Role
activation alert

16 Send notifications when Notification_Requestor_EndUser_Assignment / Requestor


eligible members unifiedRoleManagementPolicyNotificationRule
activate this role:
Notification to activated
user (requestor)

17 Send notifications when Notification_Approver_EndUser_Assignment / Approver


eligible members unifiedRoleManagementPolicyNotificationRule
activate this role:
Request to approve an
activation
See also
Overview of role management through the privileged identity management (PIM)
API
Use PIM APIs in Microsoft Graph to update Azure AD rules
Configure Azure AD role settings in Privileged Identity Management - Azure portal
Use privileged identity management
(PIM) APIs in Microsoft Graph to update
Azure AD rules
Article • 04/12/2023

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" .

If successful, all requests return 204 No Content response codes.

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.

Example 1: Update the


activation maximum duration
Category of rule: Activation rule
Microsoft Graph rule type: unifiedRoleManagementPolicyExpirationRule
Microsoft Graph rule ID: Expiration_EndUser_Assignment

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": []
}
}

Example 2: Update the justification, MFA, and


ticketing rules required on activation
Category of rule: Activation rule
Microsoft Graph rule type: unifiedRoleManagementPolicyEnablementRule
Microsoft Graph rule ID: Enablement_EndUser_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_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": []
}
}

Example 3: Require approval to activate


Category of rule: Activation rule
Microsoft Graph rule type: unifiedRoleManagementPolicyApprovalRule
Microsoft Graph rule ID: Approval_EndUser_Assignment

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": []
}
]
}
}

Example 4: Set expiration of eligible


assignment
Category of rule: Activation rule
Microsoft Graph rule type: unifiedRoleManagementPolicyExpirationRule
Microsoft Graph rule ID: Expiration_Admin_Eligibility

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": []
}
}

Example 5: Set expiration of active assignment


Category of rule: Assignment rule
Microsoft Graph rule type: unifiedRoleManagementPolicyExpirationRule
Microsoft Graph rule ID: Expiration_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/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

Microsoft Graph PIM API enables organizations to manage privileged access to


resources in Azure Active Directory (Azure AD). It also helps to manage the risks of
privileged access by limiting when access is active, managing the scope of access, and
providing an auditable log of privileged access.

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:

Removing existing or adding more group members also removes administrators.


Adding more roles to the group members instead of assigning roles to individual
users.

Assigning eligibility instead of a persistently active User Administrator privilege allows


the company to enforce just-in-time access, which grants temporary permissions to
carry out the privileged tasks. After defining the role eligibility, the eligible group
member then activates their assignment for a temporary period. All records of role
activations will be auditable by the company.

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).

Step 1: Create a test user


Create a user who must reset their password at first sign in. From this step, record the
value of the new user's id for use in the next step. After creating the user, visit the Azure
portal and enable multifactor authentication (MFA) for the user. For more information
about enabling MFA, see the See also section.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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]"
}

Step 2: Create a security group that can be


assigned an Azure AD role
Create a group that’s assignable to an Azure AD role. Assign yourself as the group
owner and both you and Aline (the user created in Step 1) as members.

Request: Create a role-assignable group


Replace 1ed8ac56-4827-4733-8f80-86adc2e67db5 with your ID and 7146daa8-1b4b-4a66-
b2f7-cf593d03c8d2 with the value of Aline's ID.

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:

Create a unifiedRoleEligibilityScheduleRequest object that identifies the group IT


Helpdesk (User) as eligible for the User Administrator role for one year. Azure AD
extends this eligible assignment to the group members, that is, you and Aline.
Scope the eligible assignment to your entire tenant. This allows the user admin to
use their privilege against all users in your tenant, except higher privileged users
such as the Global Administrator.

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": {}
}

Step 4: Confirm the user's current role


assignments
While the group members are now eligible for the User Administrator role, they're still
unable to use the role. This is because they're yet to activate their eligibility. You can
confirm by checking the user's current role assignments.

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.

Step 5: User self-activates their eligible


assignment
An incident ticket CONTOSO: Security-012345 has been raised in Contoso's incident
management system and the company requires that all employee's refresh tokens be
invalidated. As a member of IT Helpdesk, Aline is responsible for fulfilling this task.

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.

For principalId, supply the value of your (Aline's) id.


The roleDefinitionId is the id of the role you're eligible for, in this case, the User
Administrator role.
Enter the details of the ticket system that provides an auditable justification for
activating the request.

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"
}
}

You may confirm your assignment by running GET


https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignmentScheduleReq

uests/filterByCurrentUser(on='principal') . The response object returns your newly


activated role assignment with its status set to Granted . With your new privilege, carry
out any allowed actions within five hours your assignment is active for. This includes
invalidating all employees' refresh tokens. After five hours, the active assignment expires
but through your membership in the IT Support (Users) group, you still remain eligible
for the User Administrator role.

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.

Step 6: Clean up resources


Sign in as the Global Administrator and delete the following resources that you created
for this tutorial: the role eligibility request, IT Support (Users) group, and the test user
(Aline Dupuy).

Revoke the role eligibility request

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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

HTTP/1.1 204 No Content

Delete the test user

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

HTTP/1.1 204 No Content


See also
Tutorial: Assign Azure AD roles in Privileged Identity Management using Microsoft
Graph PowerShell
Overview of role management through PIM
Overview of the industry data API in
Microsoft Graph (preview)
Article • 05/02/2023

The industry data API is an Education industry focused ETL (Extract-Transform-Load)


platform that combines data from multiple sources into a single Azure Data Lake data
store, normalizes the data, and exports it in outbound flows. The API provides resources
that you can use to get statistics after the data is processed, and assist with monitoring
and troubleshooting.

Why integrate with the industry API?

Build applications that upload and monitor


Most education software developers learn early on that class roster is one of the key
pieces of information they need to run their application, and it's typically locked away
inside a school student information system (SIS). Any time teachers bring a new
application into their classroom, they spend time manually importing roster data into
the app. Many independent software vendors (ISVs) address this by connecting with a
SIS to import roster data. With hundreds of student information systems with
proprietary formats, this can become a challenge.

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:

Upload and validate CSV data


Validate uploaded files

Enable school admins to manage identity and roster sync


using School Data Sync (preview)
Use the industry data API to manage end-to-end synchronization scenarios with School
Data Sync.

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?

Industry data API in Microsoft Graph beta

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

Why integrate with Outlook mail?

Integrate with rich features and reach hundreds of


millions of customers
Integrating with Outlook means tapping into the rich experience that customers love -
consistent, intuitive experience for mail, contacts, calendar, available on all devices -
mobile, web, and desktop.

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.

Automate message organization and processing


Customers like how Outlook helps them stay organized. Microsoft Graph brings these
features to app developers, enabling them to build customer workflows that optimize
on discovery and improve efficiency and productivity:

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.

Outlook categories are differentiated by name and color. Categories allow


customers to tag messages to enhance organization and discovery. Apps can
access and define a user's master list of categories. More, that list is shared across
Outlook messages, as well as events, contacts, tasks, and group posts, and opens
up creative scenarios for app developers. For example, an online training provider
can color-code the emails, course events, and follow-up assignments for each
course a user has enrolled in.

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.

Write smarter apps that leverage intelligence


Use Microsoft Graph to suggest contextual data to your app users:

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.

Store app data in a resource or resource instance


Often times apps have to store their data in an external data store and entail overhead
in managing and accessing the data. Microsoft Graph lets you simply include app data
as Internet message headers when creating or sending a new message, or a reply to a
message.

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.

Where is the data?


The Microsoft Graph API supports accessing data in users' primary mailboxes and in
shared mailboxes . The data can be calendar, mail, or personal contacts stored in a
mailbox in the cloud on Exchange Online as part of Microsoft 365, or on Exchange on-
premises in a hybrid deployment.

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?

Outlook mail API in Microsoft Graph v1.0


Outlook mail API in Microsoft Graph beta

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

Emails are represented by the message resource in Microsoft Graph.

By default, messages are identified by a unique entry ID in the id property. When a


message is initially created and saved as a draft or sent, the store provider assigns the
message an entry ID. By default, that ID changes when the message is copied or moved
to another folder, store, or .PST file. You reference the message by its current ID for
further processing.

Create and send mail


In Outlook, you can create and send an email in the same sendMail action, or you can
create a draft, subsequently add content and send the draft.

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.

Set the from and sender properties


When a message is being composed, in most cases, Outlook sets the from and sender
properties to the same signed-in user. You can update these properties in the following
scenarios:

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.

Use MailTips to check recipient status and save


time (preview)
Use MailTips to make smart decisions before sending an email. MailTips can tell you
information such as the recipient's mailbox is restricted to specific senders, or approval
is required for emailing the recipient.

Read messages with control over the body


format returned
You can read a message in a mailbox by referencing its ID:

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:

For text format requests: Preference-Applied: outlook.body-content-type="text"


For HTML format requests: Preference-Applied: outlook.body-content-type="html"

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

Integrate with '@' social gesture (preview)


@-mentions are notifications to alert users if they are mentioned in messages. The
mention resource enables apps to set and get the common online social gesture, the
'@' prefix, in emails. You can:

Create @-mentions when creating a message


Get all the messages in a user's mailbox that contain an @-mention of the user
Get all the @-mention is a message

Other shared capabilities


Take advantage of the following common capabilities that are shared among Microsoft
Graph entities:

Subscribe to change notifications on messages when one or more types of


changes occur, such as message creation or update.
Track incremental changes to messages in a folder.
Create open extensions or schema extensions to add custom data to a message
instance.
Create extended properties in a message instance to store custom data for
Outlook MAPI properties, when these properties are not already exposed in the
Microsoft Graph API metadata.

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.

Access mail folders


Programmatically, message folders are represented by the mailFolder resource, and the
Inbox is one of the folders at the root of the folder structure.

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.

Create and organize the folder tree


You can create mail folders under the Inbox or as child folders of other folders. When
you create, copy, or move a folder and its contents, Outlook updates the read-only
parentFolderId and childFolderCount properties of the involved folders. When the
contents of a folder are copied or moved to another folder, by default, the individual
entry IDs of the contents also change.

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.

Use rules to automate copying or moving


messages
Outlook lets customers set up rules to automate specific actions on incoming messages
when some pre-determined conditions are met. You can create a rule for the Inbox as a
messageRule to copy or move a message to a specific folder upon certain conditions.
Conditions are messageRulePredicates. They can include the message subject or body
containing certain text,the message sent from certain email addresses, or the message
marked important, and so on.

Direct only the messages you care about to the


Focused Inbox
Focused Inbox lets customers train Outlook to show only the incoming messages from
senders that you care about on the Focused tab, and the rest on the Other tab. Initially,
Outlook's classification system organizes Inbox messages in a default way. Over time,
you can correct and train the system through the user interface or programmatically.
The more you use the Focused Inbox, the better the classification system can infer which
incoming message you want to see on the Focused tab.

Programmatically, you can update the inferenceClassification property of a message to


indicate whether you want to see the message in the Focused or Other tab. This is a
one-off designation for a specific message. If, on the other hand, you want to see
messages from a specific sender always in the Focused tab or Other tab, you can set an
instruction for Outlook. Each instruction is an inferenceClassificationOverride instance
specifying the sender's name and your designation for messages from that sender to be
always focused or other . Each user's instructions for the user's Focused Inbox are
stored as a collection of inferenceClassificationOverride instances on the user object.
Keep messages and mail folders up to date in
apps
Apps often have to synchronize and keep a user's mail data up-to-date in the app local
store. Microsoft Graph lets you subscribe to change notifications to get notified when
data changes, and query for actual changes as soon as they happen.

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:

You can append a $value segment to a get-message operation on that message.


If the message is attached to an Outlook item or group post, you can append a
$value segment to a get-attachment operation on that item or group post.

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:

Plain text message


Message with alternative content (i.e., in both plain text and HTML)
Reply message with the original message attached
Text message with attachments of image, audio, video, or application files
Other message constructs

The following are typical MIME headers in a message. For more information, see RFC
2045 .

MIME-Version - Indicates the message is MIME-formatted.

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.

Get MIME content of an Outlook message


You can get the MIME representation of a message by appending the $value segment
when getting the message:

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

Received: from contoso.com (10.194.241.197) by


contoso.com (10.194.241.197) with Microsoft
SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.1.1374.0 via
Mailbox
Transport; Mon, 4 Sep 2017 03:00:08 -0700
Received: from contoso.com (10.194.241.197) by
contoso.com (10.194.241.197) with Microsoft
SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.1.1374.0; Mon, 4
Sep
2017 03:00:07 -0700
Received: from contoso.com
(fe80::5bf:5059:4ca0:5017) by contoso.com
(fe80::5bf:5059:4ca0:5017%12) with mapi id 15.01.1374.000; Mon, 4 Sep 2017
03:00:01 -0700
From: Administrator <[email protected]>
To: Administrator <[email protected]>
Subject: This email has attachment.
Thread-Topic: This email has attachment.
Thread-Index: AQHTJWSHSywMzSz8o0OJud48nG50GQ==
Date: Mon, 4 Sep 2017 10:00:00 +0000
Message-ID:
<[email protected]>
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:
contoso.com
X-MS-Has-Attach: yes
X-MS-Exchange-Organization-Network-Message-Id:
0ffdb402-ec03-42c8-5d32-08d4f37bb517
X-MS-Exchange-Organization-SCL: -1
X-MS-TNEF-Correlator:
X-MS-Exchange-Organization-RecordReviewCfmType: 0
x-ms-publictraffictype: Emai

```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

The attachment is an email.

--_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_--

Get MIME content of an Outlook message


attached to an Outlook item or group post
You can also get the MIME representation of an Outlook message, if the message has
been attached to an Outlook event, message, task, or group post that your app can
access.

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.

If the message is attached to an event in the user's default calendar:

HTTP

GET /users/{id}/events/{id}/attachments/{id}/$value

If the message is attached to another message in the user's mailbox:

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

Received: from MWHPR22MB0302.namprd22.prod.outlook.com (2603:10b6:104:5::23)


by MWHPR2201MB1053.namprd22.prod.outlook.com with HTTPS via
CO2PR04CA0193.NAMPRD04.PROD.OUTLOOK.COM; Mon, 22 Apr 2019 19:48:20 +0000
Received: from MWHPR22MB1007.namprd22.prod.outlook.com (10.172.167.21) by
MWHPR22MB0302.namprd22.prod.outlook.com (10.173.53.146) with Microsoft SMTP
Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id
15.20.1813.12; Mon, 22 Apr 2019 19:48:16 +0000
Received: from MWHPR22MB1007.namprd22.prod.outlook.com
([fe80::1d05:c2d3:92a:f8dc]) by MWHPR22MB1007.namprd22.prod.outlook.com
([fe80::1d05:c2d3:92a:f8dc%9]) with mapi id 15.20.1813.017; Mon, 22 Apr
2019
19:48:16 +0000
From: Adele Vance <[email protected]>
To: Megan Bowen <[email protected]>
Subject: Press conference
Thread-Topic: Press conference
Thread-Index: AQHU+UQNzFWFTilRjECtpiWorLYxqA==
Date: Mon, 22 Apr 2019 19:48:16 +0000
Message-ID:

<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

Create a message draft createMessage

Send an email sendMail

Reply to a message reply

Create a draft to reply to a message createReply

ReplyAll to a message replyAll

Create a draft to replyAll to a message createReplyAll

Forward a message forward


Use cases API method

Create a draft to forward a message createForward

Specify request header and MIME message


body
You can create a message in JSON or MIME format. Specify the intended format in the
request header:

Content-Type: application/json to use JSON format in the request body.


Content-Type: text/plain to use MIME format in the request body.

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

Received: from contoso.com (10.194.241.197) by


contoso.com (10.194.241.197) with with HTTPS; Thu, 6 May 2021
22:47:18 +0000
Received: from contoso.com (10.194.241.197)
by contoso.com (10.194.241.197) with
SMTP Server (version=TLS1_2,
cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.1.1374.0 via
Mailbox; Thu, 6 May
2021 22:47:15 +0000
Received: from contoso.com
(fe80::5bf:5059:4ca0:5017) by contoso.com
(fe80::5bf:5059:4ca0:5017%12) with mapi id 15.01.1374.000; Thu, 6 May 2021
22:47:14 +0000
From: Adele Vance <[email protected]>
To: Alex Wilber <[email protected]>
CC: Christie Cline <[email protected]>
Subject: Testing the MIME feature in Graph
Thread-Topic: Testing the MIME feature in Graph
Thread-Index: AQHTJWSHSywMzSz8o0OJud48nG50GQ==
Date: Thu, 6 May 2021 22:47:14 +0000
Message-ID:
<[email protected]>
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: contoso.com
X-MS-Has-Attach: yes
X-MS-Exchange-Organization-Network-Message-Id:
0ffdb402-ec03-42c8-5d32-08d4f37bb517
X-MS-Exchange-Organization-SCL: -1
X-MS-TNEF-Correlator:
X-MS-Exchange-Organization-RecordReviewCfmType: 0
x-ms-publictraffictype: Email
x-originating-ip: [123.456.789.012]
x-ms-traffictypediagnostic: ASDFG12HJ3456:
X-Microsoft-Antispam-Mailbox-Delivery:
ucf:0;jmr:0;auth:0;dest:I;ENG:(750129)(520011016)(706158)(944506458)
(944626604);
X-Microsoft-Antispam-Message-Info:

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,

We are testing the Graph MIME feature.

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,&nbsp;</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.&nbsp;</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_--

The following is the corresponding base64-encoded string:

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_--

Error conditions and messages


Scenario Operation Error Error message
code

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:

Microsoft Graph permissions


Mailbox permissions

Microsoft Graph permissions


In order to send messages from another user, applications that use user tokens use the
Mail.Send.Shared permission.

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.

Sending with Microsoft Graph


You can send messages from another user by either sending directly or by creating a
draft and then sending it.

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]"
}
}
}

Sent Items behavior


After the message is sent, it can be saved to the sending user's Sent Items folder, the
from user's Sent Items folder, or both. It can also not be saved at all.

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.

The default behavior can be changed by other outside factors:

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

Example 1: Successful send through /me endpoint


In this example, Adele Vance has been granted Send on Behalf permission to Allan
Deyoung's mailbox.

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

HTTP/1.1 202 Accepted

Example 2: Unsuccessful attempt to send without


permissions
In this example, Adele Vance attempts to send an email from Patti Fernandez, but has
not been granted either the Send on Behalf or Send As permission. The response
contains a ErrorSendAsDenied error.

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

HTTP/1.1 403 Forbidden


Content-Type: application/json

{
"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.

1. Creating a new message in sender's mailbox


Outlook creates a new message in the sender's Drafts folder, copies the message
content, recipients, and attachments from the JSON request to the draft message, and
then saves it. If successful, the method returns an HTTP response 202 Accepted status
code.

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.

2. Notifying transport service of new outbound


message
Next, Exchange Online notifies its transport service that a new message is available for
pickup.

3. Copying outbound message to transport


pipeline
Next, the transport process reads message content from the sender's mailbox, converts
it to MIME format, and stores it into the transport pipeline. If the sender provided MIME
content, the transport process copies the MIME content more or less intact. Otherwise,
the transport process serializes the message properties to construct MIME content.

If step 3 fails, the transport process constructs a non-delivery report message and places
it in the sender's Inbox.

4. Moving original message to the Sent Items


folder
After all of this succeeds, transport calls back to the store to assume responsibility for
the message. In response, the Exchange store updates the message and moves it from
the Drafts folder to the Sent Items folder. (Depending on optional message properties, it
may move to a different folder or delete the message instead.)

5. Performing policy evaluation and routing


The next steps taken by transport include policy enforcement, routing, and next-hop
delivery. Transport examines recipient email addresses and buckets them according to
what the initial routing hop has to be. Transport detects invalid recipient addresses at
this point, for which transport mails the non-delivery reports back to the sender.
Transport then applies policies configured by tenant administrators. Such policies may
reject the message based on its content, store additional copies, and so on. After
applying policy, transport fans out a copy of the message to each next-hop destination.
For more details about the transport flow, see mail flow and the transport pipeline.

6. Delivering message to recipients


Exchange Online transport may or may not be responsible for final delivery to all
recipients. That depends on whether those recipients have Exchange Online mailboxes.

7. Delivering report messages to sender


A few services are involved in generating delivery reports and sending them to the
sender accordingly:

When a responsible transport component, which can be a Exchange Online or non-


Exchange Online component, determines that one or more recipient email
addresses are non-deliverable, the component generates non-delivery reports.
At the same time, the transport component generates delivery reports if the
sender explicitly requested them.
The recipient's email service or email client may generate read and non-read
notifications, or not at all. For more details about report messages, see DSNs and
NDRs in Exchange Server.

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

Be aware of a known issue if you're attaching large files to a message or event in a


shared or delegated mailbox.

Step 1: Create an upload session


Create an upload session to attach a file to a message or event. Specify the file in the
input parameter AttachmentItem.

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.

The uploadSession object in the response also includes the nextExpectedRanges


property, which indicates the initial upload starting location should be byte 0.

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.

Example: Create an upload session for a message

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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-"
]
}

Example: Create an upload session for an event

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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-"
]
}

Step 2: Use the upload session to upload a


range of bytes of the file
To upload the file, or a portion of the file, make a PUT request to the URL returned in
step 1 in the uploadUrl property of the uploadSession resource. You can upload the
entire file, or split the file into multiple byte ranges. For better performance, keep each
byte range less than 4 MB.

Specify request headers and request body as described below.

Request headers

Name Type Description

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.

Content- String The MIME type. Specify application/octet-stream . Required.


Type

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).

Example: First upload to the message

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"]
}

Example: First upload to the event

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"]
}

Step 3: Continue uploading byte ranges until


the entire file has been uploaded
Following the initial upload in step 2, continue to upload the remaining portion of the
file, using a similar PUT request as described in step 2, before you reach the expiration
date/time for the session. Use the nextExpectedRanges collection to determine where
to start the next byte range to upload. You may see multiple ranges specified, indicating
parts of the file that the server has not yet received. This is useful if you need to resume
a transfer that was interrupted and your client is unsure of the state on the service.

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.

Example: Final upload to the message

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

HTTP/1.1 201 Created

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

Example: Final upload to the event

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

Step 4 (optional): Get the file attachment from


the Outlook item
As always, getting an attachment from an Outlook item is not technically limited by
attachment size.

However, getting a large file attachment in base64-encoded format affects API


performance. If you expect a large attachment:

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.

Example: Get the raw file attached to the event


Following the event example and using the attachment ID returned in the Location
header of the previous step, the example request in this section shows using a $value
parameter to get the attachment raw content data.

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

{Raw bytes of the file}

Example: Get the metadata of the file attached to the


message
Following the message example, the example request in this section shows using a
$select parameter to get some of the metadata of a file attachment on a message,
excluding contentBytes.

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
}

Alternative: Cancel the upload session


At any point of time before the upload session expires, if you have to cancel the upload,
you can use the same initial opaque URL to delete the upload session. A successful
operation returns HTTP 204 No Content .

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.

Example: Cancel the upload session for the message

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

HTTP/1.1 204 No content


Errors

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.

Microsoft Graph permissions


Use the delegated permissions, Mail.Read.Shared or Mail.ReadWrite.Shared , to
respectively read or write messages in a shared or delegated folder.

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 .

For more information, see mail permissions.

Get a message in the shared folder


You can get a specific message in Garth's Inbox:

HTTP

GET users/{Garth-userId | Garth-


userPrincipalName}/mailfolders('Inbox')/messages/{id}
On successful completion, you'll get HTTP 200 OK and the message instance identified
by {id} from Garth's Inbox.

Get all messages in the shared folder


Get all the messages in Garth's Inbox:

HTTP

GET users/{Garth-userId | Garth-


userPrincipalName}/mailfolders('Inbox')/messages

On successful completion, you'll get HTTP 200 OK and a collection of message instances
in Garth's Inbox.

Get the shared folder


Get the folder (Inbox) that Garth has shared with John.

HTTP

GET users/{Garth-userId | Garth-userPrincipalName}/mailfolders('Inbox')

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.

Lifetime of immutable IDs


An item's immutable ID will not change so long as the item stays in the same mailbox.
That means that immutable ID will NOT change if the item is moved to a different folder
in the mailbox. However, the immutable ID will change if:

The user moves the item to an archive mailbox.


The user exports the item (to a PST, as an MSG file, etc.) and re-imports it into their
mailbox.

Items that support immutable IDs


The following items support immutable IDs:

message resource type


attachment resource type
event resource type
eventMessage resource type
contact resource type
outlookTask resource type

Container types (mailFolder, calendar, etc.) do not support immutable ID, but their
regular IDs were already constant.

Immutable ID with sending mail


You can use immutable IDs to find a message in the Sent Items folder after it has been
sent, using the following steps:

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.

Immutable ID with change notifications


You can request that Microsoft Graph send immutable IDs in change notifications by
including the Prefer: IdType="ImmutableId" header when creating a subscription.
Existing subscriptions created without the header will continue to use the default ID
format. In order to switch existing subscriptions to use immutable IDs, you must delete
and recreate them using the header.

Immutable ID with delta query


You can request that Microsoft Graph return immutable IDs in delta query responses for
supported resource types by including the Prefer: IdType="ImmutableId" header. The
@odata.nextLink and @odata.deltaLink values returned by delta queries are compatible

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.

Updating existing data


If you've already got a database filled with thousands of regular IDs, you can migrate
those IDs to immutable format using the translateExchangeIds function. You can provide
an array of up to 1000 IDs to be translated into a target format.

7 Note

You can also use translateExchangeIds to migrate Exchange Web Services


applications to Microsoft Graph.

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.

Subscribe to changes in contacts, calendar, or


mail
To subscribe to change notifications of Outlook resources, first create a subscription.

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:

Delegated permission supports subscribing to items in folders in only the signed-in


user's mailbox. For example, you cannot use the delegated permission Calendars.Read
to subscribe to events in another user’s mailbox.

To subscribe to change notifications of Outlook contacts, events, or messages in


shared or delegated folders:
Use the corresponding application permission to subscribe to changes of items in a
folder or mailbox of any user in the tenant.
Do not use the Outlook sharing permissions (Contacts.Read.Shared,
Calendars.Read.Shared, Mail.Read.Shared, and their read/write counterparts), as
they do not support subscribing to change notifications on items in shared or
delegated folders.

Depending on the resource, use the least privileged permission specified in the following
table to call this API.

Resource Supported Resource Paths Delegated Delegated Application


(work or (personal
school Microsoft
account) account)

contact Changes to all personal contacts in a user's Contacts.Read Contacts.Read Contacts.Read


mailbox:
/me/contacts
/users/{id}/contacts
Changes to contacts in a user's
contactFolder:
/users/{id}/contactFolders/{id}/contacts

event Changes to all events in a user's mailbox: Calendars.Read Calendars.Read Calendars.Read


/me/events
/users/{id}/events

message Changes to all messages in a user's Mail.ReadBasic, Mail.ReadBasic, Mail.ReadBasic,


mailbox: Mail.Read Mail.Read Mail.Read
/me/messages
/users/{id}/messages
Changes to messages in a user's
mailFolder:
/users/{id}/mailFolders/{id}/messages

Include resource data in notification payload (preview)


7 Note

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:

includeResourceData: Set this property to true to explicitly request resource data.

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

Do not include in the URL $top , $skip , $orderby , $select=Body,UniqueBody , and


$expand other than singleValueExtendedProperties or
multiValueExtendedProperties.

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.

Refine the conditions for a notification


You can further refine the conditions for a notification by using the $filter query
parameter. See an example.

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:

A message added to or marked unread in the folder would trigger a Created


notification.
Reading a message or marking it as read in the folder would trigger a Deleted
notification.
A change to any property, other than isRead, of a message resource in the folder
would trigger an Updated notification.

If you don’t use a $filter when creating the subscription:

Adding a message to the folder would result in a Created notification.


Reading a message in the folder, marking the message as read, or changing any other
property of a message in that folder would result in an Updated notification.
Deleting the message would result in a Delete notification.

Subscribe to lifecycle notifications


The Outlook contact, event, and message resources also support subscribing to lifecycle
notifications. Lifecycle notifications are needed in case your app gets their subscriptions
removed or misses some change notifications. Apps should implement logic to detect and
recover from the loss, and resume a continuous change notification flow. To learn more, see
subscribing to lifecycle notifications.

Keep track of subscription lifetime


Make sure to extend a subscription before it expires. The maximum lifetime for a
subscription without Outlook resource data is 4230 minutes (under 3 days), and 1 day with
resource data.

If you lose the permission granted earlier for a subscription and the subscription expires
meanwhile, request permission again to create a new subscription.

Receive notification payloads


Depending on your subscription, notifications may include resource data. Subscriptions
with resource data allow you to get the resource payload along with the notification,
avoiding the overhead for a separate API call to get the changed resource data.

Receive notifications with resource data (preview)


The following is an example of the payload of a notification with resource data of a
message resource. The resource and resourceData properties correspond to the message
instance that triggered the notification. Use the encryptedContent property to decrypt the
resource data.
JSON

{
"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.

The following is an example of a decrypted notification payload. The decrypted payload


conforms to the Outlook message schema. The payload is similar to that returned by a GET
message operation. However, the notification payload contains only those properties
specified with a $select parameter in the resource property of the subscription.
Notification payloads for other Outlook resources like contact and event follow their
respective schemas.

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]"
}
}
}

Receive notifications without resource data


Notifications without resource data give you enough information to make GET calls to get
the resource. Subscriptions for notifications without resource data don't require an
encryption certificate, because the actual resource data is not sent over.

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

Example 1: Create a subscription to get change notifications


without resource data when the user receives a new
message
The following example requests a notification for a message being created in the user's
mailbox.

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

The following is an example of the 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/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
}

Example 2: Create a subscription to get change


notifications with resource data when the user receives a
new message (preview)
The following example subscribes to notifications with resource data for a message being
created in the user's mailbox. The properties of the message resource to be included in the
notification payload are specified using the $select query parameter.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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
}

Example 3: Create a subscription to get change


notifications with resource data for a message based on a
condition (preview)
The following example subscribes to notifications with resource data for a message being
created in the Drafts folder, containing one or more attachments, and of high importance.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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

Why integrate with OneNote?


By integrating your apps with OneNote, you can create empowering experiences across
multiple platforms that reach millions of users worldwide. You can use Microsoft Graph
to access notebooks, sections, and pages in OneNote to create solutions that help your
users plan and organize ideas and information.

Collect and organize notes and ideas


Use OneNote as a canvas where users can add and arrange their content. Microsoft
Graph makes it easy to write apps that enable students to take notes and do research,
families to share plans and ideas, or shoppers to share pictures. Your app can grab the
information people want, send it to OneNote, and then help them organize it.

Capture information in many formats


Capture HTML, embed images (sourced locally or at a public URL), video, audio, email
messages, and other common file types. OneNote can even render webpages and PDF
files as snapshots. Microsoft Graph supports a set of standard HTML and CSS for
OneNote page layout, so you can use tables, inline images, and basic formatting to get
the look you want.

Use the OneNote ecosystem to enhance your core


scenarios
Tap into other powerful OneNote features. The OneNote APIs in Microsoft Graph run
OCR on images, support full-text search, auto-syncs clients, process images, and extract
business card captures and online product and recipe listings. Use OneNote as your
digital memory store in the cloud for notes and lightweight media, or as a data feed for
domain-specific data.
Reach millions of OneNote users on all major platforms
Use OneNote to increase your app usage. OneNote is preinstalled on new Windows
devices, and is available for most platforms, online, and as part of Microsoft 365. When
you publish apps that use the feature-rich OneNote environment, you have access to
broad cross-platform market potential.

What can I do with OneNote APIs in Microsoft


Graph?
The following are some of the most popular requests for working with OneNote
resources.

Operation URL

GET my notebooks https://graph.microsoft.com/v1.0/me/onenote/notebooks

GET my sections https://graph.microsoft.com/v1.0/me/onenote/sections

GET my pages https://graph.microsoft.com/v1.0/me/onenote/pages

Learn more about OneNote APIs


Take an in-depth look at Microsoft Graph APIs to learn about the OneNote content
updating capabilities. The topics in the following list show you how to create new
OneNote pages and update existing pages with new content. You'll also learn about
best practices in using Microsoft Graph to update OneNote notebooks.

Work with OneNote


Use the OneNote REST API
Best practices
Branding guidelines
Open the OneNote client
Use note tags in OneNote pages
Error codes for OneNote APIs in Microsoft Graph

Work with OneNote pages


Input and output HTML in OneNote pages
Get OneNote content and structure with Microsoft Graph
Create OneNote pages
Update OneNote page content

Work with OneNote page content


Create absolute positioned elements in OneNote pages
Add images, videos, and files to OneNote pages
Use OneNote API div tags to extract data from captures

API reference
Looking for the API reference for this service?

OneNote API in Microsoft Graph v1.0


OneNote API in Microsoft Graph beta

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

Applies to: Consumer notebooks on OneDrive | Enterprise notebooks on Microsoft 365

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:

Backup/restore OneNote sections


Backup/restore OneNote notebooks

For backup and restore operations, see Best practices for discovering files and
detecting changes at scale.

Construct the request URI


To construct the request URI, start with the service root URL:

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

Learn more about the service root URL.

Resource paths for GET requests


Use the following resource paths to get pages, sections, section groups, notebooks, and
image or file resources.

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]

Get pages (metadata) from a specific section.

../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 sort order for pages is lastModifiedTime desc .

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]

Pages can expand the parentNotebook and parentSection properties.

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" />

Page HTML content


Get the HTML content of a page.

../pages/{page-id}/content[?includeIDs]

(learn more about returned HTML content)

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]

Get all sections that are directly under a specific notebook.

../notebooks/{notebook-id}/sections[?filter,orderby,select,top,skip,expand,count]

Sections can expand the parentNotebook and parentSectionGroup properties.


The default sort order for sections is name asc .

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]

Sections can expand the parentNotebook and parentSectionGroup properties.

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]

Section groups can expand the sections, sectionGroups, parentNotebook, and


parentSectionGroup properties.

The default sort order for section groups is name asc .

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]

Section groups can expand the sections, sectionGroups, parentNotebook, and


parentSectionGroup properties.
The default query expands the parent notebook and parent section group and selects
their id , name , and self properties.

Notebook collection
Get all the notebooks that are owned by the user.

../notebooks[?filter,orderby,select,top,skip,expand,count]

Notebooks can expand the sections and sectionGroups properties.

The default sort order for notebooks is name asc .

Notebook entity
Get a specific notebook.

../notebooks/{notebook-id}[?select,expand]

Notebooks can expand the sections and sectionGroups properties.

Image or other file resource


Get the binary data of a specific resource.

../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

Getting a collection of resources is not supported.

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

Example GET requests


You can query for OneNote entities and search page content to get just the information
you need. The following examples show some ways you can use supported query string
options in GET requests to Microsoft Graph.

Remember:

All GET requests start with the service root URL.

Examples: https://www.onenote.com/api/v1.0/me/notes and


https://www.onenote.com/api/v1.0/myOrganization/siteCollections/{id}/sites/{id

}/notes/

Spaces in the URL query string must use %20 encoding.


Example: filter=title%20eq%20'biology'

Property names and OData string comparisons are case-sensitive. We recommend


using the OData tolower function for string comparisons.

Example: filter=tolower(name) eq 'spring'

search & filter


Get all pages that contain the term recipe that were created by a specific app ( search is
available for consumer notebooks only).

[GET] ../pages?search=recipe&filter=createdByAppId eq 'WLID-


000000004C12821A'

search & select


Get the title, OneNote client links, and contentUrl link for all pages that contain the
term golgi app ( search is available for consumer notebooks only).

[GET] ../pages?search=golgi app&select=title,links,contentUrl

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

expand (multiple levels)


Get all notebooks and expand their sections and section groups, and expand all sections
in each section group.

[GET] ../notebooks?expand=sections,sectionGroups(expand=sections)

7 Note

Expanding parents of child entities or expanding children of parent entities creates


a circular reference and is not supported.

expand & select (multiple levels)


Get the name and self link for a specific section group, and get the name and self links
for all its sections.

[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
)

expand & levels (multiple levels)


Get all notebooks, sections, and section groups.

[GET] ../notebooks?
expand=sections,sectionGroups(expand=sections,sectionGroups(levels=max;expan
d=sections))

filter
Get all sections that were created in October 2014.

[GET] ../sections?filter=createdTime ge 2014-10-01 and createdTime le 2014-


10-31

Get the pages that were created by a specific app since January 1, 2015.

[GET] ../pages?filter=createdByAppId eq 'WLID-0000000048118631' and


createdTime ge 2015-01-01

filter & expand


Get all pages in a specific notebook. The API returns 20 entries by default.

[GET] ../pages?filter=parentNotebook/id eq '{notebook-


id}'&expand=parentNotebook
Get the name and pagesUrl link for all sections from the School notebook. OData string
comparisons are case-sensitive, so use the tolower function as a best practice.

[GET] ../notebooks?filter=tolower(name) eq
'school'&expand=sections(select=name,pagesUrl)

filter & select & orderby


Get the name and pagesUrl link for all sections that contain the term spring in the
section name. Order sections by last modified date.

[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.

[GET] ../pages?orderby=createdByAppId,createdTime desc

search & filter & top


Get the five newest pages created since January 1, 2015 that contain the phrase cell
division. The API returns 20 entries by default with a maximum of 100. The default sort
order for pages is lastModifiedTime desc ( search is available for consumer notebooks
only).

[GET] ../pages?search="cell division"&filter=createdTime ge 2015-01-01&top=5

search & filter & top & skip


Get the next five pages in the result set ( search is available for consumer notebooks
only).

[GET] ../pages?search=biology&filter=createdTime ge 2015-01-01&top=5&skip=5

And the next five ( search is available for consumer notebooks only).

[GET] ../pages?search=biology&filter=createdTime ge 2015-01-01&top=5&skip=10

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

select & expand & filter (multiple levels)


Get the name and pagesUrl link for all sections in the user's default notebook.
[GET] ../notebooks?
select=name&expand=sections(select=name,pagesUrl)&filter=isDefault eq true

top & select & orderby


Get the title and self link for the first 50 pages, ordered alphabetically by title. The API
returns 20 entries by default with a maximum of 100. The default sort order for pages is
lastModifiedTime desc .

[GET] ../pages?top=50&select=title,self&orderby=title

skip & top & select & orderby


Get pages 51 to 100. The API returns 20 entries by default with a maximum of 100.

[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.

Supported OData query string options


When sending GET requests to Microsoft Graph, you can use OData query string options
to customize your query and get just the information you need. They can also improve
performance by reducing the number of calls to the service and the size of the response
payload.

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.

Can be used for a single entity or a collection.


Separate multiple properties with commas.
Property names are case-sensitive.

filter filter=isDefault eq true

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

Property names and OData string comparisons are case-sensitive. We recommend


using the OData tolower function for string comparisons.

Example: filter=tolower(name) eq 'spring'

orderby orderby=title,createdTime desc

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

search search=cell div

Available for consumer notebooks only.

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

Supported OData operators and functions


Microsoft Graph supports the following OData operators and functions in filter
expressions. When using OData expressions, remember:

Spaces in the URL query string must be replaced with the %20 encoding.
Example: filter=isDefault%20eq%20true

Property names and OData string comparisons are case-sensitive. We recommend


using the OData tolower function for string comparisons.

Example: filter=tolower(name) eq 'spring'

Comparison operator Example

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)

Logical operator Example

and createdTime le 2014-01-30 and createdTime gt 2014-01-23

or createdByAppId eq '{app-id}' or createdByAppId eq '{app-id}'

not not contains(tolower(title),'school')

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

substring substring(tolower(title),1) eq 'spring'

tolower tolower(title) eq 'spring'

toupper toupper(title) eq 'SPRING'

trim trim(tolower(title)) eq 'spring'

concat concat(title,'- by MyRecipesApp') eq 'Carrot Cake Recipe - by


MyRecipesApp'

OneNote entity properties


The filter, select, expand, and orderby query expressions can include properties of
OneNote entities.

Example

../sections?filter=createdTime ge 2015-01-
01&select=name,pagesUrl&orderby=lastModifiedTime desc

Property names are case-sensitive in query expressions.

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:

Pages: parentNotebook, parentSection


Sections: parentNotebook, parentSectionGroup
Section groups: sections, sectionGroups, parentNotebook, parentSectionGroup
Notebooks: sections, sectionGroups

Request and response information for GET


requests
Request data Description

Protocol All requests use the SSL/TLS HTTPS protocol.

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.

Accept header application/json for OneNote entities and entity sets

text/html for page content

Response Description
data

Success A 200 HTTP status code.


code

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.

Constructing the Microsoft Graph notes service root URL


The Microsoft Graph notes root URL uses the following format for all calls to Microsoft
Graph notes:

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 for GET requests
To get OneNote content or structure, you'll need to request appropriate permissions.

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:

Create a page by sending a POST pages request.

Create a notebook by sending a POST notebooks request.

Get page metadata by sending a GET pages or GET pages/{id} request.

Get notebook metadata by sending a GET notebooks or GET notebooks/{id}


request.
The following examples show how to check the status code of the response, parse the
JSON to extract the URLs, and then open the OneNote client.

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

/* Import the JSON library */


#import "AFURLRequestSerialization.h"

- (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

NSURL *url = [NSURL URLWithString:standardResponse.oneNoteWebUrl];


[[UIApplication sharedApplication] openURL:url];

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

public ApiResponse getResponse() throws Exception {


/* Get the HTTP response code and message from the connection object */
int responseCode = mUrlConnection.getResponseCode();
String responseMessage = mUrlConnection.getResponseMessage();
String responseBody = null;

/* Get the response if the new page was created successfully. */


if ( responseCode == 201) {
InputStream is = mUrlConnection.getInputStream();

/* Verify that this byte array is big enough. */


byte[] b1 = new byte[1024];
StringBuffer buffer = new StringBuffer();

/* Copy the body of the response into the new string. */


/* Make sure the buffer is big enough. */
while ( is.read(b1) != -1)
buffer.append(new String(b1));

/* When the returned data is complete, close the connection


and convert the byte array into a string. */
mUrlConnection.disconnect();
responseBody = buffer.toString();
}

/* Create a new JSON object, and an object to hold the response URLs. */
JSONObject responseObject = null;
ApiResponse response = new ApiResponse();
try {

/* Store and verify the HTTP response code. */


response.setResponseCode(responseCode);
response.setResponseMessage(responseMessage);
if ( responseCode == 201) {

/* Retrieve the two URLs from the links property. */


responseObject = new JSONObject(responseBody);
String clientUrl = responseObject.getJSONObject(

"links").getJSONObject("oneNoteClientUrl").getString("href");
String webUrl = responseObject.getJSONObject(
"links").getJSONObject("oneNoteWebUrl").getString("href");
response.setOneNoteClientUrl(clientUrl);
response.setOneNoteWebUrl(webUrl);
}
} catch (JSONException ex) {

/* If the JSON was malformed or incomplete... */


String msg = ex.getMessage();
msg = msg;
}
return response;
}

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

starting the Intent. The following example shows how to do that.

Java

if (response.getResponseCode() == 201) {

// Get the URL from the OneNote API JSON response.


String onenoteClientUrl = obtainClientLinkFromJSONResponse();
String androidClientUrl =
onenoteClientUrl.replaceAll(
"=([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-
[0-9a-fA-F]{12})&",
"={$1}&");

// Open the URL: Open the newly created OneNote page.


Uri uriUrl = Uri.parse(androidClientUrl);
Intent launchBrowser = new Intent(Intent.ACTION_VIEW, uriUrl);
startActivity(launchBrowser);
}

See also
Get OneNote content and structure
Create OneNote pages
Create OneNote pages
Article • 03/03/2023

Applies to: Consumer notebooks on OneDrive | Enterprise notebooks on Microsoft 365

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 .

Construct the request URI


To construct the POST request URI, start with the service root URL:

https://graph.microsoft.com/v1.0/me/onenote

Then append the pages endpoint:

Create a page in any section (specified by section name)

.../pages?sectionName=DefaultSection

Create a page in any section (specified by ID)

.../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:

Create a page in the default section of 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

Learn more about the service root URL.

Use the sectionName URL parameter


The following rules apply when using the sectionName parameter to create a page in a
named section in the default notebook:

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.

Section names must be URL-encoded. For example, spaces must be encoded as


%20.

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.

Construct the message body


The HTML that defines page content is called input HTML. Input HTML supports a subset
of standard HTML and CSS, with the addition of custom attributes. (Custom attributes,
like data-id and data-render-src, are described in Input and output HTML.)

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>

If you're sending binary data, you must use a multipart request.

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.

Requirements and limitations for input HTML in POST


pages requests
When sending input HTML, be aware of these general requirements and limitations:

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.

JavaScript code, included files, and CSS are removed.

HTML forms are removed in their entirety.

Microsoft Graph supports a subset of HTML elements.


Microsoft Graph supports a subset of common HTML attributes and a set of
custom attributes, such as the data-id attribute used for updating pages. For
supported attributes, see Input and output HTML.

Supported HTML and CSS for OneNote pages


Not all elements, attributes, and properties are supported (in HTML4, XHTML, CSS,
HTML5, etc.). Instead, Microsoft Graph accepts a limited set of HTML that better fits how
people use OneNote. For more information, see HTML tag support for pages . If a tag's
not listed there, it'll probably be ignored.

The following list shows the basic element types that Microsoft Graph supports:

<head> and <body>


<title> and <meta> that set the page title and creation date

<h1> through <h6> for section headings


<p> for paragraphs

<ul> , <ol> , and <li> for lists and list items

<table> , <tr> and <td> , including nested tables


<pre> for preformatted text (preserves white space and line breaks)

<b> and <i> for bold and italic character styles

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

... binary image data ...

--MyPartBoundary198374
Content-Disposition:form-data; name="fileBlock1"
Content-Type:application/pdf

... binary file data ...

--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

Protocol All requests use the SSL/TLS HTTPS protocol.

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

Success A 201 HTTP status code.


code

Response A OData representation of the new page in JSON format.


body

Errors If the request fails, the API returns errors in the @api.diagnostics object in the
response body.

Location The resource URL for the new page.


header

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.

Constructing the Microsoft Graph service root URL


The Microsoft Graph service root URL uses the following format for all calls to Microsoft
Graph:

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.

OneNote section size limitations


There is a limit to the number of pages that you can add to a section using the OneNote
API. When this limit is reached for a section and an attempt is made to create a new
page in that section, you will see a response with HTTP status code 507 and message
"Exceeded the maximum number of pages allowed per section". For more information
about this error code, see OneNote error codes.

You can use one of the following workarounds:

Create a new section and add new pages there.


Delete unused pages of an existing section that has reached the page limit.

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

Applies to Consumer notebooks on OneDrive | Enterprise notebooks on Microsoft 365

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.

Construct the request URI


To construct the request URI, start with the service root URL:

https://graph.microsoft.com/v1.0/me/onenote

Then append the page's content endpoint:

Get the page HTML and all defined data-id values

../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.

Your full request URI will look like this:

https://graph.microsoft.com/v1.0/me/onenote/pages/{id}/content

Learn more about the service root URL.

Construct the message body


The HTML of a OneNote page contains text, images, and other content organized into
structures such as div, img, and ol elements. To update OneNote page content, you add
and replace HTML elements on the page.

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>'
}
]

See more examples.

Attributes for JSON change objects


Use the target, action, position, and content attributes to define JSON objects for
PATCH requests.

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.

Applies only to body, div, ol, and ul elements.

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.

Applies only to body, div, ol, and ul elements.

replace Replaces the target with the supplied content.

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.

With insert: The subsequent sibling of the target element.

before With append: The first child of the target element.

With insert: The preceding sibling 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

<p id="p:{33f8a242-7c33-4bb2-90c5-8425a68cc5bf}{40}">Some text on the


page</p>
<img id="img:{33f8a242-7c33-4bb2-90c5-8425a68cc5bf}{45}" ... />

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>'
}
]

Supported elements and actions


Many elements on the page can be updated, but each element type supports specific
actions. The following table shows supported target elements and the update actions
that they support.

Element Replace Append child Insert sibling

body no yes no
(targets first div on the page)

div no yes no
(absolute positioned)

div yes yes yes


(within a div) (id only)

img, object yes no yes


(within a div)

ol, ul yes yes yes


(id only)

table yes no yes


(id only)
Element Replace Append child Insert sibling

p, li, h1-h6 yes no yes


(id only)

title yes no no

The following elements do not support any update actions.

img (absolute positioned)


object (absolute positioned)
tr, td
meta
head
span
a
style tags

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 child elements


Insert sibling elements
Replace elements
Complete PATCH requests

Append child elements


The append action adds a child to a body, div (within a div), ol, or ul element. The
position attribute determines whether to append the child before or after the target.
The default position is after.

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>'
}
]

Append to the body element


You can use the body shortcut to append a child element inside the first div on any
page.

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 sibling elements


The insert action adds a sibling to the target element. The position attribute determines
whether to insert the sibling before or after the target. The default position is after. See
elements that support insert.

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>'
}
]

Change the title


This example shows how to change the title of a page. To change the title, use the title
keyword as the target value. Don't use a # with the title target.
JSON

[
{
'target':'title',
'action':'replace',
'content':'New title'
}
]

Update a to-do item

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.

Complete PATCH request examples


The following examples show complete PATCH requests.

Request with text content only

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>'
}
]

Multipart request with binary content


The following example shows a multipart PATCH request that includes binary data.
Multipart requests require a "Commands" part that specifies the application/json
content type and contains the array of JSON change objects. Other data parts can
contain binary data. Part names typically are strings appended with the current time in
milliseconds or a random GUID.

HTTP

PATCH https://graph.microsoft.com/v1.0/me/onenote/notebooks/pages/{page-
id}/content

Content-Type: multipart/form-data; boundary=PartBoundary123


Authorization: Bearer {token}

--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

... binary image data ...


--PartBoundary123--

Request and response information for PATCH


requests
Request Description
data

Protocol All requests use the SSL/TLS HTTPS protocol.

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.

Constructing the Microsoft Graph service root URL


The OneNote service root URL uses the following format for all calls to the OneNote API:

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

You can get user ids by making a GET request on


https://graph.microsoft.com/v1.0/users .

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

Applies to Consumer notebooks on OneDrive | Enterprise notebooks on Microsoft 365

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.

Use img to render an image on the page.


Use iframe to embed a video on the page.
Use object to add a file attachment to 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.

Add a public image from the web

Use img with src="https://image-url" and specify the URL of a publicly accessible
image. Renders the image on the OneNote page.

Add an image using binary data

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.

Add a webpage snapshot

Use img with data-render-src="https://webpage-url" and specify the URL of a


webpage. Renders a snapshot of the whole webpage on the OneNote page.

Add an image rendered from HTML

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.

Add images of PDF file contents

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

Use object with data="name:file-block-name" data-attachment="file-name.file-ext"


type="media-type" and send an image file in the data part of a multipart request. Adds a

file attachment to the OneNote page and displays a file icon.

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.

Image media types

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.

Add a public image from the web


In the input HTML of your request, include <img src="https://..." /> and specify the
URL of a publicly accessible image for the src attribute.

HTML

Content-Type: multipart/form-data; boundary=MyAppPartBoundary


Authorization: Bearer {access-token}
--MyAppPartBoundary
Content-Disposition: form-data; name="Presentation"
Content-Type: text/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--

Add an image using binary data


In the input HTML of your request's Presentation part, include <img src="name:part-
name" /> , where part-name is the unique identifier for the data part in your multipart

request that contains the binary image data. Just send the binary data, don't use Base64
or otherwise encode it.

HTML

Content-Type: multipart/form-data; boundary=MyAppPartBoundary


Authorization: Bearer {access-token}

--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--

Add a webpage snapshot


You can use Microsoft Graph to snapshot entire webpages and insert them into new
pages. This method is useful to archive webpages or capture complex webpages that
have features that OneNote doesn't support (like some CSS).

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

Content-Type: multipart/form-data; boundary=MyAppPartBoundary


Authorization: Bearer {access-token}

--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--

Add an image rendered from HTML


When you pass the HTML as a data-block, be sure there is no active content that would
require user credentials, or a pre-loaded browser plug-in. The engine that Microsoft
Graph uses to render the HTML page into an image has no ability to log in a user, and
doesn't include plug-ins like Adobe Flash, Apple QuickTime, and so on. That also means
that dynamically-loaded content, such as might come with an AJAX script, won't appear
if getting the data requires user login credentials or cookies.
In the input HTML of your request's Presentation part, include <img data-render-
src="name:part-name" /> , where part-name is the unique identifier for the data part in
your multipart request that contains the HTML.

HTML

Content-Type: multipart/form-data; boundary=MyAppPartBoundary


Authorization: Bearer {access-token}

--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--

Add an image file as an attachment


In the input HTML of your request's Presentation part, include <object
data="name:part-name" data-attachment="file-name.file-ext" type="media-type/media-
subtype" /> , where part-name is the unique identifier for the data part in your multipart

request that contains the binary image data. Just send the binary data, don't use Base64
or otherwise encode it.
HTML

Content-Type: multipart/form-data; boundary=MyAppPartBoundary


Authorization: Bearer {access-token}

--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

... binary file data ...

--MyAppPartBoundary--

Learn more about file media types.

Adding videos
You can embed videos in OneNote pages using <iframe data-original-
src="https://..." /> in the input HTML.

Supported video sites


Dailymotion
Office Mix
Sway
Sketchfab
TED
YouTube
Vimeo
Vine

iframe attributes

data-original-src

Required. The URL of the video.

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

Content-Type: multipart/form-data; boundary=MyAppPartBoundary


Authorization: Bearer {access-token}

--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.

Add a file attachment

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.

Add images of PDF file contents

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

The file name and extension to display on the OneNote page.

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.

Add a file attachment


In the input HTML of your request's Presentation part, include <object
data="name:part-name" data-attachment="file-name.file-ext" type="media-type/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

Content-Type: multipart/form-data; boundary=MyAppPartBoundary


Authorization: Bearer {access-token}

--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

... binary file data ...

--MyAppPartBoundary--

Add images of PDF file contents


In the input HTML of your request's Presentation part, include <img data-render-
src="name:part-name" ... /> , 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

Content-Type: multipart/form-data; boundary=MyAppPartBoundary


Authorization: Bearer {access-token}

--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

... binary file data ...

--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.

When to use HTML versus data-render-src


When trying to decide between putting HTML directly onto the OneNote page instead
of using the data-render-src attribute, consider the following:

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.

Permissions for POST pages


Notes.Create
Notes.ReadWrite
Notes.ReadWrite.All

Permissions for PATCH pages


Notes.ReadWrite
Notes.ReadWrite.All

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.

Attributes and positioning behavior


Use the data-absolute-enabled and style attributes to create absolute positioned
elements on a page, as follows:

The body element must specify data-absolute-enabled="true" . If omitted or set to


false , all body content is rendered inside a _default absolute positioned div that

the API creates, and all position settings are ignored.

Only div , img , and object elements can be absolute positioned elements.

Absolute positioned elements must specify style="position:absolute" .

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.

Absolute positioned elements cannot be nested or contain positioned elements.


The API ignores any position settings specified on nested elements inside an
absolute positioned div, renders the nested content inside the absolute positioned
parent div, and returns a warning in the api.diagnostics property in the response.

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

<body data-absolute-enabled="true" style="font-family:Calibri;font-


size:11pt">
<div data-id="_default"
style="position:absolute;left:48px;top:120px;width:624px">
<p>This content will appear in the _default div.</p>
<p>This content will also appear in the _default div.</p>
</div>
<div data-id="div1"
style="position:absolute;left:99px;top:174px;width:624px">
<p>This content will appear in an absolute positioned div.</p>
</div>
</body>

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.

Supported CSS style attributes


All absolute positioned elements can specify top and left positions. Divs and images can
specify width, and images can also specify height. For example:

HTML

<img style="position:absolute;top:140px;left:95px;width:480px;height:665px"
src="..." />

Attribute Supported Description


element

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

width div, img The width of the element, in pixels only.

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.

Permissions for POST pages

Notes.Create
Notes.ReadWrite
Notes.ReadWrite.All

Permissions for PATCH pages


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

Applies to Consumer notebooks on OneDrive | Enterprise notebooks on Microsoft 365

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:

<link rel="canonical" href="www.domainname.com/page/123/size12/type987" />

data-render-method
The extraction method to run. Required.

Value Description

extract.businesscard A business card extraction.


Value Description

extract.recipe A recipe extraction.

extract.product A product listing extraction.

extract An unknown extraction type.

For best results, specify the content type ( extract.businesscard , extract.recipe , or


extract.product ) if you know it. If the type is unknown, use the extract method, and

the OneNote API will try to auto-detect the type.

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.

none Does nothing.

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.

Business card extractions


The OneNote API tries to find and render the following contact information based on an
image of a person's or company's business card.

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.

Common scenarios for business card extractions

Extract business card information, and also render the business


card image
Specify the extract.businesscard method and the none fallback. Also send an img
element with the src attribute that also references the image. If the API is unable to
extract any content, it renders the business card image only.

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" />

Extract business card information, and render the business card


image only if the extraction fails
Specify the extract.businesscard method and use the default render fallback. If the API
is unable to extract any content, it renders the business card image instead.

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.

Common scenarios for recipe extractions


Extract recipe information, and also render a snapshot of the recipe
webpage

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/" />

Extract recipe information, and render a snapshot of the recipe


webpage only if the extraction fails

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>

Extract recipe information, and also render a link to the recipe


Specify the extract.recipe method and the none fallback. Also send an a element with
the src attribute set to the recipe 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 recipe link is
rendered.

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>

Product listing extractions


Title
Rating
Primary image
Description
Features
Specifications

The API is optimized for products from many popular sites such as Amazon.com and
HomeDepot.com.

Common scenarios for recipe extractions

Extract product information, and also render a snapshot of the


product webpage

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" />

Extract product information, and render a snapshot of the product


webpage only if the extraction fails
Specify the extract.product method and use the default render fallback. If the API is
unable to extract any content, it renders a snapshot of the product webpage instead.

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>

Extract product information, and also render a link to the product

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,

this can help to optimize the extraction results.

Common scenarios for unknown extractions

Send an image or a URL, and render the supplied image or a


snapshot of the webpage if the extraction fails
Specify the extract method so the API automatically detects the content type, and use
the default render fallback. If the API is unable to extract any content, it renders the
supplied image or snapshot of the webpage instead.

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.

Permissions for POST pages


Notes.Create
Notes.ReadWrite
Notes.ReadWrite.All

Permissions for PATCH pages


Notes.ReadWrite
Notes.ReadWrite.All

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

Applies to Consumer notebooks on OneDrive | Enterprise notebooks on Microsoft 365

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.

Note tag attributes


In the HTML of a OneNote page, a note tag is represented by the data-tag attribute.
For example:

An unchecked to-do box: <p data-tag="to-do">

A checked to-do box: <p data-tag="to-do:completed">

A star: <h2 data-tag="important">

A data-tag value is composed of a shape, and sometimes a status (see all supported
values).

Property Description

shape The identifier of the note tag (example: to-do or important ).

status The status of check box note tags. This is used only to set check boxes as completed.

Add or update note tags


To add or update a built-in note tag, just use the data-tag attribute on a supported
element. For example, here's a paragraph marked as important:

HTML

<p data-tag="important">...</p>
Separate multiple note tags with commas:

HTML

<p data-tag="important, critical">...</p>

You can define a data-tag on the following elements:

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

<p data-tag="to-do:completed" data-id="prep">Till garden bed</p>


<p data-tag="to-do" data-id="spring">Plant peas and spinach</p>
<p data-tag="to-do" data-id="summer">Plant tomatoes and peppers</p>

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.

Note tags on lists


Here are some guidelines for working with note tags on lists:

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:

The data-tag setting for a ul or ol overrides all settings on child li elements.


This applies even when the ul or ol doesn't specify a data-tag but its child li
elements do.

For example, if you create a ul or ol that defines data-tag="project-a" , all its


list items will display the Project A note tag. Or if the ul or ol doesn't define a
data-tag , none of its items will display a note tag. This override happens

regardless of any explicit settings on child li elements.

Unique data-tag settings are honored for list items under the following
conditions:

The li elements are not nested in a ul or ol in a create or update request.

An li element is individually addressed in an update request.

Unnested li elements sent in input HTML are returned in a ul in the output


HTML.

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>

Retrieve note tags


Built-in note tags are included in the output HTML when you get page content:

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

<h1 style="...">Status meeting</h1>


<p data-tag="important">Next week's meeting has been moved to <span
style="font-weight:bold">Wednesday</span>.</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>
<li><span data-tag="critical">Design handouts</span></li>
<li><span data-tag="critical">Plan keynote</span></li>
</ul>

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.

Built-in note tags for OneNote


OneNote includes the following built-in note tags:

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.

Permissions for POST pages


Notes.Create
Notes.ReadWrite
Notes.ReadWrite.All

Permissions for PATCH pages


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
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.

Background color is not currently supported for the body element.

Output attributes

Output attribute Description


Output attribute Description

data-absolute- Indicates whether the body supports absolute positioned elements. Always
enabled true in output HTML.

style The font-family and font-size properties of the body.

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-id A reference for the element.

Used to update page content.

data- The fallback action if the extraction fails: render (default) or none
render-
fallback

data- The extraction method to perform, for example:


render- extract.businesscard or extract.recipe
method

data- The content source for the extraction.


render-src

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" .

Example: <div style="position:absolute;width:360px;top:350px;left:300px"


... />
The CSS style properties of the element. In the output HTML, these values are
returned inline on appropriate child elements.

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

data-id A reference for the element.

Used to update page content.

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.

Used to update page content.

style The position and size properties of the div.

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

<html htmlns="https://www.w3.org/1999/xhtml" lang="en-US">


<head>
<title>Page Title</title>
</head>
<body data-absolute-enabled="true" style="font-family:Calibri;font-
size:11px">
<div data-id="_default"
style="position:absolute;left:48px;top:120px;width:624px">
<p>Some text</p>
<p>More text inside a nested div</p>
</div>
</body>
</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

alt The supplied alt text for the image.


Input Description
attribute

data-id A reference for the element.

Used to update page content.

data- Either data-render-src or src is required.


render-
src The webpage to render as a bit-mapped image on the OneNote page:

- data-render-src="https://..." for a public URL.

- data-render-src="name:BlockName" for an image part in the "Presentation" block of a


multipart request.

This method is useful when the webpage is more complex than the OneNote page
can faithfully render, or when the page requires login credentials.

data-tag A note tag on the element.

style The position and size properties for the image: position (absolute only), left, top,
width, and height.

Size can be set on any image.

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" .

Example: <img style="position:absolute;width:360px;top:350px;left:300px" ... />

In the output HTML, the image size is returned separately in width and height
attributes.

src Either src or data-render-src is required.

The image to render on the OneNote page:

- src="https://..." for a URL to a publicly available image on the Internet.

- src="name:BlockName" for a named part in a multipart request that represents the


image.

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

alt The supplied alt text for the image.

data-id A reference for the element.

Used to update page content.

data-index The position of the image. For split image support.

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

data-tag A note tag on the element.

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.

Used to update page content.

src The endpoint for the version of the image resource that has been optimized for
web browsers and mobile and tablet form factors.

style The position properties of the image.

width, The width or height of the image, in pixels.


height

Output HTML examples for images


Output img elements contain endpoints for image file resources and the image type, as
shown below. You can make separate GET requests to image resource endpoints to
retrieve their binary contents.

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.

Image with web-ready and high resolution resources

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="..."] />

Image created by using the data-render-src attribute

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.

Split image with three component images

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

You can also attach a video file using an object element.

Input attributes

Input attribute Description

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

Output attribute Description

data-original-src The URL of the video source.

src A link to the video that is embedded in the OneNote page.

width, height The width or height of the iframe, in pixels.

Example: width=300

Output HTML example for videos


Output iframe elements contain endpoints that link to the source page and video, as
shown.

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.

data- Required. The file name.


attachment

data-id A reference for the element.

Used to update page content.

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" .

Example: <object style="position:absolute;top:350px;left:300px" ... />

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

data The endpoint for the file resource.


Output Description
attribute

data- The file name.


attachment

data-id A reference for the element.

Used to update page content.

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.

Used to update page content.

style The position properties of the object.

type The standard media file type.

Output HTML example for objects


Output object elements contain endpoints that link to the file resources in the page, as
shown. You can make separate GET requests to file resource endpoints to retrieve their
binary contents.

HTML

<object
data="https://graph.microsoft.com/v1.0/me/onenote/resources/{file-
id}/$value"
data-attachment="fileName.pdf"
type="application/pdf"
[style="..."] />

Paragraphs and headings


Paragraphs, headings, and other text containers can contain the following attributes in
the input and output HTML.

Input attributes

Input attribute Description


Input attribute Description

data-id A reference for the element.

Used to update page content.

data-tag A note tag on a p or h1 - h6 element.

style The CSS style properties of the element.

Output attributes

Output Description
attribute

data-id A reference for the element.

Used to update page content.

data-tag A note tag on a p or h1 - h6 element.

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.

Used to update page content.

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

<h1>Heading <i>One</i> text</h1>


<p style="font-size:8pt;color:green;font-family:Courier;text-
align:center">Some text</p>
<p>Some <span style="font-size:16px;color:#ff0000;font-family:Segoe UI
Black">more</span> text</p>

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

Input attribute Description

data-id A reference for the element.

Used to update page content.

data-tag A note tag on a ul, ol, or li element.

style The list-style-type and the CSS style properties for the list or list item.

Output attributes

Output Description
attribute

data-id A reference for the element.

Used to update page content.

data-tag A note tag on a span in an li element.

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.

Used to update page content.


Output Description
attribute

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:

Ordered list Unordered list

none none

decimal (default) disc (default)

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.

Homogenous list style


This example shows input HTML that sets the list style type on the ol element and CSS
styles on individual list items.

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>

Variable list styles


This example shows input HTML that sets different list style types on the li elements.

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

data-id A reference for the element.

Used to update page content.

style The CSS style properties of the element, and also:


- width. Supported by table and td as pixels or percentage of page width.

Example: width="100px" or width="60%"

border Adds border to table with specified width

width Width of the table

bgcolor The background color of the table

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

data-id A reference for the element.

Used to update page content.

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.

Used to update page content.

style The CSS style properties of the element.

The following examples show input HTML that uses different ways to define styles on
tables and the output HTML that's returned.

Input HTML with optional settings at different levels

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>

Output HTML with CSS styles returned inline on the td elements

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

background- style="background-color:#66cc66" (defaults to white)


color
Both hexadecimal format and named colors are supported.

color style="color:#ffffff" (defaults to black)

font-family style="font-family:Courier" (defaults to Calibri)


Property Example

font-size style="font-size:10pt" (defaults to 11pt)

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.

font-style style="font-style:italic" (normal or italic only)

font-weight style="font-weight:bold" (normal or bold only)

strike- style="text-decoration:line-through"
through

text-align style="text-align:center" (for block elements only)

text- style="text-decoration:underline" (none or underline only)


decoration

The following inline character styles are also supported:

<b> <i> <u>

<em> <strong> <strike>

<sup> <sub> <del>

<cite>

Input and output HTML example


The following image shows a simple page that was created with Microsoft Graph.
This is the input HTML sent in the message body to create the page.

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

<html htmlns="https://www.w3.org/1999/xhtml" lang="en-US">


<head>
<title>Sample Study Notes</title>
</head>
<body data-absolute-enabled="true" style="font-family:Calibri;font-
size:11pt">
<div data-id="_default"
style="position:absolute;left:48px;top:120px;width:624px">
<h1 style="font-size:16pt;color:#1e4e79;margin-top:11pt;margin-
bottom:11pt">American History 101: Moon Landing</h1>
<p>First moon landing - July 20, 1969 with Apollo 11 (Eagle)</p>
<br />
<p><span style="font-weight:bold">Apollo 11 Astronauts</span>
</p>
<table style="border:0px">
<tr>
<td style="border:0px">Neil Armstrong</td>
<td style="border:0px">Commander</td>
</tr>
<tr>
<td style="border:0px">Buzz Aldrin</td>
<td style="border:0px">LM Pilot</td>
</tr>
<tr>
<td style="border:0px">Michael Collins</td>
<td style="border:0px">Command Module Pilot</td>
</tr>
</table>
<br />
<img alt="Apollo 11 commemorative stamp." width="400"
height="248" src="https://graph.microsoft.com/v1.0/me/onenote/resources/0-
f717b5fa5eaa454da7ecdf72a8c137fe!1-73DBAF9B7E5C4B4C!10456/$value"
data-src-type="image/jpeg" data-fullres-
src="https://graph.microsoft.com/v1.0/me/onenote/resources/0-
f717b5fa5eaa454da7ecdf72a8c137fe!1-73DBAF9B7E5C4B4C!10456/$value" data-
fullres-src-type="image/jpeg" />
<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>
</div>
</body>
</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.

Use $select to select the minimum set of


properties you need
When you query for a resource (for example, sections inside a notebook), you make a
request similar to the following.

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

The same approach applies to other OneNote APIs.

Use $expand instead of making multiple API


calls
Suppose you want to retrieve all of the user’s notebooks, sections, and section groups in
a hierarchical view. You might accomplish that by doing the following:

Call GET ~/notebooks to get the list of notebooks.

For every retrieved notebook, call GET ~/notebooks/{notebookId}/sections to


retrieve the list of sections.
For every retrieved notebook, call GET ~/notebooks/{notebookId}/sectionGroups to
retrieve the list of section groups.

Optionally recursively iterate through section groups.

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.

When getting all pages for a user, do so for


each section separately
While Microsoft Graph exposes an endpoint to retrieve all pages, this isn't the best way
to get all the pages the user has access to. When the user has too many sections, this
can lead to timeouts or bad performance. It is better to iterate each section, getting
pages for each one separately.

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

When getting page metadata, override the default lastModifiedDateTime ordering. It is


faster to get pages when you don't have to sort them by lastModifiedDateTime . To do
this, you can sort by any other property; for example:

HTTP
GET ~/sections/{id}/pages?
$select=id,title,createdDateTime&$orderby=createdDateTime
Branding guidelines for OneNote API
developers
Article • 06/25/2022

Applies to Consumer notebooks on OneDrive | Enterprise notebooks on Microsoft 365

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 and name lockup (preferred)


The icon symbol is locked with the name. This is the preferred graphic representation of
the OneNote logo.

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

Print: 5 mm (0.2 inches)


Color
When the OneNote logo is used on white or light backgrounds, the preferred logo color
is purple—its brand color. When it appears on a purple background, the logo should be
knocked out to white.

Screen: R128 G57 B123 or Hex #80397B

Print: C75 M100 Y0 K0

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

Don’t change the scale or the proportions


Don’t use a drop shadow

Don’t change the color, except to black or white (see Color)

Don’t rotate the logo or icon

Don’t rearrange the logo elements


Don’t use an effect such as extrude and bevel

Don’t create a new logo or icon

Referencing the OneNote name


Full name: Microsoft OneNote

Short name: OneNote

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).

Example: Proseware for 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.

Indicating Recommended: Send to OneNote


interoperability
with OneNote Acceptable: Share with OneNote
Acceptable when used in reference to "sharing" with other applications—for
example, Share with OneNote, Facebook, or Twitter.)

Never: Save to OneNote


This is technically incorrect.

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.

Error response example


When your request generates an error, the OneNote API stops performing the request
and returns an error response as a JSON object. An error response contains the
associated error code, a message, and a link to the appropriate section of this article.
The following example shows how an error response looks.

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.

Codes from 10001 to 19999


The service is having problems or is sending information to the application.

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.

Codes from 20001 to 29999


The application code has done something wrong.

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

<p data-tag="to-do:completed">To-do note tag in completed state (checked


box in the UI)</p>

See Use note tags.

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.

For more information, see Microsoft Graph service-specific throttling guidance.

20168
The video source specified in the request is not supported. See Supported video sites
for the current list.

Codes from 30001 to 39999


Something is wrong with the user's account.

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's personal site is Try the request later.


currently being
provisioned.

The user does not have a The user should contact their Microsoft 365 tenant administrator.
valid OneDrive for
Business license.

A network issue prevented Try the request later.


the request from being
successfully sent.

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.

Codes from 40001 to 49999


The user or application does not have the correct permissions.

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.

Effortlessly target your user for notification delivery


across different endpoints
You can use the notifications API to target a personal Microsoft account or a work or
school Azure Active Directory (Azure AD) account to deliver notifications. The platform
distributes this notification to all user endpoints running your application or service,
including Windows UWP, iOS, Android, and web endpoints. This capability helps
maximize outreach by ensuring appropriate notifications can reach your target,
wherever they are.

Easily manage notifications across endpoints


Using the new and improved notifications client SDK within your client application,
you can update the state of a notification and sync that state across all endpoints. For
example, when a user acts on a notification on one device, you can update the state of
this notification (such as marking it as read or dismissed), and the same state change will
be distributed to all other endpoints. The Microsoft Graph notifications API tracks the
state of your user's notifications in a centralized way, making it easy for you to ensure
that your notifications are handled once, and dismissed everywhere, thereby minimizing
redundancy and ensuring a great customer experience.

Retrieve notification state and history


You can use the notifications API to retrieve notification history based on an expiration
time you define (up to 30 days). Notifications that are marked as read or dismissed are
still retrievable from the history, enabling in-app views of notification history as well as
enabling you to build on insights and intelligence.

Guaranteed delivery for high-priority notifications


On platforms like iOS, under certain power conditions, raw data notifications might be
delayed in delivery due to batching, or not reach the target endpoint at all. For high-
priority notifications being delivered to users on iOS, the Microsoft Graph notifications
platform allows you to specify a raw-to-visual toast notification "fallback" option that
automatically sends a visual toast notification to the target iOS device, thereby ensuring
your user gets notified near real-time.

Privacy and compliance


Our push-to-pull model ensures that notifications never leave trusted boundaries.
Platform-specific push services are used to send a shoulder-tap to your user's device
and from there, the client SDK securely fetches the corresponding payload from the
Microsoft Graph notifications service. We meet most enterprise compliance
requirements, including ISO 27001, ISO 27018, EUMC, HIPAA, FERPA, SOC 1, SOC 2, and
of course GDPR.

How do I get started?


To get started, see the integration overview section to learn how you can integrate user-
centric notifications within your application.

API reference
Looking for the API reference for this service?

Use the notifications REST API in Microsoft Graph


Integrate with 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) .

You can integrate your apps with Microsoft Graph notifications with a few simple steps,
as shown in the following diagram.

1. Register your application in the Microsoft Azure portal.

2. Onboard to Partner Center/Windows Dev Center for cross-platform application


identity and push notification credentials for Windows, iOS, and Android.

3. Set up your app server to send notifications via Microsoft Graph.

4. Integrate the new notifications client SDK into your Windows, iOS, Android, or
web clients to receive and manage notifications.

7 Note

We recommend using the new and improved, lightweight notification SDK


instead of the cross-device Project Rome SDK .
Manage app registration and API
permission 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) .

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.

Register your app to support Microsoft


accounts or work or school accounts
Register your application on the Microsoft Azure portal to support Microsoft accounts
or work or school accounts. If you’ve previously registered your application on the
Microsoft Application Portal , your existing apps will show up in the new and improved
Azure portal experience.

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.

App certificates and secrets


To enable your application to identify and authenticate itself when obtaining auth
tokens, you can either upload your own certificate or create a new client secret by going
to Certificates & secrets in the Azure portal.

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:

User.Read - allows your application to sign-in your user

UserActivity.ReadWrite.CreatedByApp - allows app subscription for notification


retrieval

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:

1. On the left menu, go to Cross-Device Experiences, select Configuring a new


cross-device app, and provide your app name, as shown in the following
screenshot.

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.

6. Verify your cross-device app domain, which serves as a verification process to


prove that your application has ownership of this domain. This acts like a cross-
device app identity for the application or applications you registered, as shown.

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.

In order to send a notification to your user, your application service will:

1. Authenticate with the Microsoft identity platform.


2. Post a notification to the Microsoft Graph API using the auth token, and target the
user with a user notification subscription ID that is obtained from your app client
when creating a subscription.

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.

Guaranteed delivery on iOS


On platforms like iOS, under certain power conditions, raw data notifications might be
delayed in delivery due to batching, or not reach the target endpoint at all. For high-
priority notifications being delivered to users on iOS, the Microsoft Graph notifications
platform allows you to specify a raw-to-visual toast notification "fallback" option that
automatically sends a visual toast notification to the target iOS device, thereby ensuring
your user gets notified near real-time. To learn how to leverage fallback options, please
see the notification resource.

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.

New incoming notification flow


For receiving new incoming notifications, the data flow is shown in the following
diagram.
The process involves a few components:

App server - The back end of your application


App client - The front end of your application (a UWP app, an Android app, or an
iOS app)
Microsoft Graph notifications - The service component that enables user
notifications to be published, stored, and synced across different instances of app
clients across devices and platforms
WNS - The Windows push notification service that Microsoft Graph notifications
uses to signal the clients

The diagram shows the following steps:

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.

Notification update flow


One of the main benefits for using Microsoft Graph notifications is that it persists
notifications in the cloud securely and turns them into a stateful resource type.
Therefore, it can help your application to manage and sync the correct state of the
notifications across different devices for the same signed in user in a cross-device
scenario. When a notification is marked as dismissed, or marked as read on one device,
the other devices can be notified in real-time. "Handled once, dismissed everywhere"
can become a true promise as part of the notification experience for your users.

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.

The diagram shows the following steps:

1. Application logic. Something triggers the notification to be changed or deleted. In


general, any event can trigger a notification to change.
2. App calling into the client SDK to update or delete a notification. Currently, we
expose two properties regarding state changes - userActionState and readState -
but your application can define these states and when they need to be updated.
For example, when a user dismisses the notification popup, you can update the
userActionState to be Dismissed. When a user clicks the notification popup and
launches the app to consume corresponding app content, you can update the
userActionState to be Activated and update the readState to be Read.
3. After the corresponding API is called to update or delete a notification, the SDK
will call into the user notification store in the cloud in order to fan-out this change
to the other app client instances with the same signed in user.
4. On receiving the update/delete request from a client, Microsoft Graph notifications
will update the notification store, and identify the other app client instances that
subscribed to this change.
5. For each app client subscription, Microsoft Graph notifications sends a signal to
notify the app client, via the native push service provided by the operating system.
In this case, this is a UWP app on Windows, and it uses WNS push raw notification
to send the signal.
6. After the application is signaled by the incoming push notification, it asks the SDK
to fetch for the changes in the user notification store.
7. The SDK establishes a secure and compliant connection with the user notifications
store in Microsoft Graph.
8. The SDK gets the data changes - in this case, the changes are notification state
updates or notification deletions.
9. The SDK fires event callbacks to notify the app after the changes are successfully
retrieved.
10. 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, because there are notification updates, the app should update the UI locally
to reflect the state change. For example, if a notification is marked as activated,
you can remove the corresponding toast notification popup inside Windows action
center to achieve "handled once, dismissed everywhere".
For more information about Microsoft Graph notifications, see Microsoft Graph
Notifications overview. For more information about the steps required to integrate with
Microsoft Graph notifications from end to end, see Microsoft Graph notifications
integration overview.

Adding the SDK to your project


On Windows, the client-side SDK is a NuGet package that ships outside of the Windows
operating system. This API is available in C#, C++, and WinJS.

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….

Go to the Browse tab, and search for Microsoft.ConnectedDevices.UserNotifications.


You will see the Microsoft Graph notifications client-side SDK in the search results. Click
the Install button to install it.

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:

Use packages from nuget.org


Quickstart: Install and use a package in Visual Studio

Initializing the Connected Device Platforms


The client-side SDK is built on top of an infrastructure called Connected Device Platform.
Before you can use any features, the platform must be initialized within your app. The
initialization steps should occur in your main class OnLaunched or onActivated method,
because they are required before the notification scenarios can take place.

You must construct and initialize the platform by instantiating the


ConnectedDevicesPlatform class. Before doing that, make sure to hook up event
handlers, as shown, because after platform is started, the events might begin to fire.

C#

var platform = new ConnectedDevicesPlatform();


platform.AccountManager.AccessTokenRequested +=
AccountManager_AccessTokenRequestedAsync;
platform.AccountManager.AccessTokenInvalidated +=
AccountManager_AccessTokenInvalidated;
platform.NotificationRegistrationManager.NotificationRegistrationStateChange
d += NotificationRegistrationManager_NotificationRegistrationStateChanged;
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.

AccountManager_AccessTokenRequestedAsync
For a full implementation, see the Windows app sample .

C#

private async void


AccountManager_AccessTokenRequestedAsync(ConnectedDevicesAccountManager
sender, ConnectedDevicesAccessTokenRequestedEventArgs args)
{
private List<Account> accounts = new List<Account>();
var account = accounts.Find((x) => x.EqualsTo(args.Request.Account));
if (account != null)
{
try
{
var accessToken = await
account.GetAccessTokenAsync(args.Request.Scopes);
args.Request.CompleteWithAccessToken(accessToken);
}
catch (Exception ex)
{
args.Request.CompleteWithErrorMessage(ex.Message);
}
}
}

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)}");
}

Handling push registration expiration


Microsoft Graph notifications uses WNS, the native push platform on Windows, to signal
the client application on user notifications data changes. This happens when new
incoming notifications are published from your app server, or when any notification's
state is updated on a different device with the same signed in user in a cross-device
scenario.

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

For a full implementation, see the Windows app sample .


C#

private async void


NotificationRegistrationManager_NotificationRegistrationStateChanged(Connect
edDevicesNotificationRegistrationManager sender,
ConnectedDevicesNotificationRegistrationStateChangedEventArgs args)
{
if ((args.State ==
ConnectedDevicesNotificationRegistrationState.Expired) || (args.State ==
ConnectedDevicesNotificationRegistrationState.Expiring))
{
var account = m_accounts.Find((x) => x.EqualsTo(args.Account));
if (account != null)
{
await account.RegisterAccountWithSdkAsync();
}
}
}

Signing in your user


Microsoft Graph notifications, like many other resource types inside Microsoft Graph,
are centralized around users. In order for your app to subscribe to and start receiving
notifications for the signed in user, you first need to obtain a valid OAuth token to be
used in the registration process. You can use your preferred method of generating and
managing the OAuth tokens. The sample app uses ADAL.

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 .

Adding the user account to the platform


You need to register the signed in user account with the SDK. This involves adding the
account and registering a push channel to receive the initial push notifications through
WNS.

C#

var account = new ConnectedDevicesAccount(accountId, accountType);


var addResult = await platform.AccountManager.AddAccountAsync(account);
if (addResult.Status != ConnectedDevicesAccountAddedStatus.Success)
{
throw new Exception("Add account failed with " + addResult.Status +
"!");
}

var pushChannel = await


PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAs
ync();
ConnectedDevicesNotificationRegistration registration = new
ConnectedDevicesNotificationRegistration();
registration.Type = ConnectedDevicesNotificationType.WNS;
registration.Token = pushChannel.Uri;
var registerResult = await
platform.NotificationRegistrationManager.RegisterAsync(account,
registration);
if (registerResult.Status !=
ConnectedDevicesNotificationRegistrationStatus.Success)
{
throw new Exception("Register push channel failed with " +
registerResult.Status + "!");
}

Subscribing to receive user's notifications


You need to instantiate a UserDataFeed object for your application for this signed in
user. Your application is identified by the cross-platform app ID you provided during the
Cross-Device Experiences onboarding process.

C#

UserDataFeed feed = UserDataFeed.GetForAccount(account, platform,


"YOUR_HOST_HERE");

var scopes = new List<UserDataFeedSyncScope> {


UserNotificationChannel.SyncScope };
var subscribeResult = await feed.SubscribeToSyncScopesAsync(scopes);
if (!subscribeResult)
{
throw new Exception("Subsribe failed!");
}
var channel = new UserNotificationChannel(feed);
var reader = channel.CreateReader();
reader.DataChanged += Reader_DataChanged;

Receiving and managing user notifications


The flow diagram earlier in this topic shows that the programming patterns to handle a
new incoming notifications from an app server and a notification update or deletion
initiated from another app client instance are similar. The following are the steps for
handling these data changes.

Handling incoming push notification signal


All types of user notification data changes generate a signal that gets delivered to the
app clients as a push notification. For Windows UWP apps, the signal is delivered as a
WNS push raw notification. On receiving the raw push signal, the app should call
TryParse to trigger the SDK to fetch from the Microsoft Graph notifications service for
the actual data changes.

C#

public async Task ReceiveNotificationAsync(string content)


{
ConnectedDevicesNotification notification =
ConnectedDevicesNotification.TryParse(content);
if (notification != null)
{
await platform.ProcessNotificationAsync(notification);
}
}

Handling user notification data changes


After the SDK successfully fetches the data changes, an event callback is invoked and
the app client is expected to handle notification creation, update, or deletion.

C#

private async void Reader_DataChanged(UserNotificationReader reader, object


args)
{
var notifications = await reader.ReadBatchAsync(UInt32.MaxValue);

foreach (var notification in notifications)


{
// Handle notification changes based on change type;
}
}

Update state of a notification


If a notification state change is initiated from this app client instance (for example, if the
toast notification popup on this device is activated by the user), the app needs to call
the SDK to update the notification's state in order to have this state change synced
across all devices used by the same user.

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.

New incoming notification flow


For receiving new incoming notifications, the data flow is shown in the following
diagram.
he process involves a few components:

App server - The back end of your application


App client - The front end of your application (a UWP app, an Android app, or an
iOS app)
Microsoft Graph notifications - The service component that enables user
notifications to be published, stored, and synced across different instances of app
clients across devices and platforms
FCM - Firebase Cloud Messaging, the push notification service provided by
Android as a part of Google Play Services. Microsoft Graph notifications use this
service to signal the Android app clients about user notification data changes.

The diagram shows the following steps:

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.

Notification update flow


One of the main benefits for using Microsoft Graph notifications is that it persists
notifications in the cloud securely and turns them into a stateful resource type.
Therefore, it can help your application to manage and sync the correct state of the
notifications across different devices for the same signed in user in a cross-device
scenario. When a notification is marked as dismissed, or marked as read on one device,
the other devices can be notified in real-time. "Handled once, dismissed everywhere"
can become a true promise as part of the notification experience for your users.

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.

The diagram shows the following steps:

1. Application logic. Something triggers the notification to be changed or deleted. In


general, any event can trigger a notification to change.
2. App calling into the client SDK to update or delete a notification. Currently, we
expose two properties regarding state changes - userActionState and readState -
but your application can define these states and when they need to be updated.
For example, when a user dismisses the notification popup, you can update the
userActionState to be Dismissed. When a user clicks the notification popup and
launches the app to consume corresponding app content, you can update the
userActionState to be Activated and update the readState to be Read.
3. After the corresponding API is called to update or delete a notification, the SDK
will call into the user notification store in the cloud in order to fan-out this change
to the other app client instances with the same signed in user.
4. On receiving the update/delete request from a client, Microsoft Graph notifications
will update the notification store, and identify the other app client instances that
subscribed to this change.
5. For each app client subscription, Microsoft Graph notifications sends a signal to
notify the app client, via the native push service provided by the operating system.
In this case, this is an Android app, and it uses FCM data message to send the
signal.
6. After the application is signaled by the incoming push notification, it asks the SDK
to fetch for the changes in the user notification store.
7. The SDK establishes a secure and compliant connection with the user notifications
store in Microsoft Graph.
8. The SDK gets the data changes - in this case, the changes are notification state
updates or notification deletions.
9. The SDK fires event callbacks to notify the app after the changes are successfully
retrieved.
10. 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, because there are notification updates, the app should update the UI locally
to reflect the state change. For example, if a notification is marked as activated,
you can remove the corresponding notification message inside Android's
notification tray to achieve "handled once, dismissed everywhere".
For more information about Microsoft Graph notifications, see Microsoft Graph
Notifications overview. For more information about the steps required to integrate with
Microsoft Graph notifications from end to end, see Microsoft Graph notifications
integration overview.

Development environment and requirements


To use Microsoft Graph notifications, you will need an Android app development IDE
and an Android device with one of the supported architectures (armeabi-v7a, arm64-
v8a, x86, or x86_64) or an emulator. The system must be running Android 4.4.2 or later.

Adding the SDK to your project


Insert the following repository references into the build.gradle file at the root of your
project.

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

<uses-permission android:name="android.permission.INTERNET" />


<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

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;

Initializing the Connected Device Platforms


The client-side SDK is built on top of an infrastructure called Connected Device Platform.
Before any feature can be used, the platform must be initialized within your app. The
initialization steps should occur in your main class OnCreate method, because they are
required before the notification scenarios can take place.

You must construct and initialize the platform by instantiating the


ConnectedDevicesPlatform class. Before doing that, make sure to hook up event
handlers, because after the platform is started, the events might begin to fire.

Java

ConnectedDevicesPlatform platform = new ConnectedDevicesPlatform(context);

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

private void onAccessTokenRequested(ConnectedDevicesAccountManager sender,


ConnectedDevicesAccessTokenRequestedEventArgs args) {
ConnectedDevicesAccessTokenRequest request = args.getRequest();
List<String> scopes = request.getScopes();

// We always need to complete the request, even if a matching account is


not found
if (account == null) {
request.completeWithErrorMessage("The app could not find a matching
ConnectedDevicesAccount to get a token");
return;
}

// Complete the request with a token


account.getAccessTokenAsync(scopes)
.thenAcceptAsync((String token) -> {
request.completeWithAccessToken(token);
}).exceptionally(throwable -> {
request.completeWithErrorMessage("The Account could not return a
token with those scopes");
return null;
});
}

accessTokenInvalidated

For a full implementation, see the Android sample app .

Java
private void onAccessTokenInvalidated(ConnectedDevicesAccountManager sender,
ConnectedDevicesAccessTokenInvalidatedEventArgs args, List<Account>
accounts) {
Log.i(TAG, "Token invalidated for account: " +
args.getAccount().getId());
}

Handling push registration expiration


Microsoft Graph notifications uses FCM, the native push platform on Android, to signal
the client application on user notifications data changes. This happens when new
incoming notifications are published from your app server, or when any notification's
state is updated on a different device with the same signed in user in a cross-device
scenario.

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 .

Signing in your user


Microsoft Graph notifications, like many other resource types in Microsoft Graph, are
centralized around users. In order for your app to subscribe to and start receiving
notifications for the signed in user, you first need to obtain a valid OAuth token to be
used in the registration process. You can use your preferred method of generating and
managing the OAuth tokens. The sample app used ADAL.

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 .

Adding the user account to the platform


You need to register the signed in user account with the SDK, which involves adding the
account and registering a push channel in order to receive the initial push notifications
through FCM.

Java

public AsyncOperation<Boolean> prepareAccountAsync(final Context context) {


// Accounts can be in 3 different scenarios:
// 1: cached account in good standing (initialized in the SDK and our
token cache).
// 2: account missing from the SDK but present in our cache: Add and
initialize account.
// 3: account missing from our cache but present in the SDK. Log the
account out async

// Subcomponents (e.g. UserDataFeed) can only be initialized when an


account is in both the app cache
// and the SDK cache.
// For scenario 1, initialize our subcomponents.
// For scenario 2, subcomponents will be initialized after
InitializeAccountAsync registers the account with the SDK.
// For scenario 3, InitializeAccountAsync will unregister the account
and subcomponents will never be initialized.
switch (mState) {
// Scenario 1
case IN_APP_CACHE_AND_SDK_CACHE:
mUserNotificationsManager = new
UserNotificationsManager(context, mAccount, mPlatform);
return registerAccountWithSdkAsync();
// Scenario 2
case IN_APP_CACHE_ONLY: {
// Add the this account to the
ConnectedDevicesPlatform.AccountManager
return
mPlatform.getAccountManager().addAccountAsync(mAccount).thenComposeAsync((Co
nnectedDevicesAddAccountResult result) -> {
// We failed to add the account, so exit with a failure to
prepare bool
if (result.getStatus() !=
ConnectedDevicesAccountAddedStatus.SUCCESS) {
result.getStatus());
return AsyncOperation.completedFuture(false);
}

// Set the registration state of this account as in both app


and sdk cache
mState =
AccountRegistrationState.IN_APP_CACHE_AND_SDK_CACHE;
mUserNotificationsManager = new
UserNotificationsManager(context, mAccount, mPlatform);
return registerAccountWithSdkAsync();
});
}
// Scenario 3
case IN_SDK_CACHE_ONLY:
// Remove the account from the SDK since the app has no
knowledge of it
mPlatform.getAccountManager().removeAccountAsync(mAccount);
// This account could not be prepared
return AsyncOperation.completedFuture(false);
default:
// This account could not be prepared
Log.e(TAG, "Failed to prepare account " + mAccount.getId() + "
due to unknown state!");
return AsyncOperation.completedFuture(false);
}
}

Java

public AsyncOperation<Boolean> registerAccountWithSdkAsync() {


if (mState != AccountRegistrationState.IN_APP_CACHE_AND_SDK_CACHE) {
AsyncOperation<Boolean> toReturn = new AsyncOperation<>();
toReturn.completeExceptionally(new IllegalStateException("Cannot
register this account due to bad state: " + mAccount.getId()));
return toReturn;
}

// Grab the shared GCM/FCM notification token from this app's


BroadcastReceiver
return
RomeNotificationReceiver.getNotificationRegistrationAsync().thenComposeAsync
((ConnectedDevicesNotificationRegistration notificationRegistration) -> {
// Perform the registration using the NotificationRegistration
return
mPlatform.getNotificationRegistrationManager().registerAsync(mAccount,
notificationRegistration)
.thenComposeAsync((result) -> {
if (result.getStatus() ==
ConnectedDevicesNotificationRegistrationStatus.SUCCESS) {
Log.i(TAG, "Successfully registered account " +
mAccount.getId() + " for cloud notifications");
} else {
// It would be a good idea for apps to take a look at
the different statuses here and perhaps attempt some sort of remediation.
// For example, token request failed could mean that the
user needs to sign in again. An app could prompt the user for this action
// and retry the operation afterwards.
Log.e(TAG, "Failed to register account " +
mAccount.getId() + " for cloud notifications!");
return AsyncOperation.completedFuture(false);
}

return mUserNotificationsManager.registerForAccountAsync();
});
});
}

Subscribing to receive user's notifications


You need to instantiate a UserDataFeed object for your application for this logged in
user. Your application is identified by the cross-platform app ID you provided during the
Cross-Device Experiences onboarding.

Java

public UserNotificationsManager(@NonNull Context context, @NonNull


ConnectedDevicesAccount account, @NonNull ConnectedDevicesPlatform platform)
{
Context context = new Context;
UserDataFeed feed = UserDataFeed.getForAccount(account, platform,
Secrets.APP_HOST_NAME);
UserNotificationChannel channel = new UserNotificationChannel(feed);
UserNotificationReader reader = channel.createReader();
reader.dataChanged().subscribe((reader, aVoid) ->
readFromCache(reader));
}
}

Receiving and managing user notifications


The flow diagram earlier in this topic shows that the programming patterns to handle a
new incoming notifications from an app server and a notification update or deletion
initiated from another app client instance are similar. The following are the steps for
handling these data changes.

Handling incoming push notification signal


All types of user notification data changes generate a signal that gets delivered to the
app clients as a push notification. For Android apps, the signal is delivered as a FCM
push data message. On receiving the data message signal, the app should call TryParse
to trigger the SDK to fetch from the Microsoft Graph notifications service for the actual
data changes.

Java

public void onMessageReceived(RemoteMessage message) {


Map data = message.getData();
ConnectedDevicesNotification notification =
ConnectedDevicesNotification.tryParse(data);

if (notification != null) {
try {
ConnectedDevicesPlatform platform =
ConnectedDevicesManager.getConnectedDevicesManager(getApplicationContext()).
getPlatform();

// NOTE: it may be useful to attach completion to this async in


order to know when the notification is done being processed.
// This would be a good time to stop a background service or
otherwise cleanup.
platform.processNotificationAsync(notification);
} catch (Exception e) {
Log.e(TAG, "Failed to process FCM notification" +
e.getMessage());
}
}
}

Handling user notification data changes


After the SDK successfully completes fetching the data changes, an event callback is
invoked and the app client is expected to handle notification creation, update, or
deletion.

Java

private void readFromCache(final UserNotificationReader reader)


{
reader.readBatchAsync(Long.MAX_VALUE).thenAccept(notifications -> {
synchronized (this) {
for (final UserNotification notification : notifications) {
if (notification.getStatus() ==
UserNotificationStatus.ACTIVE) {
removeIf(mNewNotifications, item ->
notification.getId().equals(item.getId()));

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());
}

removeIf(mHistoricalNotifications, item ->


notification.getId().equals(item.getId()));
mHistoricalNotifications.add(0, notification);
} else {
removeIf(mNewNotifications, item ->
notification.getId().equals(item.getId()));
removeIf(mHistoricalNotifications, item ->
notification.getId().equals(item.getId()));
clearNotification(mContext.getApplicationContext(),
notification.getId());
}
}
}

});
}

Update state of a notification


If a notification state change is initiated from this app client instance (for example, if the
toast notification popup on this device is activated by the user), the app needs to call
the SDK to update the notification's state in order to have this state change synced
across all devices used by the same user.

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.

New incoming notification flow


For receiving new incoming notifications, the data flow is shown in the following
diagram.
The process involves a few components:

App server - The back end of your application


App client - The front end of your application (a UWP app, an Android app, or an
iOS app)
Microsoft Graph notifications - The service component that enables user
notifications to be published, stored, and synced across different instances of app
clients across devices and platforms
APNs - The Apple Push Notification Service provided by Apple for iOS apps.
Microsoft Graph notifications use this service to signal the iOS app clients about
user notification data changes.

The diagram shows the following steps:

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.

Notification update flow


One of the main benefits for using Microsoft Graph notifications is that it persists
notifications in the cloud securely and turns them into a stateful resource type.
Therefore, it can help your application to manage and sync the correct state of the
notifications across different devices for the same signed in user in a cross-device
scenario. When a notification is marked as dismissed, or marked as read on one device,
the other devices can be notified in real-time. "Handled once, dismissed everywhere"
can become a true promise as part of the notification experience for your users.

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.

The diagram shows the following steps:

1. Application logic. Something triggers the notification to be changed or deleted. In


general, any event can trigger a notification to change.
2. App calling into the client SDK to update or delete a notification. Currently, we
expose two properties regarding state changes - userActionState and readState -
but your application can define these states and when they need to be updated.
For example, when a user dismisses the notification popup, you can update the
userActionState to be Dismissed. When a user clicks the notification popup and
launches the app to consume corresponding app content, you can update the
userActionState to be Activated and update the readState to be Read.
3. After the corresponding API is called to update or delete a notification, the SDK
will call into the user notification store in the cloud in order to fan-out this change
to the other app client instances with the same signed in user.
4. On receiving the update/delete request from a client, Microsoft Graph notifications
will update the notification store, and identify the other app client instances that
subscribed to this change.
5. For each app client subscription, Microsoft Graph notifications sends a signal to
notify the app client, via the native push service provided by the operating system.
In this case, this is an iOS, and it uses APNs background update notification to
send the signal.
6. After the application is signaled by the incoming push notification, it asks the SDK
to fetch for the changes in the user notification store.
7. The SDK establishes a secure and compliant connection with the user notifications
store in Microsoft Graph.
8. The SDK gets the data changes - in this case, the changes are notification state
updates or notification deletions.
9. The SDK fires event callbacks to notify the app after the changes are successfully
retrieved.
10. 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, because there are notification updates, the app should update the UI locally
to reflect the state change. For example, if a notification is marked as activated,
you can remove the corresponding alert UI inside the iOS notification center to
achieve "handled once, dismissed everywhere".
For more information about Microsoft Graph notifications, see Microsoft Graph
Notifications overview. For more information about the steps required to integrate with
Microsoft Graph notifications from end to end, see Microsoft Graph notifications
integration overview.

Adding the SDK to your project


The simplest way to add the Connected Devices Platform to your iOS app is by using the
CocoaPods dependency manager. Go to your iOS project's Podfile and insert the
following entry:

ObjectiveC

platform :ios, "10.0"


workspace 'iOSSample'

target 'iOSSample' do
# Uncomment the next line if you're using Swift or would like to use
dynamic frameworks
# use_frameworks!

pod 'ProjectRomeSdk'

# Pods for iOSSample

7 Note

In order to consume CocoaPod, you must use the .xcworkspace file in your project.

Initializing the Connected Device Platforms


The client-side SDK is built on top of an infrastructure called Connected Device Platform.
Before any feature can be used, the platform must be initialized within your app. The
initialization steps should occur in your AppDelegate method, because they are
required before the notification scenarios can take place.

You must construct and initialize the platform by instantiating the


MCDConnectedDevicesPlatform class. efore doing that, make sure to hook up event
handlers, as shown, because after platform is started, the events might begin to fire.

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];

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 iOS sample app .

accessTokenInvalidated

For a full implementation, see the iOS sample app .

ObjectiveC
[platform.accountManager.accessTokenInvalidated
subscribe:^(MCDConnectedDevicesAccountManager* _Nonnull manager
__unused,
MCDConnectedDevicesAccessTokenInvalidatedEventArgs* _Nonnull
request) {
}];

Handling push registration expiration


Microsoft Graph notifications use APNs, the native push platform on iOS, to signal the
client application on user notifications data changes. This happens when new incoming
notifications are published from your app server, or when any notification's state is
updated on a different device with the same signed in user in a cross-device scenario.

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 .

Signing in your user


Microsoft Graph notifications, like many other resource types inside Microsoft Graph,
are centralized around users. In order for your app to subscribe to and start receiving
notifications for the signed in user, you first need to obtain a valid OAuth token to be
used in the registration process. You can use your preferred method of generating and
managing the OAuth tokens. The sample app uses ADAL.

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 .

Adding the user account to the platform


You need to register the signed in user account with the SDK. This involves adding the
account and registering a push channel to receive the initial push notifications through
APNs. For details, see the prepareAccountAsync method in the sample.

ObjectiveC

MCDConnectedDevicesPlatform* platform = [MCDConnectedDevicesPlatform new];


MCDConnectedDevicesAccount* mcdAccount = [MCDConnectedDevicesAccount new];

[platform.accountManager addAccountAsync:mcdAccount callback:adapter];

Subscribing to receive user's notifications


You need to instantiate a UserDataFeed object for your application for this signed in
user. Your application is identified by the cross-platform app ID you provided during the
Cross-Device Experiences onboarding process.

ObjectiveC

// Initialize the feed and subscribe for notifications


MCDUserDataFeed* feed = [MCDUserDataFeed getForAccount:account
platform:platform
activitySourceHost:APP_HOST_NAME];

NSArray<MCDUserDataFeedSyncScope*>* syncScopes = @[
[MCDUserNotificationChannel syncScope] ];
[feed subscribeToSyncScopesAsync:syncScopes
callback:^(BOOL success __unused, NSError* _Nullable error __unused)
{
// Start syncing down notifications
[feed startSync];
}];

Receiving and managing user notifications


The flow diagram earlier in this topic shows that the programming patterns to handle a
new incoming notifications from an app server and a notification update or deletion
initiated from another app client instance are similar. The following are the steps for
handling these data changes.

Handling incoming push notification signal


All types of user notification data changes generate a signal that gets delivered to the
app clients as a push notification. In the case of an iOS app, the signal is delivered as an
APNs background update notification. On receiving the data message signal, the app
should call TryParse to trigger the SDK to fetch from the Microsoft Graph notifications
service for the actual data changes.

ObjectiveC

// App running in background and received a push notification, launched by


user tapping the alert view
MCDConnectedDevicesNotification* notification =
[MCDConnectedDevicesNotification tryParse:notificationInfo];
if (notification != nil) {
[_platformManager.platform processNotificationAsync:notification
completion:^(NSError* error __unused) {
// NOTE: it may be useful to attach completion to this async in
order to know when the
// notification is done being processed.
// This would be a good time to stop a background service or
otherwise cleanup.
}];
} else {
NSLog(@"Remote notification is not for ConnectedDevicesPlatform, skip
processing");
}

Handling user notification data changes


After the SDK successfully fetches the data changes, an event callback is invoked and
the app client is expected to handle notification creation, update, or deletion.

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;
}
}
}
}];

Update state of a notification


If a notification state change is initiated from this app client instance (for example, if the
toast notification popup on this device is activated by the user), the app needs to call
the SDK to update the notification's state in order to have this state change synced
across all devices used by the same user.

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:

"Search for People who’s name starts with ‘J’"


"Which documents are most interesting to this person?"

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)

Use the /search endpoint


We encourage developers to use the /search endpoint when building their products;
the /people endpoint is in maintenance mode. The following are reasons to consider
using the /search endpoint:

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.

Browse people by relevance


You can browse people who are related to the signed-in user or to some other user in
the signed-in user's organization, provided you have got the appropriate authorization.
You get a collection of person objects that are ordered by relevance. You can further
customize the collection of person objects that is returned in the response by specifying
the query parameters top , skip , orderby , select , and filter .

Fuzzy searches based on people criteria


The people API lets you search for people relevant to the signed-in user, provided that
your app has got permissions by that user. (Read more on people permissions.)

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

Why integrate with the profile API (preview)?


The profile API represents the next generation in modeling and representing people in
Microsoft 365 services. Profile data can be used together with people data to build
customized experiences based on Microsoft Graph.

Why configure profile cards in your


organization (preview)?
Profile cards let users in an organization see information about one another, such as
their names and contact information. Administrators can use the profile card API to
customize how information about their organization surfaces within Microsoft 365
people experiences.
Why integrate with document-based insights?

Use intelligence to improve collaboration


During a typical work day, users often interact with large amounts of information stored
across many documents and collaborate with other users in many different ways. It's
important that they can always find what they need, when they need it.

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.

Make relevant content visible


In Microsoft 365, Delve uses the trending insight to help users discover the documents
that are most interesting to them right now. See figure 1.

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.

Figure 1. Delve in Microsoft 365 showing popular documents for a user


Allow users to collaborate and get back to work
The new Microsoft 365 people cards tap into the used and shared insights to connect
the dots between people and units of knowledge. The people card identifies and
displays relevant documents about a person. Users can see people cards across the
suite, for example, in Outlook on the web. See figure 2.

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.

Figure 2. Outlook on the web showing a people card for a user


Why integrate with Microsoft Viva Insights
(preview)?
Microsoft Viva Insights provides insight into how people spend their time and who they
spend it with. This data can help people plan their day, gain insights into their different
work patterns, and help them balance work and life.

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.

Returned people properties


The people API returns the following set of properties.

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.

Supported Recipient Mailbox Directory People People subtype Notes


people, type details type
groups, and
rooms
variations

Organization UserMailbox, Y Y Person OrganizationUser A user who


user MailUser belongs to the
organization.

Organization User Y (Off by Y (Off by Person OrganizationUser A user who


user without default) default) belongs to the
email address organization.

Organization MailContact, N Y Person OrganizationContact A contact


contact Contact explicitly added
to the global
address list (GAL)
by the tenant
admin, but which
is not part of the
organization.
Supported Recipient Mailbox Directory People People subtype Notes
people, type details type
groups, and
rooms
variations

Private contact Contact Y N/A Person PersonalContact A contact


explicitly created
by the user that
doesn't belong to
the organization.
If the user
manually adds to
its contacts
someone part of
the organization,
it will still be
classified as
OrganizationUser .

Private contact Contact Y (Off by N/A Person PersonalContact A contact


without email default) explicitly created
address by the user that
doesn't belong to
the organization.
If the user
manually adds to
its contacts
someone part of
the organization,
it will still be
classified as
OrganizationUser .
Supported Recipient Mailbox Directory People People subtype Notes
people, type details type
groups, and
rooms
variations

Implicit contact Contact Y N/A Person ImplicitContact A contact inferred


from from
communication communication
history history (email and
chat) that we
don't have
enough
information about
to determine if it
is a person,
group, etc. On
business
accounts, this will
always be an
outside
organization
contact, as inside
organization
contacts found in
the
communication
history will always
be classified as
OrganizationUser .
For consumer
accounts,
anything that is
not a
PersonalContact
will be classified
as
ImplicitContact .

Implicit contact Contact Y N/A Person ChatImplicitContact Same as


from chat ImplicitContact ,
history but when the
communication
history is
exclusively from
chat.

Room Rooms Y Y Other Room

Guest GuestUser Y Y Other Guest


Supported Recipient Mailbox Directory People People subtype Notes
people, type details type
groups, and
rooms
variations

Hidden guest GuestUser Y (Off by Y (Off by Other Guest


default) default)

Modern group Group Y Y Group UnifiedGroup Group known as:


Exchange 365
Group, Modern
Groups, Microsoft
365 Groups. For
more details
about Microsoft
365 Groups, see
Learn about
Microsoft 365
Groups .

Teams group Group Y Y Group UnifiedGroup Same as


Microsoft 365
Groups, but
represents
internally a team
in Microsoft
Teams.

Hidden Teams Group Y (Off by Y Group UnifiedGroup Hidden Teams


group default) group.

Distribution list Group Y Y Group PublicDistributionList Classic Exchange


distribution list or
mail enabled
security group.

Personal Contact Y (Off by N/A Group PersonalDistributionList A virtual


distribution list default) distribution group
created by the
user as a helper
to send emails to
multiple contacts
in an easy way.
Used only for
Outlook on the
web compose as
a UX feature, not
returned for other
callers.
Supported Recipient Mailbox Directory People People subtype Notes
people, type details type
groups, and
rooms
variations

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.

Example 1: Mailbox results only


JSON

"Provenances": ["Mailbox"]

Example 2: Results from both sources


JSON

"Provenances": ["Mailbox", "Directory"]

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.

Note: In case of a conflict, directory sources are preferred.

Mailbox results consist of:

People who sent you email


People who you sent email to
People you had meeting with
People you had Teams chat with
People in your manager's org chart
Public contacts of the above people

Relevant aspects for the use case when a directory source searches in the global addressing
list in Azure Active Directory:

Not applicable for consumer users


People who are not in the caller's global addressing list will not be returned
People who are hidden by IBP (information barrier protocol) will not be returned
People who are hidden in the address list will not be returned

Get more results


Specify the size to get more results. By default, 25 results or less will be returned based on the
search query matches.

JSON

"Size": 25

Specify the minimum index for paging


Set the minimum index for paging to specify the initial page of results. By default, the
minimum index for paging is 0 and the first result is the most relevant.

JSON

"From": 0

Select the fields to return


The API returns a set of default properties, but you can customize a request to return a
specific number of properties. The following example limits the response to the DisplayName,
EmailAddresses, and phones properties.

JSON

"Fields": ["DisplayName", "EmailAddresses", "phones"]

Use a filter to limit the response


Use the Filter object to limit the response to specific values. Possible filter values are:
PeopleType, PeopleSubType.

The following examples show requests that use the Filter object to return people whose
record contains the specified criteria.

Example 1: Filter to person suggestions


The following example limits the response to only person suggestions. The response contains
both private and organization contacts.

JSON

"Filter": {
"And": [
{
"Term": {
"PeopleType": "Person"
}
}
]
},

Example 2: Filter to person suggestions within the


organization
The following example limits the reponse only to business users.

JSON

"Filter": {
"And": [
{
"Term": {
"PeopleType": "Person"
}
},
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
}
]
},

Example 3: Filter to all users, distribution lists, or modern


distribution list in the organization
The following example limits the response to different categories of PeopleSubtype.

JSON

"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "PublicDistributionList"
}
},
{
"Term": {
"PeopleSubtype": "UnifiedGroup"
}
}
]
},

Example 4: Filter to organization users and meeting rooms


The following example limits the response to organization users and meeting rooms.

JSON

"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Rooms"
}
}
]
},

Example 5: Filter to organization users and guests


The following example limits the response to organization users and guests.

JSON
"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Guest"
}
}
]
},

Example 6: Combine multiple filters


The following example combines multiple filters to limit the response to the specified criteria.

JSON

"Filter": {
"And": [
{
"Or": [
{
"Term": {
"PeopleType": "Person"
}
},
{
"Term": {
"PeopleType": "Other"
}
}
]
},
{
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Guest"
}
}
]
}
]
},
Full request

Example: Search person by name


The following request gets the people most relevant to the signed-in user, based on
communication and collaboration patterns and business relationships.

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.

Including a person as relevant or "working-


with"
For a person to be included as relevant to or "working with" a profile owner in Delve, to
be displayed in the owner's profile card, or to be returned by the people API, there must
be a public relationship between the person and the profile owner. The following
illustration shows a User A, an index of relationships with other users (User B), and a
public profile showing a subset of user relationships.
The following are examples of public relationships:

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.

Examples of public interaction include:

Sending or receiving emails to/from each other as part of a public group


Inviting users to meetings as part of group, or where more than X people are
invited

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:

People.Read - Use to make general people API calls; for example,


https://graph.microsoft.com/v1.0/me/people/ . People.Read requires end user
consent.
People.Read.All - Required to retrieve the people most relevant to a specified user
in the signed-in user’s organization
( https://graph.microsoft.com/v1.0/users/{id}/people ) calls. People.Read.All
requires admin consent.

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.

Get a collection of relevant people


The following request gets the people most relevant to the signed-in user ( /me ), based
on communication and collaboration patterns and business relationships.

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"
}
}
]
}

Sort the response


By default, the people in the response are sorted by their relevance to your query. You
can change the order of the people in the response by using the $orderby parameter.
This query selects the people most relevant to you, sorts them by their displayName,
and then returns the first 10 people on the sorted list.

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"
}
}
]
}

Change the number of people and fields returned


You can change the number of people returned in the response by setting the $top
parameter.

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

The following example shows the response.

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"
}
]
}

Types of results included


By default, Microsoft Graph serves mailbox-only results, which are your saved contacts
or people you are most likely to interact with. To retrieve organization-wide directory
results, specify an HTTP header, as shown.

HTTP

"X-PeopleQuery-QuerySources: Mailbox,Directory”

Select the fields to return


You can limit the amount of data returned from the server by using the $select
parameter to choose one or more fields. The @odata.id field is always returned.

The following example limits the response to the displayName and


scoredEmailAddresses of the 10 most relevant people.

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
}
]
}
]
}

Use a filter to limit the response


You can use the $filter parameter to limit the response to only those people whose
record contains the specified criteria.
The following query limits the response to person instances with the personType
property being assigned person as class and organizationUser as subclass.

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"
}
}
]
}

Select the fields to return in a filtered response


You can combine the $select and $filter parameters to create a custom list of people
relevant to the user and get only the fields that your application needs.

The following example gets the displayName and scoredEmailAddresses of people


whose display name equals the specified name. In this example, only people whose
display name equals "Lorrie Frye" are returned.

HTTP

GET https://graph.microsoft.com/v1.0/me/people/?
$select=displayName,scoredEmailAddresses&$filter=displayName eq 'Lorrie
Frye'

The following example shows the response.

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
}
]
}
]
}

Browse another user’s relevant people


The following request gets the people most relevant to another person in the signed-in
user's organization, as described in the implementation of the working-with feature. This
request requires the People.Read.All permission. All the query parameters described in
the above sections apply as well.

In this example, Roscoe Seidel's relevant people are displayed.

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.

Use search to select people


Use the $search parameter to select people who meet a particular set of criteria.
The following search query returns people relevant to /me whose displayName or
emailAddress has a word that begins with the letter "j".

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"
}
}
]
}

Perform a fuzzy search


Searches implement a fuzzy matching algorithm. They will return results based on an
exact match and also on inferences about the intent of the search. For example, imagine
a user with a display name of "Tyler Lee" and an email address of [email protected]
who is in the people collection of the signed-in user. All of the following searches will
return this user Tyler as one of the results.

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.

Customize people insights for an organization


By default, the display or return of people insights is enabled for an organization.
Administrators with the global administrator role can customize this behavior for an
organization using REST APIs and the appropriate permissions. They can customize by
setting properties of the insightsSettings resource in the following ways:

Configure people insights via the Microsoft 365 admin


center
An administrator with the global administrator role can enable or disable the people
insights privacy setting via a toggle. To do so, in the Microsoft 365 admin center, expand
Settings, select Search & intelligence, select Configurations, and under People insights,
choose Change.
The Allow your organization to use People insights toggle allows you to enable or
disable people insights for the whole tenant. Optionally, you can also disable it only for
a group of users following the previous steps and searching for a specific group. Choose
Save to save your settings.
Configure people insights via REST API
Disable people insights for all users in the organization, by setting the
isEnabledInOrganization property of the insightsSettings resource to false . (By
default, the isEnabledInOrganization property is true .)

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.

Use the update operation to set the isEnabledInOrganization or disabledForGroup


properties accordingly for people insights.

Keep the following in mind when updating item insights settings:

People insights settings are available only in the beta endpoint.


The update operation doesn’t verify that a group exists. Make sure to get the
correct ID of the Azure AD group from the Azure portal, verify that the group
exists, and that the intended users have been added to the group. If the group
doesn’t exist, no changes will be made for any user in the organization.
It can take up to 24 hours or longer for updates to insightsSettings to be reflected.

Behavior changes in the Microsoft 365 UI and


people API
Disabling people insights means that the data is not generated for a specified user. It
doesn’t affect search and ranking of results.

When customizing privacy for people insights, you can observe behavioral changes in
the following areas:

Microsoft 365 profile card


User profile in Delve
Listing relevant people
Add or delete custom attributes on a
profile card using the profile card API
(preview)
Article • 06/28/2022

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.

Use the profileCardProperty resource to show additional properties from Azure AD on


profile cards for an organization by:

Making additional attributes visible


Adding custom attributes

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

Operations on the profileCardProperty resource that use delegated permissions


require the signed-in user to have a tenant administrator or global administrator
role.

Make additional attributes visible


You can make the following attributes from Azure Active Directory (Azure AD) visible on
users' profile cards. These attributes are not case-sensitive:

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"
}

If successful, the response returns a 201 OK response code and a profileCardProperty


object in the response body. The value for the Alias attribute would be displayed on a
user's profile card.
HTTP

HTTP/1.1 201 OK
Content-type: application/json

{
"directoryPropertyName": "Alias",
"annotations": []
}

Add a custom attribute


You can add any of the 15 Azure AD custom extension attributes to users' profile cards
by configuring your organization settings and adding the corresponding value as a
profileCardProperty in Microsoft Graph. You can add one profileCardProperty resource
at a time.

It takes up to 24 hours for the changes to show on profile cards.

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:

Azure AD custom extension attribute Value to specify as directoryPropertyName

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.

If successful, the response returns a 201 OK response code and a profileCardProperty


object in the response body. In this example you can assume that the profile card
displays Kostenstelle for all users that have set their language settings to German on the
profile card. For all other users, Cost center will be displayed on the profile card.

Response

HTTP

HTTP/1.1 201 OK
Content-type: application/json

{
"directoryPropertyName": "customAttribute1",
"annotations": [
{
"displayName": "Cost center",
"localizations": [
{
"languageTag": "de",
"displayName": "Kostenstelle"
}
]
}
]
}

Delete a custom attribute


Following the same mapping between Azure AD custom extension attributes and profile
card custom attributes (such as customAttribute1 ) as described in the preceding section
Adding a custom attribute, you can delete a custom attribute using the delete
operation, as shown in the following example.

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

HTTP/1.1 204 No Content

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

Computation of item insights


Microsoft 365 is the world’s productivity cloud, where many features are designed
around you, as the user. By interacting with resources such as files in Microsoft 365, you
produce signals that Microsoft aggregates and assembles into a graph for your
organization. In the graph, the signal data is represented as relationships between you
and the other resources. Derived from signals in the graph are insights that power a few
Microsoft 365 experiences. Examples of experiences include suggesting the best time for
the next team meeting, helping you sort out personal and work information on your
phone, and many other intelligence scenarios.

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.

Item insights in Microsoft 365


Item insights power a few prominent file-based experiences in Microsoft 365.
Recommended files
An example of an experience empowered by item insights is the files under
Recommended in Office.com. Microsoft Graph gathers signals of those files accessible
to you that have ongoing activity, derives item insights from these signals, and applies
these insights to recommend files so you can quickly find the ones that matter to you
most. With item insights, you can quickly get to your most relevant documents.

Files for discovery


You can discover potentially useful content that you can access but may not have seen
before, under Discover in Delve or Outlook mobile. These are documents trending
around you, calculated based on the activity of your closest network of people in your
organization. They include files stored in OneDrive for Business and SharePoint Online.

Recent files in card-based interfaces


In card-based interfaces such as Delve and the profile cards in Microsoft 365 item
insights bring forward OneDrive, SharePoint, or Outlook files that you have modified
recently or shared with the person looking at your profile, which has access to that
content. Such personalized insights help your colleagues save time searching for the
right person or information.

Microsoft runs on trust


Microsoft uses only your activities in a shared working space (activities such as sharing,
modifying, commenting actions) within your organization to calculate recommendations
for others. That means, if you simply glanced at or clicked on a shared document
without changing or commenting on it, your colleagues will not see the document as a
recommendation because you browsed the document.

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 .

Disable or re-enable item insights


By default, item insights are enabled. Administrators use specific settings to control item
insights. If an administrator disables your item insights, you can re-enable them only by
working with the administrator. Learn more about ways for an administrator to control
item insights.

Updating settings can take up to 24 hours to apply within the user’s organization across
Microsoft 365 experiences.

After your item insights are disabled, the following happens:


Microsoft stops using your signals when computing recommendations for others.
Your colleagues stop receiving item insights based on activities that you perform in
shared workspaces. Your colleagues’ insights-based experience becomes less rich
in places such as the Recommended section of files in Office.com and Delve, as
shown in the following example, if you were signed in with the user name MeganB.

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.

Insights about your file-based activities in collaborative workspaces are no longer


shared with others, protecting you from undesirable discovery of your data. On the
other hand, your access to experiences showing trending content is not revoked.
You can see the activities and data of users who have not disabled item insights.
Suggested meeting hours are no longer calculated and shown on your profile
card.

API reference
Looking for the API reference for this service?

Insights API in Microsoft Graph v1.0


Insights API in Microsoft Graph beta

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.

Item insights privacy


Item insights privacy settings provide the ability to configure the visibility of insights
derived from Microsoft Graph between users and other items (such as documents or
sites) in Microsoft 365. You can disable the Delve app via the pre-existing controls, but
allow other insights-based experiences to continue to provide assistance.

There are a few ways to customize users' item insights privacy settings:

A user can view or update one's own settings, in two ways:


MyAccount, under Settings & Privacy .
Microsoft Graph REST API - reading or updating one's own settings that are
exposed through an itemInsights navigation property of userSettings. These
user-centric item insights privacy settings are of the type userInsightsSettings.
An administrator can customize these settings at scale for an organization, or for a
subset of people in a group in an organization, through one of the following ways:
Microsoft 365 admin center
Microsoft Graph PowerShell SDK
Microsoft Graph REST API

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.

How to customize item insights in an


organization
Item insights settings provide flexibility for administrators to use Azure AD tools.
Administrators can disable item insights for an entire organization, or for only members
of a specified Azure AD group. They can configure item insights in the Microsoft 365
admin center, or by using the PowerShell SDK or Microsoft Graph REST API with due
permissions. Keep in mind that the global administrator role is required.

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.

Configure item insights settings via Microsoft 365 admin


center
An administrator with the global administrator role can tune item insights privacy
settings via toggles for an orgnization or a subset of people in a group as part of the
organization. To do so, in the Microsoft 365 admin center, expand Settings, select
Search & intelligence, and under Item insights, choose Change settings.

Configure item insights settings via PowerShell


Confirm the following additional prerequisites. Then you can use the Microsoft Graph
PowerShell SDK to set item insights for an entire organization or for specific groups.

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

Get-MgOrganizationSettingItemInsight -OrganizationId $TenantId

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

The update method requires additional User.ReadWrite.All permissions. To create


a Microsoft Graph session with a specific required scope, use the following
command and consent to requested permissions.

PowerShell

Connect-MgGraph -Scopes "User.Read.All","User.ReadWrite.All"

Use the following command, where you replace $TenantId with your Azure Active
Directory Tenant ID and specify -IsEnabledInOrganization as false .

PowerShell

Update-MgOrganizationSettingItemInsight -OrganizationId $TenantId -


IsEnabledInOrganization:$false

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

Configure item insights settings using the REST API


As stated earlier, by default, item insights privacy settings are enabled for the entire
organization. These settings are exposed through a navigation property named
itemInsights in organizationSettings. You can change the default in one of two ways:

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.

Use the update operation to set the isEnabledInOrganization and disabledForGroup


properties accordingly.

How item insights are enabled isEnabledInOrganization disabledForGroup

Entire organization (default) true empty

Disabled for a subset of users in true ID of the Azure AD group which


the organization contains the subset of users

Disabled for the entire false ignored


organization

Keep the following in mind when updating item insights settings:

insights settings are available only in the beta endpoint.


Get the ID of an Azure AD group from the Azure portal, and make sure the group
exists, because the update operation does not check the existence of the group.
Specifying a non-existent group in disabledForGroup does not disable insights for
any users in the organization.
Updating settings can take up to 24 hours to be applied across all Microsoft 365
experiences.
Regardless of item insights settings, Delve continues to respect Delve tenant and
user level privacy settings.

Behavior changes in UI and APIs


For a full list of experiences affected when disabling item insights, see Overview of item
insights.

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:

Connect and collaborate in Office Delve


Are my documents safe in Office Delve?
Delve for admins
Manage pronouns settings for an
organization using the Microsoft Graph
API (preview)
Article • 04/14/2023

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.

Enabling pronouns in an organization facilitates associating users with their preferred


pronouns within the organization. This includes the following end user experiences:

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.

Configure pronoun settings using PowerShell


You can use the Microsoft Graph PowerShell SDK to configure pronoun settings in your
organization.

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

Confirm your current settings


To get pronoun settings configuration for an organization, use the following command,
and replace $TenantId with your Azure Active Directory tenant ID. You can retrieve this
ID from the overview page of your Azure Active Directory.
PowerShell

Get-MgOrganizationSettingPronoun -OrganizationId $TenantId

Enable pronouns in your organization


By default, pronouns are disabled. You can use the Microsoft Graph PowerShell module
to make pronouns available in your organization.

7 Note

The update method requires additional Organization.ReadWrite.All permissions.


To create a Microsoft Graph session with a specific required scope, use the
following command and consent to requested permissions.

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

Update-MgOrganizationSettingPronoun -OrganizationId $TenantId -


IsEnabledInOrganization:$true

Disable pronouns in your organization


Alternatively, you can make pronouns unavailable for your organization using the
following command, where you replace $TenantId with your Azure Active Directory
Tenant ID, and specify -IsEnabledInOrganization as false .

PowerShell

Update-MgOrganizationSettingPronoun -OrganizationId $TenantId -


IsEnabledInOrganization:$false
Configure pronouns settings using the
Microsoft Graph REST API

Confirm your current settings


Use the get operation to return the current settings for pronouns in your organization.

The following example gets the current display settings, which have pronouns disabled.

HTTP

GET
https://graph.microsoft.com/beta/organization/{organizationId}/settings/pron
ouns

If successful, the response returns a 200 OK response code and a pronounsSettings


resource in the response body.

HTTP

HTTP/1.1 200 OK
Content-Type: application/json

{
"isEnabledInOrganization": false
}

Enable pronouns in your organization


Use the update operation to enable pronouns in your organization.

HTTP

PATCH
https://graph.microsoft.com/beta/organization/{organizationId}/settings/pron
ouns
Content-Type: application/json

{
"isEnabledInOrganization": true
}

If successful, the response returns a 200 OK response code and a pronounsSettings


resource in the response body.
HTTP

HTTP/1.1 200 OK
Content-Type: application/json

{
"isEnabledInOrganization": true
}

Disable pronouns in your organization


Use the update operation to make pronouns unavailable in your organization.

HTTP

PATCH
https://graph.microsoft.com/beta/organization/{organizationId}/settings/pron
ouns
Content-Type: application/json

{
"isEnabledInOrganization": false
}

If successful, the response returns a 200 OK response code and a pronounsSettings


resource in the response body.

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.

Why integrate with Outlook personal contacts?

Complement messaging and calendaring scenarios for


hundreds of millions of customers
Hundreds of millions of consumers and tens of millions of organization customers
choose Outlook as their email client. Contacts provide a complementary function for
messaging and calendaring by letting customers maintain a convenient, integrated store
of contacts data within Outlook. For developers, tapping into the rich functionality of
mail or calendar means opening up richer scenarios with the user's contacts data.

Automate contact organization


The contacts API lets you keep your customers organized, in close parity as the
customers do it themselves through Outlook:

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.)

Share contact information


The contacts API lets you get contact items of the signed-in user, or of the users who
have shared or delegated their contacts to the signed-in user. For example, if Garth has
shared a contact folder 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.

Leverage people API in Microsoft Graph to make better


use of all people data
You can use the typical CRUD operations for an Outlook contact to create and manage
contacts. As part of Microsoft Graph, you can also use the people API that looks at a
user's Outlook contacts, as well as social networks, organization directory, and people
from recent communication, and return information about people from all these sources
that are most relevant to the user. Take advantage of this additional intelligence in
people picker scenarios.

Take advantage of other shared features and


conveniences in Microsoft Graph
The contact entity supports a contact photo which is implemented as the same
profilePhoto entity as a user photo stored in Exchange Online or Azure Active
Directory. This eliminates the overhead in converting between contact and user
profile photos.
You can keep the app local store synchronized by subscribing to change
notifications and tracking changes to contacts and contact folders.
You can extend app storage in a contact instance as an open extension, or add
strongly typed custom data to the contact schema as a schema extension.

Where is the data?


The Microsoft Graph API supports accessing data in users' primary mailboxes and in
shared mailboxes . The data can be calendar, mail, or personal contacts stored in a
mailbox in the cloud on Exchange Online as part of Microsoft 365, or on Exchange on-
premises in a hybrid deployment.

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?

Outlook contacts API in Microsoft Graph v1.0


Outlook contacts API in Microsoft Graph beta

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.

Programmatically, Microsoft Graph supports getting contacts in contact folders that


have been shared by other users, as well as getting the shared folders themselves. The
support also applies to folders in a delegated mailbox.

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

The sharing permissions (Contacts.Read.Shared or Contacts.ReadWrite.Shared)


allow you to read or write contacts in a shared or delegated folder. They do not
support subscribing to change notifications on items in such folders. To set up
change notification subscriptions on contacts in a shared, delegated, or any other
user's contact folder in the tenant, use the application permission, Contacts.Read.

Get a contact in the shared folder


You can get a specific contact in the custom contact folder that Garth has shared with
John:

HTTP

GET users/{Garth-userId | Garth-userPrincipalName}/contactFolders/{folder-


id}/contacts/{id}

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

GET users/{Garth-userId | Garth-userPrincipalName}/contactFolders/{folder-


id}/contacts

On successful completion, you'll get HTTP 200 OK and a collection of contact instances
in Garth's shared contact folder.

Get the shared folder


Get the contact folder that Garth has shared with John.

HTTP

GET users/{Garth-userId | Garth-userPrincipalName}/contactFolders/{folder-


id}

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:

Why integrate with Outlook personal contacts


The contacts API 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.

Lifetime of immutable IDs


An item's immutable ID will not change so long as the item stays in the same mailbox.
That means that immutable ID will NOT change if the item is moved to a different folder
in the mailbox. However, the immutable ID will change if:

The user moves the item to an archive mailbox.


The user exports the item (to a PST, as an MSG file, etc.) and re-imports it into their
mailbox.

Items that support immutable IDs


The following items support immutable IDs:

message resource type


attachment resource type
event resource type
eventMessage resource type
contact resource type
outlookTask resource type

Container types (mailFolder, calendar, etc.) do not support immutable ID, but their
regular IDs were already constant.

Immutable ID with sending mail


You can use immutable IDs to find a message in the Sent Items folder after it has been
sent, using the following steps:

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.

Immutable ID with change notifications


You can request that Microsoft Graph send immutable IDs in change notifications by
including the Prefer: IdType="ImmutableId" header when creating a subscription.
Existing subscriptions created without the header will continue to use the default ID
format. In order to switch existing subscriptions to use immutable IDs, you must delete
and recreate them using the header.

Immutable ID with delta query


You can request that Microsoft Graph return immutable IDs in delta query responses for
supported resource types by including the Prefer: IdType="ImmutableId" header. The
@odata.nextLink and @odata.deltaLink values returned by delta queries are compatible

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.

Updating existing data


If you've already got a database filled with thousands of regular IDs, you can migrate
those IDs to immutable format using the translateExchangeIds function. You can provide
an array of up to 1000 IDs to be translated into a target format.

7 Note

You can also use translateExchangeIds to migrate Exchange Web Services


applications to Microsoft Graph.

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.

Subscribe to changes in contacts, calendar, or


mail
To subscribe to change notifications of Outlook resources, first create a subscription.

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:

Delegated permission supports subscribing to items in folders in only the signed-in


user's mailbox. For example, you cannot use the delegated permission Calendars.Read
to subscribe to events in another user’s mailbox.

To subscribe to change notifications of Outlook contacts, events, or messages in


shared or delegated folders:
Use the corresponding application permission to subscribe to changes of items in a
folder or mailbox of any user in the tenant.
Do not use the Outlook sharing permissions (Contacts.Read.Shared,
Calendars.Read.Shared, Mail.Read.Shared, and their read/write counterparts), as
they do not support subscribing to change notifications on items in shared or
delegated folders.

Depending on the resource, use the least privileged permission specified in the following
table to call this API.

Resource Supported Resource Paths Delegated Delegated Application


(work or (personal
school Microsoft
account) account)

contact Changes to all personal contacts in a user's Contacts.Read Contacts.Read Contacts.Read


mailbox:
/me/contacts
/users/{id}/contacts
Changes to contacts in a user's
contactFolder:
/users/{id}/contactFolders/{id}/contacts

event Changes to all events in a user's mailbox: Calendars.Read Calendars.Read Calendars.Read


/me/events
/users/{id}/events

message Changes to all messages in a user's Mail.ReadBasic, Mail.ReadBasic, Mail.ReadBasic,


mailbox: Mail.Read Mail.Read Mail.Read
/me/messages
/users/{id}/messages
Changes to messages in a user's
mailFolder:
/users/{id}/mailFolders/{id}/messages

Include resource data in notification payload (preview)


7 Note

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:

includeResourceData: Set this property to true to explicitly request resource data.

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

Do not include in the URL $top , $skip , $orderby , $select=Body,UniqueBody , and


$expand other than singleValueExtendedProperties or
multiValueExtendedProperties.

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.

Refine the conditions for a notification


You can further refine the conditions for a notification by using the $filter query
parameter. See an example.

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:

A message added to or marked unread in the folder would trigger a Created


notification.
Reading a message or marking it as read in the folder would trigger a Deleted
notification.
A change to any property, other than isRead, of a message resource in the folder
would trigger an Updated notification.

If you don’t use a $filter when creating the subscription:

Adding a message to the folder would result in a Created notification.


Reading a message in the folder, marking the message as read, or changing any other
property of a message in that folder would result in an Updated notification.
Deleting the message would result in a Delete notification.

Subscribe to lifecycle notifications


The Outlook contact, event, and message resources also support subscribing to lifecycle
notifications. Lifecycle notifications are needed in case your app gets their subscriptions
removed or misses some change notifications. Apps should implement logic to detect and
recover from the loss, and resume a continuous change notification flow. To learn more, see
subscribing to lifecycle notifications.

Keep track of subscription lifetime


Make sure to extend a subscription before it expires. The maximum lifetime for a
subscription without Outlook resource data is 4230 minutes (under 3 days), and 1 day with
resource data.

If you lose the permission granted earlier for a subscription and the subscription expires
meanwhile, request permission again to create a new subscription.

Receive notification payloads


Depending on your subscription, notifications may include resource data. Subscriptions
with resource data allow you to get the resource payload along with the notification,
avoiding the overhead for a separate API call to get the changed resource data.

Receive notifications with resource data (preview)


The following is an example of the payload of a notification with resource data of a
message resource. The resource and resourceData properties correspond to the message
instance that triggered the notification. Use the encryptedContent property to decrypt the
resource data.
JSON

{
"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.

The following is an example of a decrypted notification payload. The decrypted payload


conforms to the Outlook message schema. The payload is similar to that returned by a GET
message operation. However, the notification payload contains only those properties
specified with a $select parameter in the resource property of the subscription.
Notification payloads for other Outlook resources like contact and event follow their
respective schemas.

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]"
}
}
}

Receive notifications without resource data


Notifications without resource data give you enough information to make GET calls to get
the resource. Subscriptions for notifications without resource data don't require an
encryption certificate, because the actual resource data is not sent over.

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

Example 1: Create a subscription to get change notifications


without resource data when the user receives a new
message
The following example requests a notification for a message being created in the user's
mailbox.

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

The following is an example of the 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/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
}

Example 2: Create a subscription to get change


notifications with resource data when the user receives a
new message (preview)
The following example subscribes to notifications with resource data for a message being
created in the user's mailbox. The properties of the message resource to be included in the
notification payload are specified using the $select query parameter.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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
}

Example 3: Create a subscription to get change


notifications with resource data for a message based on a
condition (preview)
The following example subscribes to notifications with resource data for a message being
created in the Drafts folder, containing one or more attachments, and of high importance.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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

Why use the reports API?

Integrate Microsoft 365 usage reporting into your


organization's existing reporting solution
Many companies have existing reporting solutions that use a reporting application or
web portal. You can use the reports API to incorporate Microsoft 365 usage data into
your organization's existing reporting solution so that all IT service reports are in a
unified location.

Retain usage reports for historical analysis


You can use the reports API to get the data that's available in all usage reports, including
organization-level summaries per service, entity-level (user, sites, accounts) usage
information for the last 7/30/90/180 days, and daily activity aggregates. This gives you
the option to keep historical usage information for as long as required.

Analyze AD FS application activity and configuration


Provides information about a relying party configured with Active Directory Federation
Services (AD FS), its aggregated usage, and whether the relying party configuration can
be migrated to Azure Active Directory.

Monitor application sign-ins


Monitor the usage of your applications and make decisions about usage patterns.

Determine who is using your applications and how are


they using them
The authentication methods usage reports help you understand how users in your
organization use Azure Active Directory (Azure AD) capabilities, such as self-service
password rest and multi-factor authentication (MFA). These reports help you determine
which authentication methods are more successful for your organization, what types of
errors end users are running into, and hat campaign you need to run to help your end
users adopt the use of self-service password rest and MFA.

Monitor activity on an Azure AD tenant


Gain a better understanding of how your users access and use Azure AD services. You
can analyze the data to create custom solutions tailored to your organization's specific
needs.

What data can I access by using the reports


API?
You can use the reports API to access the data sets listed in the following table.

Reports API Data set

Activity Directory audit


Sign-in
Provisioning

AD FS applications Relying part detailed summary (preview)

Application registration Credential user registration count (preview)


Credential user registration details (preview)
User credential usage details (preview)
Credential usage summary (preview)

Application sign-in Sign-in summary (preview)


Sign-in details (preview)

Microsoft Teams Device usage


Team activity (preview)
User activity

Microsoft 365 (general) Activations


Active users
Apps usage
Browser usage (preview)
Groups activity
Reports API Data set

OneDrive Activity
Usage

Outlook Activity
App usage
Mailbox usage

SharePoint Activity
Site usage

Skype for Business Activity


Device usage
Organizer activity
Participant activity
Peer to peer activity

Yammer Activity
Device usage
Groups activity

API reference
Looking for the API reference for this service?

Identity and access reports API in Microsoft Graph beta


Microsoft 365 usage reports API in Microsoft Graph v1.0
Microsoft 365 usage reports API in Microsoft Graph beta

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:

Application-level authorization - Allows an app to read all service usage reports


without a signed-in user. The permissions granted to the application determine
authorization.
User delegated authorization - Allows an app to read all service usage reports on
behalf of the signed-in user. In addition to the app having been granted the
required permissions, the user must be a member of an Azure AD limited
administrator role. This can be one of the following roles: Company Administrator,
Exchange Administrator, SharePoint Administrator, Lync Administrator, Teams
Service Administrator, Teams Communications Administrator, Global Reader, Usage
Summary Reports Reader, or Reports Reader. The Global Reader and Usage
Summary Reports Reader roles will only have access to tenant-level data, without
visibility into detailed metrics.

If you're calling the APIs from Graph Explorer:

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

Graph Explorer does not support application-level authorization.

If you're calling the APIs from an application:

The Azure AD tenant administrator 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 signed-in user must be a member
of a limited administrator role in Azure AD.

Assign Azure AD roles to users


After an application is granted permissions, everyone with access to the application (that
is, members of the Azure AD tenant) receives the granted permissions. To further protect
sensitive reports data, tenant administrators must assign users of the application the
appropriate Azure AD roles. For details, see Administrator role permissions in Azure
Active Directory and Assign administrator and non-administrator roles to users with
Azure Active Directory.

7 Note

You must be a tenant administrator to perform this step.

To assign a role to a user:

1. Sign in to the Azure portal (https://portal.azure.com ).


2. Click the icon in the top left to expand the Azure portal menu. Select Azure Active
Directory > Users.
3. Click the name of the user.
4. Choose Assigned roles, and then Add assignment.
5. Select the appropriate role, and click Add.
Overview of the Microsoft Search API in
Microsoft Graph
Article • 06/28/2022

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.

Why use the Microsoft Search API?

One unified search endpoint for Microsoft cloud data


The Microsoft Search API provides one unified search endpoint that you can use to
query data in the Microsoft cloud—messages and events in Outlook mailboxes and files
on OneDrive and SharePoint—that Microsoft Search already indexes.

Include custom external data in search experience


Use Microsoft Graph connectors to include data outside of the Microsoft cloud in your
search experience. For instance, connect to an organization's human resources database
or product catalog. Then use the Microsoft Search API to seamlessly query the external
data source.

Browse the Microsoft Graph connectors gallery to find ready-to-use connectors.


Alternatively, you can build your own connectors to index external custom items and
query specific external data sources.

Consistent, up-to-date search experience


When you use the Microsoft Search API, your customers benefit from more
personalized, relevant search results powered by Microsoft Graph. The search
experience in your apps will return results that are consistent with search in Office
applications.
What data can I add or access by using the
Microsoft Search API?
The Microsoft Search API supports searching the following content in the Microsoft
cloud:

Outlook email message and calendar event resources.


SharePoint and OneDrive files and folders (driveItem resources), list, listItem, site,
and drive resources.
Person resources in an organization who are most relevant to a user.
Content ingested through the Microsoft Graph connectors platform: externalItem
resources.
Administrative search answer resources: acronyms, bookmarks, and QnA resources.

API reference
Looking for the API reference for this service?

Use the Microsoft Search API to query data v1.0


Use the Microsoft Search API to query data beta
Use the Microsoft Search API to index data
Use the Microsoft Search API to manage administrative search answers beta
(preview)

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.

Example 1: Search acronyms

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.

Example: Search bookmarks

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 contentSources property to include the connection ID that is assigned during


the connector setup. You can pass multiple connection IDs to search across
multiple connections. Results are returned in a single list, ranked across the
multiple connections.

The entityTypes property as externalItem .

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.

In addition, you can aggregate search results based on properties in an externalItem


that are numeric or string type, and that are set to be refinable in the schema. For more
information, see Refine search results using aggregations.
Example 1: Retrieve items using Azure SQL
built-in connector
In this example, the content of the AdventureWorks database has been ingested using
the Azure SQL built-in connector.

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"
}
}
},
]
}
]
}
]
}

Example 2: Retrieve items using semantic labels

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
}
]
}
]
}

For more details, see Assign property labels.

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.

Example 1: Search files

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"
}
}
}
]
}
]
}
]
}

Example 2: Search list items

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"
}
}
}
]
}
]
}
]
}

Example 3: Search sites

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/"
}
}
]
}
]
}
]
}

Example 4: Search all content in OneDrive and


SharePoint
This example queries all the content in OneDrive and SharePoint sites to which the
signed-in user has read access. The resource property in the response returns matches
that are files and folders as driveItem objects, matches that are containers (SharePoint
lists) as list, and all other matches as listItem.

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"
}
}
]
}
]
}
]
}

Example 5: Use filters in search queries


You can use KQL in search terms of queries for OneDrive and SharePoint. For example:

"query": "contoso filetype:docx OR filetype:doc" scopes the query to Word


documents.
"query": "test path:\"https://contoso.sharepoint.com/sites/Team

Site/Documents/Project\"" scopes the query to a particular folder within a site.


"query": "contoso AND isDocument=true" scopes the query to only return

documents. Any container (folder, document library) will not be returned.


"query": "contoso contentclass:STS_List_Events" scopes the query to Calendar

events stored in SharePoint.


"query": "contoso (LastModifiedTime > 2021-02-01 AND Created > 2021-02-01)"
scopes the query to filter SharePoint and OneDrive items by date

In order to be valid, properties restriction should specify a valid, queryable managed


property name in the condition.

Example 6: Specify select properties


You can specify the fields you want back in the response, as part of the fields sub-
property in listItem or an internal listItem sub-property in driveItem of a searchHit
object in the response. This is a way to either trim down the response over the wire, or
to request some specific properties that are not part of the out-of-the-box schema.

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.

Performing a search with application permission is limited to one geographic region.


You must specify a value for the region property in your search request when you use
application permissions to run a search. To get the region value for a tenant, use the
dataLocationCode property of the siteCollection resource. For more information and
examples, see Get the region value.

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.

Example 1: Default search request

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.

To include all private content in a search using application permissions, specify


privateContent in the sharePointOneDriveOptions property.

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.

Supported entity combination


The following table shows the relationship between different entity types that can be interleaved.

Entity Type message chatMessage drive driveItem event externalItem list listItem person site

message True - - - - - - - - -

chatMessage - True - - - - - - - -

drive - - True True - True True True - True

driveItem - - True True - True True True - True

event - - - - True - - - - -

externalItem - - True True - True True True - True

list - - True True - True True True - True

listItem - - True True - True True True - True

person - - - - - - - - True -

site - - True True - True True True - True

Examples

Example 1: Search with SharePoint file types and connector


combination

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 results are sorted by receivedDateTime in descending order.

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.

Example 1: Search messages in a user's mailbox


The following example queries messages in the signed-in user's mailbox that contain
the string "contoso" in any part of the message (the sender name, subject, message
body, or any attachments). The query returns the first 25 results. The search results are
ordered by DateTime descending.

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]"
}
}
}
}
]
}
]
}
]
}

Example 2: Search top results messages


The following example uses the search query shown in Example 1, and sorts the results
by relevance.

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.

Returned people properties


The people API returns the following set of properties.

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.

Supported Recipient Mailbox Directory People People subtype Notes


people, type details type
groups, and
rooms
variations

Organization UserMailbox, Y Y Person OrganizationUser A user who


user MailUser belongs to the
organization.

Organization User Y (Off by Y (Off by Person OrganizationUser A user who


user without default) default) belongs to the
email address organization.

Organization MailContact, N Y Person OrganizationContact A contact


contact Contact explicitly added
to the global
address list (GAL)
by the tenant
admin, but which
is not part of the
organization.
Supported Recipient Mailbox Directory People People subtype Notes
people, type details type
groups, and
rooms
variations

Private contact Contact Y N/A Person PersonalContact A contact


explicitly created
by the user that
doesn't belong to
the organization.
If the user
manually adds to
its contacts
someone part of
the organization,
it will still be
classified as
OrganizationUser .

Private contact Contact Y (Off by N/A Person PersonalContact A contact


without email default) explicitly created
address by the user that
doesn't belong to
the organization.
If the user
manually adds to
its contacts
someone part of
the organization,
it will still be
classified as
OrganizationUser .
Supported Recipient Mailbox Directory People People subtype Notes
people, type details type
groups, and
rooms
variations

Implicit contact Contact Y N/A Person ImplicitContact A contact inferred


from from
communication communication
history history (email and
chat) that we
don't have
enough
information about
to determine if it
is a person,
group, etc. On
business
accounts, this will
always be an
outside
organization
contact, as inside
organization
contacts found in
the
communication
history will always
be classified as
OrganizationUser .
For consumer
accounts,
anything that is
not a
PersonalContact
will be classified
as
ImplicitContact .

Implicit contact Contact Y N/A Person ChatImplicitContact Same as


from chat ImplicitContact ,
history but when the
communication
history is
exclusively from
chat.

Room Rooms Y Y Other Room

Guest GuestUser Y Y Other Guest


Supported Recipient Mailbox Directory People People subtype Notes
people, type details type
groups, and
rooms
variations

Hidden guest GuestUser Y (Off by Y (Off by Other Guest


default) default)

Modern group Group Y Y Group UnifiedGroup Group known as:


Exchange 365
Group, Modern
Groups, Microsoft
365 Groups. For
more details
about Microsoft
365 Groups, see
Learn about
Microsoft 365
Groups .

Teams group Group Y Y Group UnifiedGroup Same as


Microsoft 365
Groups, but
represents
internally a team
in Microsoft
Teams.

Hidden Teams Group Y (Off by Y Group UnifiedGroup Hidden Teams


group default) group.

Distribution list Group Y Y Group PublicDistributionList Classic Exchange


distribution list or
mail enabled
security group.

Personal Contact Y (Off by N/A Group PersonalDistributionList A virtual


distribution list default) distribution group
created by the
user as a helper
to send emails to
multiple contacts
in an easy way.
Used only for
Outlook on the
web compose as
a UX feature, not
returned for other
callers.
Supported Recipient Mailbox Directory People People subtype Notes
people, type details type
groups, and
rooms
variations

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.

Example 1: Mailbox results only


JSON

"Provenances": ["Mailbox"]

Example 2: Results from both sources


JSON

"Provenances": ["Mailbox", "Directory"]

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.

Note: In case of a conflict, directory sources are preferred.

Mailbox results consist of:

People who sent you email


People who you sent email to
People you had meeting with
People you had Teams chat with
People in your manager's org chart
Public contacts of the above people

Relevant aspects for the use case when a directory source searches in the global addressing
list in Azure Active Directory:

Not applicable for consumer users


People who are not in the caller's global addressing list will not be returned
People who are hidden by IBP (information barrier protocol) will not be returned
People who are hidden in the address list will not be returned

Get more results


Specify the size to get more results. By default, 25 results or less will be returned based on the
search query matches.

JSON

"Size": 25

Specify the minimum index for paging


Set the minimum index for paging to specify the initial page of results. By default, the
minimum index for paging is 0 and the first result is the most relevant.

JSON

"From": 0

Select the fields to return


The API returns a set of default properties, but you can customize a request to return a
specific number of properties. The following example limits the response to the DisplayName,
EmailAddresses, and phones properties.

JSON

"Fields": ["DisplayName", "EmailAddresses", "phones"]

Use a filter to limit the response


Use the Filter object to limit the response to specific values. Possible filter values are:
PeopleType, PeopleSubType.

The following examples show requests that use the Filter object to return people whose
record contains the specified criteria.

Example 1: Filter to person suggestions


The following example limits the response to only person suggestions. The response contains
both private and organization contacts.

JSON

"Filter": {
"And": [
{
"Term": {
"PeopleType": "Person"
}
}
]
},

Example 2: Filter to person suggestions within the


organization
The following example limits the reponse only to business users.

JSON

"Filter": {
"And": [
{
"Term": {
"PeopleType": "Person"
}
},
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
}
]
},

Example 3: Filter to all users, distribution lists, or modern


distribution list in the organization
The following example limits the response to different categories of PeopleSubtype.

JSON

"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "PublicDistributionList"
}
},
{
"Term": {
"PeopleSubtype": "UnifiedGroup"
}
}
]
},

Example 4: Filter to organization users and meeting rooms


The following example limits the response to organization users and meeting rooms.

JSON

"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Rooms"
}
}
]
},

Example 5: Filter to organization users and guests


The following example limits the response to organization users and guests.

JSON
"Filter": {
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Guest"
}
}
]
},

Example 6: Combine multiple filters


The following example combines multiple filters to limit the response to the specified criteria.

JSON

"Filter": {
"And": [
{
"Or": [
{
"Term": {
"PeopleType": "Person"
}
},
{
"Term": {
"PeopleType": "Other"
}
}
]
},
{
"Or": [
{
"Term": {
"PeopleSubtype": "OrganizationUser"
}
},
{
"Term": {
"PeopleSubtype": "Guest"
}
}
]
}
]
},
Full request

Example: Search person by name


The following request gets the people most relevant to the signed-in user, based on
communication and collaboration patterns and business relationships.

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.

Example: Search Q&As

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

Example 1: Search Teams chat message

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
}
]
}
]
}

Example 2: Search top results messages

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
}
]
}
]
}

Example 3: Search Teams Message with KQL

Supported scope terms


You can use the following scope terms in your Keyword Query Language (KQL) query.

Scope Terms Description Example

from Search only for messages from:bob


sent by scoped person.

hasAttachment Search only for messages hasAttachment:true


that contain or don't containt
attachments.

IsRead Search only for messages IsRead:true


that were or were not read.

IsMentioned Search only for messages IsMentioned:true


that did or did not mention
you.

mentions Search only for messages mentions:497b7a2a9e1a48d780e82965d2fc3a81


that mentioned somebody. (This is user id without '-')

sent Search only for messages sent > 2022-07-14


sent to the scoped date
range.

to Search only for messages to:bob


sent to the scoped person,
partially supported for the 1-
on-1 message.

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.

Example 1: Create a new acronym


The following request creates a new acronym that will display on the search results page
when a user searches for it.

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"
}

Example 2: Create a new bookmark


The following request creates a new bookmark that will display on the search results
page when a user searches for at least one of its keywords.

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

HTTP/1.1 201 CREATED


Location: /733b26d5-af76-4eea-ac69-1a0ce8716897
Content-Type: application/json

{
"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:

One or more characteristics or conditions to compare each search result against,


such as the result source or content type of the search result.
A display template to use for search results that meet the conditions. The display
template controls the way in which all results that meet the conditions appear and
behave on a search results page.

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"
}
}
}
}
]
}

Web component example


The following example shows how to use Adaptive Card templating to render search
results.

) 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 = [];

// Convert object to map


var templateDictionary = new Map(Object.entries(
mockdata.value[0].resultTemplates));

for (let hit of mockdata.value[0].hitsContainers[0].hits) {


renderTemplates.push(this.renderACT(hit,
templateDictionary));
}

for(let template of renderTemplates){


document.getElementById('exampleDiv').appendChild(template);
}
}

function renderACT(hit, templateDictionary) {


var templateId = hit.resultTemplateId;
// Define a template payload
var templatePayload = templateDictionary.get(templateId).body;
var template = new ACData.Template(templatePayload);

// Expand the template with your `$root` data object.


// This binds it to the data and produces the final Adaptive
Card payload

console.log(hit.resource);

// Create a data binding context, and set its $root property to


the
// data object to bind the template to
var context = new ACData.EvaluationContext();
context.$root = hit.resource;

console.log(context);
var card = template.expand(context);
// OPTIONAL: Render the card (requires that the adaptivecards
library be loaded)

var adaptiveCard = new AdaptiveCards.AdaptiveCard();


adaptiveCard.parse(card);
return adaptiveCard.render();
}

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.

Example 1: Request aggregations by string


fields
The following example searches listItem resources and aggregates results by their file
type, content class, and last modified time, all of which are string values.

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

same bucket by that value.


The count property specifies the number of such objects aggregated in the same
bucket. Note that this number is an approximation of the number of matches and
will not provide an exact number of matches.
Buckets of results aggregated by file type are sorted by count in descending order.
In this example, there are 3 buckets for 3 file types: docx , xlsx , and pptx .
Buckets of results aggregated by content class are sorted by the string value of the
content class in descending order. In this example, there is only one bucket with all
the matching objects sharing the same content class,
STS_ListItem_DocumentLibrary .

Buckets of results aggregated by lastModifiedTime are sorted by the string value


of lastModifiedTime in descending order. This example includes three buckets:
Before 2021-09-01T09:08:19.6224752Z , From 2021-09-01T09:08:19.6224752Z up to
2021-11-09T09:08:19.6224752Z , and 2021-11-09T09:08:19.6224752Z or later .

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\")"
}
]
}
]
}
]
}

Example 2: Apply an aggregation filter based


on a previous request
This example applies an aggregation filter that is based on the aggregationFilterToken
returned for docx as the fileType field and From 2021-09-01T09:08:19.6224752Z up to
2021-11-09T09:08:19.6224752Z as the lastModifiedTime field in example 1.

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}\")".

The datetime-formatting string value assigned to the aggregationFilters property


follows the format "{field}:{aggregationFilterToken}".

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\")"
}
]
}
]
}
]
}

Example 3: Request aggregation by a numeric


field
The following example searches driveItem resources and aggregates results by their size
which is a numeric value. The request specifies aggregation by 3 size ranges:

Size less than 100


Size between 100 and 1000
Size 1000 and higher

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:

enableSuggestion to enable/disable spelling suggestions for the user query. You


can pass true to get the suggested spelling correction information for typos in the
user query.

enableModification to enable/disable spelling modifications for the user query.


You can pass true to get the search results for the corrected query when there are
no results for the original query with typos, and get the corresponding correction
information.

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.

Example 1: Request spelling suggestions


The following example queries listItem resources that contain the string accountt and
requests a spelling suggestion for the query.

The response contains alterationResponse objects for the spelling suggestion.

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"
}
}
]
}

Example 2: Request spelling modifications


The following example queries listItem resources that contain the string accountt and
requests a spelling modification for the query.

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.

Scenarios Description Example

Basic Collapse by any single queryable and either "collapseProperties":[{"fields":


collapse sortable or refineable property. This limit ["filename"],"limit":3}]
value must be an integer between 1 and
32767.

Compound Collapse by compound fields of properties. "collapseProperties":[{"fields":


collapse There is no maximum number of fields, but at ["filename","author"],"limit":2}]
least two fields must be specified. This limit
value must be an integer between 1 and
32767.

Multi-level Collapse by level-by-level collapseProperty. "collapseProperties":[{"fields":


collapse There is no maximum number of levels, but at ["filename"],"limit":3},
least two levels must be specified. The limit {"fields":["author"],"limit":1}]
value of each level must be an integer
between 1 and 32767, and must be equal to
or less than the upper-level limit value.

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.

Filename Author Subject Rank

Note Andy Poetry 1

Note James History 2

Note Robert Culture 3

Note James Math 4

Note James Science 5

Notebook James Science 6

Notebook Andy Culture 7

Notebook James Science 8

Example 1: Basic collapse

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.

Filename Author Subject Rank

Note Andy Poetry 1

Note James History 2

Note Robert Culture 3

Notebook James Science 6

Notebook Andy Culture 7

Notebook James Science 8

Example 2: Compound collapse

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.

Filename Author Subject Rank

Note Andy Poetry 1

Note James History 2

Note Robert Culture 3

Note James Math 4

Notebook James Science 6

Notebook Andy Culture 7

Notebook James Science 8

Example 3: Multi-level collapse

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.

Filename Author Subject Rank

Note Andy Poetry 1

Note James History 2

Note Robert Culture 3

Notebook James Science 6

Notebook Andy Culture 7

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.

Example 1: Single-level sort

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"
}
}
]
}
]
}

Example 2: Multi-level sort

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.

Accept-Language header string Language

af Afrikaans

am Amharic

ar-sa Arabic (Saudi Arabia)

as Assamese

az-Latn Azerbaijani (Latin)

be Belarusian

bg Bulgarian

bn-BD Bangla (Bangladesh)

bn-IN Bangla (India)

bs Bosnian (Latin)

ca Catalan Spanish

ca-ES-valencia Valencian

cs Czech

cy Welsh

da Danish

de German (Germany)

de-de German (Germany)

el Greek

en-GB English (United Kingdom)

en-US English (United States)


Accept-Language header string Language

es Spanish (Spain)

es-ES Spanish (Spain)

es-US Spanish (United States)

es-MX Spanish (Mexico)

et Estonian

eu Basque

fa Persian

fi Finnish

fil-Latn Filipino

fr French (France)

fr-FR French (France)

fr-CA French (Canada)

ga Irish

gd-Latn Scottish Gaelic

gl Galician

gu Gujarati

ha-Latn Hausa (Latin)

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

it-it Italian (Italy)

ja Japanese

ka Georgian

kk Kazakh

km Khmer

kn Kannada

ko Korean

kok Konkani

ku-Arab Central Kurdish

ky-Cyrl Kyrgyz

lb Luxembourgish

lt Lithuanian

lv Latvian

mi-Latn Maori

mk Macedonian

ml Malayalam

mn-Cyrl Mongolian (Cyrillic)

mr Marathi

ms Malay (Malaysia)

mt Maltese

nb Norwegian (Bokmål)

ne Nepali (Nepal)

nl Dutch (Netherlands)

nl-BE Dutch (Netherlands)

nn Norwegian (Nynorsk)

nso Sesotho sa Leboa


Accept-Language header string Language

or Odia

pa Punjabi (Gurmukhi)

pa-Arab Punjabi (Arabic)

pl Polish

prs-Arab Dari

pt-BR Portuguese (Brazil)

pt-PT Portuguese (Portugal)

qut-Latn K’iche’

quz Quechua (Peru)

ro Romanian (Romania)

ru Russian

rw Kinyarwanda

sd-Arab Sindhi (Arabic)

si Sinhala

sk Slovak

sl Slovenian

sq Albanian

sr-Cyrl-BA Serbian (Cyrillic, Bosnia and Herzegovina)

sr-Cyrl-RS Serbian (Cyrillic, Serbia)

sr-Latn-RS Serbian (Latin, Serbia)

sv Swedish (Sweden)

sw Kiswahili

ta Tamil

te Telugu

tg-Cyrl Tajik (Cyrillic)

th Thai
Accept-Language header string Language

ti Tigrinya

tk-Latn Turkmen (Latin)

tn Setswana

tr Turkish

tt-Cyrl Tatar (Cyrillic)

ug-Arab Uyghur

uk Ukrainian

ur Urdu

uz-Latn Uzbek (Latin)

vi Vietnamese

wo Wolof

xh isiXhosa

yo-Latn Yoruba

zh-Hans Chinese (Simplified)

zh-Hant Chinese (Traditional)

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

Why use the Microsoft Graph security API?


The Microsoft Graph security API makes it easy to connect with security solutions from
Microsoft and partners. It allows you to more readily realize and enrich the value of
these solutions. You can connect easily with the Microsoft Graph security API by using
one of the following approaches, depending on your requirements:
Write code – Find code samples in C#, Java, NodeJS, and more.
Connect using scripts – Find PowerShell samples .
Drag and drop into workflows and playbooks – Use Microsoft Graph security
connectors for Azure Logic Apps, Microsoft Flow , and Power Apps .
Get data into reports and dashboards – Use the Microsoft Graph security
connector for Power BI.
Connect using Jupyter notebooks – Find Jupyter notebook samples .

Submit threats and trigger whole automation flow


Submit threats across security solutions more easily with a unified security threat
submission API. This allows you to not only submit threats but also get threat
submission results and trigger downstream alert flows. The new unified security threat
submission API supports both application and delegated permissions to help you build
new security solutions.

Unify and standardize alert tracking


Connect once to integrate alerts from any Microsoft Graph-integrated security solution
and keep alert status and assignments in sync across all solutions. You can also stream
alerts to security information and event management (SIEM) solutions, such as Splunk
using Microsoft Graph security API connectors. For more info about solution
integrations with the security API entities, see Security solution integrations using the
Microsoft Graph security API.

Correlate security alerts to improve threat protection and


response
Correlate alerts across security solutions more easily with a unified alert schema. This
not only allows you to receive actionable alert information but allows security analysts
to pivot and enrich alerts with asset and user information, enabling faster response to
threats and asset protection.

Update alert tags, status, and assignments


Tag alerts with additional context or threat intelligence to inform response and
remediation. Ensure that comments and feedback on alerts are captured for visibility to
all workflows. Keep alert status and assignments in sync so that all integrated solutions
reflect the current state. Use webhook subscriptions to get notified of changes.
Unlock security context to drive investigation
Dive deep into related security-relevant inventory (like users, hosts, and apps), then add
organizational context from other Microsoft Graph providers (Azure AD, Microsoft
Intune, Microsoft 365) to bring business and security contexts together and improve
threat response.

Automate security workflows and reporting


Automate security management, monitoring, and investigations to improve operational
efficiencies-and response times. Get deeper insights and context by integrating
Microsoft Graph security into your reports and dashboards.

Get deep insights to train security solutions


Visualize your data across different security products running in your organization to get
deeper security insights. Discover opportunities to learn from the data and train your
security solutions. The schema provides multiple properties to pivot on to build rich
exploratory datasets using your security data.

Utilize your threat intelligence in Microsoft security


solutions (preview)
Automatically send your threat indicators to Microsoft security solutions to enable
alert , block , or allow actions. Use the Microsoft Graph security API directly or take
advantage of integrations with leading threat intelligence platforms.

Act quickly in response to new threats (preview)


Enable swift action to defend against new threats, such as actions to block files, URLs,
domains, or IP addresses from within your security tools and workflows.

Proactively manage security risks (preview)


Use the Microsoft Secure Score (preview) to provide visibility into your organization’s
security needs and get suggestions for how to improve it, and project an improved
score after those suggestions are incorporated. Easily measure your progress over time
and get insights on specific changes that led to improvement in your score.

Manage your eDiscovery workflows


Organizations rely on Microsoft Purview eDiscovery capabilities to meet requirements to
find the truth about what happened in their organization when they need to, based on
internal or external requirements such as litigation, investigation, or regulatory
compliance.

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.

Build custom eDiscovery workflows with Microsoft Graph


https://www.youtube-nocookie.com/embed/gXqBEHy5K6E

Automate case management and synchronization with case management tools.

Add standardized tagging pallets to cases.

Create custom reporting to track case load and progress from individual cases.

Benefits of using the Microsoft Graph security


API
The following table lists the benefits that different security solutions can access by
integrating with the Microsoft Graph security API.

Area Benefits
Area Benefits

Managed Security Service Providers (MSSPs) Streamlined integration with security


operations tools, workflows, and
reporting.
Reduced deployment and maintenance
time and efforts.
Automated response to alerts by
taking action on threats.
Ability to deliver more value to MSSP
customers.

SIEM and IT Risk management solutions Smooth integration with Microsoft


security solutions and ecosystem
partners.
Rich alert metadata.
Better alert correlation.

Applications Unified threat management,


(Threat intelligence, mobile, cloud, IOT, fraud prevention, and risk management
detection, identity & access, risk & compliance, across various security solutions.
firewall, and so on) Alerts, actions, and customer threat
intelligence exposed through Microsoft
Graph.
Instant integration with Microsoft
Graph-enabled solutions.
Gain deep security insights to train
other security solutions.

API reference
Looking for the API reference for this service?

Security API in Microsoft Graph v1.0


Security API in Microsoft Graph beta

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.

The following is a description of the flow:

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.

The Microsoft Graph Security API supports two types of authorization:

Application-level authorization: There is no signed-in user (for example, a SIEM


scenario). The permissions granted to the application determine authorization.

7 Note

This option can also support cases where Role-Based Access Control (RBAC) is
managed by the application.

User-delegated authorization: A user who is a member of the Azure AD tenant is


signed in. The user must be a member of an Azure AD Limited Admin role—either
Security Reader or Security Administrator—in addition to the application having
been granted the required permissions.

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

Graph Explorer does not support application-level authorization.

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.

Manage authorization in security API client


applications
Security data provided via the Microsoft Graph Security API is sensitive and must be
protected by appropriate authentication and authorization mechanisms. The following
table lists the steps to register and create a client application that can access the
Microsoft Graph Security API.

Who Action

Application developer or Register the application as an enterprise application.


owner

Tenant admin Grant permissions to the application.

Tenant admin Assign roles to users.

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:

The application registers to require permission P1.

When users in tenant T1 get an Azure AD token for this application, the token does
not contain any permissions.

The Azure AD admin of tenant T1 explicitly grants permissions to the application.


When users in tenant T1 get an Azure AD token for the application, it will contain
permission P1.

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.

The admin of tenant T2 grants permissions P1 and P2 to the application. Now,


when users in tenant T2 get an Azure AD token for the application, the token will
contain permissions P1 and P2.

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.

Register an application with the Microsoft


identity platform endpoint
To register an application to the Microsoft identity platform endpoint, you'll need:

Application name: A string used for the application name.


Redirect URL: The URL where the authentication response from Azure AD is sent.
To start, you can use the test client web app homepage.
Required Permissions: The permissions that your application requires to be able to
call Microsoft Graph.

To register your application:

1. Go to the Azure app registration portal and sign in.

7 Note

You don't have to be a tenant admin. You will be redirected to the My


applications list.
2. Choose New registration.

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. *

5. Go to the app's API permissions 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.

Permission Entity Supported requests

SecurityActions.Read.All • securityActions (preview) GET

SecurityActions.ReadWrite.All • securityActions (preview) GET, POST

SecurityEvents.Read.All • alerts GET


• secureScores

secureScoreControlProfiles

SecurityEvents.ReadWrite.All • alerts GET, POST, PATCH


• secureScores

secureScoreControlProfiles

ThreatIndicators.ReadWrite.OwnedBy • tiIndicator (preview) GET, POST, PATCH,


DELETE

7. Choose Add permissions.

Save the following information:

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.

Grant permissions to an application


Application registration only defines which permission the application requires; it does
not grant these permissions to the application. An Azure AD tenant administrator must
explicitly grant these permissions by making a call to the admin consent endpoint. For
details, see Using the admin consent endpoint.

To grant permissions to an application, you'll need:

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.

To grant the permissions:

In a text editor, create the following URL string:

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.

Assign Azure AD roles to users


After an application is granted permissions, everyone with access to the application (that
is, members of the Azure AD tenant) receives the granted permissions. To further protect
sensitive security data, the Microsoft Graph Security API also requires users to be
assigned the Azure AD Security Reader role. For details, see Administrator role
permissions in Azure Active Directory and Assign administrator and non-administrator
roles to users with Azure Active Directory.

7 Note

You must be a tenant admin to perform this step.

To assign a role to a user:

1. Sign in to the Azure portal (https://portal.azure.com ).


2. Click the icon in the top left to expand the Azure portal menu. Select Azure Active
Directory > Users.
3. Click the name of the user.
4. Choose Assigned roles, and then Add assignment.
5. Select Security reader, and click Add.

Create an authentication code


To create an authentication code, you'll need:

Application ID: The application ID from application registration portal.


Redirect URL: The URL where the authentication response from Azure AD is sent.
To start, you can use https://localhost or the test client web app homepage.
Application Key (optional): The key of the application. This applies when you're
developing an application that will use application-only authentication code (that
is, will not support user delegated authentication).

The following table lists resources that you can use to create an authentication code.

Type of application Authentication library

Desktop apps - iOS MSAL.framework: Microsoft Authentication Library Preview for


iOS

Desktop apps - Android Microsoft Authentication Library (MSAL)

Desktop apps - .Net Microsoft Authentication Library (MSAL)

Web apps - JavaScript SPA Microsoft Authentication Library for JavaScript Preview
Type of application Authentication library

Web apps - .NET Web Server OpenIdConnection, Cookies, SystemWeb

Web apps - NodeJS Web


App

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:

var accessToken = (await client.AcquireTokenAsync(scopes)).AccessToken;

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.

A token (string) is returned by Azure AD that contains your authentication information


and the permissions required by the application. Assign this token to the HTTP header
as a bearer token, as shown in the following example.

request.Headers.Authorization = new AuthenticationHeaderValue("bearer",


accessToken);
Microsoft Graph will validate the information contained in this token and grant, or
reject, access.

To view claims contained in the returned token, use NuGet library


System.IdentityModel.Tokens.Jwt.

JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();

var securityToken = tokenHandler.ReadToken(accessToken) as JwtSecurityToken;

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.

List of connectors from Microsoft


Solution Name Connector Announcement
type

SIEM Splunk Microsoft Graph Security API Add-On for Blog post
Enterprise and Splunk Splunk on
Splunk Cloud Cloud blog
post

SIEM QRadar Microsoft Graph Security API Protocol and -


supported QRadar DSMs

ITSM ServiceNow Microsoft Graph Security API alert ingestion -


integration

SOAR Azure Logic Microsoft Graph Security connector for Blog post
Apps / Microsoft Azure Logic Apps, Microsoft Flow and Power
Flow Apps

Automation PowerShell Microsoft Graph Security PowerShell Blog post


module Module

Reporting Power BI Microsoft Graph Security connector for Blog post


Power BI
If you would like to support native integrations in your solution or be a data provider for
the Microsoft Graph Security API, review the partnership opportunities.
Information Protection overview
Article • 10/25/2022

Microsoft Purview Information Protection helps organizations to classify, label, and


protect data based on sensitivity.

Organizations use labels to aid:

Users in understanding the importance of information that is being handled.


Compliance administrators in discovering where sensitive information lives.
Security administrators in deploying data access and data loss prevention policies
based on more rich label information.

Why integrate Microsoft Purview Information


Protection?

Integrate with the ubiquitous labeling platform, servicing


millions of users and devices
More than a million organizations with tens of millions of users use Microsoft Purview
Information Protection to classify, label, and protect data. In addition to Microsoft 365,
various data loss prevention (DLP) services, business intelligence platforms, and
software-as-a-service (SaaS) solutions have embraced Microsoft Purview Information
Protection labeling to provide a richer data classification experience.

Label information in line-of-business applications


Enterprise developers use Microsoft Purview Information Protection to label and protect
sensitive customer information on export from line-of-business applications to ensure
the safety of customer information. Connecting your applications to the Microsoft
Purview Information Protection ecosystem enables applications to apply, update, and
delete sensitivity labels in your own application data, without the overhead of
integrating a full SDK.

What can I do with Microsoft Purview


Information Protection label APIs in Microsoft
Graph?
Discover labels available to a user or organization
With Microsoft Graph you can access the sensitivity labels available to a user or the
organization. Labels are applied by applications and services to data at rest or in motion,
helping users, downstream applications, and services to understand the sensitivity of the
information they're handling.

Understand how to apply labels


By providing information on the existing and desired sensitivity label, the REST API can
intelligently inform your application of the actions that should be taken to correctly
apply the label. This includes actions such as metadata application, watermark
generation, protection, and more.

Interpret labels applied to data


Applications consuming information that already has sensitivity label metadata applied
can use the extractLabel API to resolve label metadata to a Microsoft Purview
Information Protection sensitivity label. Use the label to identify the actions that should
be taken by the application when handling or consuming the labeled data.

API reference
Looking for the API reference for this service?

Microsoft Purview Information Protection API in Microsoft Graph beta

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.

Introduction to the Microsoft Graph Security


API
The Microsoft Graph Security API is a unified API that provides a standard interface and
uniform schema to integrate security alerts and threat intelligence from multiple
sources, enrich alerts and data with contextual information, and automate security
operations.

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.

Microsoft enables technology partner integration in two key ways.

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.

How do you integrate? Data available Capabilities supported

Integrate your application with the Alerts from Query alerts/Secure


Microsoft Graph Security API. Microsoft Graph Score
Security Providers Call a Microsoft
Secure Scores from Graph Security Action
Microsoft Update a Microsoft
Graph Security alert
Upload Customer
threat indicators to
Microsoft

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.

Featured technology partner scenarios


The following are three key benefits you can derive by integrating with the Microsoft
Graph Security API:

1. Your customers benefit from improvements in security effectiveness and


operations.
2. Your customers benefit from the rich information supplied by yours and other
integrated partner products.
3. The engineering investment for technology partners is simplified and the customer
value is magnified via integration with the Microsoft Graph Security API.

Enhance threat protection with the Microsoft Graph


Security API
Enabling easier integration of security alerts to inform threat detection and response.

Correlate alerts/detections from Microsoft Graph Security providers with your


detections to improve your investigation outcomes and support automations.
Access detections and context via the Microsoft Graph to improve threat response
– triage, investigation, remediation.
Access customer threat intelligence (hash, IP, URL, domain, etc.) to block/alert on
malicious activity.

Streamline IT and security management


Providing greater visibility and streamlining management of the incident lifecycle.

Aggregate alerts from multiple providers to create incidents.


Access additional context to inform alert prioritization and response.
Keep alert status synchronized across systems managing alerts.
Gain visibility into the security posture and recommendation on how to improve it
with Secure Scores.

Share threat intelligence to enable custom detections


Leverage your threat intelligence to power custom detections in Microsoft solutions.

Automatically send your threat indicators to Microsoft security solutions to enable


Alert, Block, or Allow actions.
Enable swift action to defend against new threats, such as block file, URL, domain,
IP address from within your security tools and workflows.
Customer supplied TI is used only for the supplying customer and not for any
other Microsoft customer.

Technical integrations overview


The Microsoft Graph Security API partnering opportunities are made available via two
primary integration paths, which can be used independently or together. We will outline
the high-level requirements and provide some insight into how to think about investing
in these paths here, but detailed technical explanations are left to the documents
referenced later in this document.

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.

Integrate your application with the Microsoft Graph


Security API
All integrated applications must be registered with Microsoft Graph. Both applications
used by a single customer as well as those used by many customers (multi-tenant) are
supported. In either case, the customer must grant consent for your application. When
calling the Microsoft Graph, each request from your application will contain your
application identifier and the customer you are calling on behalf of. The following types
of requests are supported:

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.

Enable others to integrate with your products through


the Microsoft Graph Security API
Microsoft Graph Security providers make their security alerts available to others through
the Microsoft Graph. Microsoft products that generate security alerts all have providers
that expose their respective alerts to the Microsoft Graph. In addition, Microsoft Graph
Security API allows for external providers, enabling you, as a Microsoft technology
partner, to share relevant security alerts from your applications in the Microsoft Graph
for customers to use. In addition to alerts, Microsoft Graph Security securityActions
enable technology partners to expose functional capabilities via the Microsoft Graph.
For example, if your security solution supports the ability to block IP addresses you can
expose “Block IP” as a capability in the Microsoft Graph. Other Microsoft Graph Security
products can call your action via the Microsoft Graph.

A Microsoft Graph Security Provider is essentially a cloud endpoint that responds to


requests from the Microsoft Graph Security API and returns the relevant security alerts
or executes actions for mutual customers. Customer and service-to-service
authentication ensure access to customer alerts and actions is secured.

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

Onboarding guides and technical documentation


Overview of the Microsoft Graph Security API
API reference
alert schema
tiIndicator schema
Security Actions schema
Secure Score schema

Sample code
Microsoft Graph Security samples
Contribute to Microsoft Graph Security samples

Help and support


If you have questions on application or service or product integrations with the
Microsoft Graph Security API, reach out to the Using Microsoft Security Graph API
tech community
Follow discussions on Microsoft Q&A with the tag: microsoft-graph-security.
If you find bugs in the samples or documentation requests or bugs file issues in
the respective sample repository .
If you have new sample requests or issues that is not scoped to a single sample,
file issues in the Microsoft Graph Security Solutions repository .

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.

Why integrate with SharePoint sites and


content?
SharePoint sites power team collaboration and communication. Microsoft 365 groups,
Microsoft Teams, and portals are all based on SharePoint, so you can use Microsoft
Graph to access data no matter where it's kept. Use the SharePoint API in Microsoft
Graph to access:

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.

Unleash your data with SharePoint lists


Lists are the foundation for data storage in SharePoint. Create lists to store a variety of
business data, from a simple customer contact list to a custom business application,
fronted with Power Apps. When you use columns to define your schema, SharePoint can
protect the integrity of your data as well as enable rich indexing, querying, and search
capabilities.

Bring the power of lists to your team's files


SharePoint stores files in a special list type called a document library. You can use the
OneDrive API to work with a library as a drive, or the SharePoint API to work with it as a
list. Just like a regular list, you can extend the schema of a Document Library to support
your business needs with custom columns.

Light up your app with your users' SharePoint intranet


data
With Microsoft Graph, you can surface your users' most important data within your app.
Keep things fresh by querying the list that stores your users' data. Create your own lists
for your app and let users access your data in other SharePoint experiences, or keep
things hidden.

Use Microsoft Graph to extend SharePoint


As a platform, SharePoint provides several models for extension and integration:

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?

SharePoint API in Microsoft Graph v1.0


SharePoint API in Microsoft Graph beta

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.

Microsoft 365 Planner task board

Why integrate with Planner tasks?


Planner provides task tracking capabilities for collaboration experiences in Microsoft
365. If your scenarios require tracking tasks and organizing work for a team or group of
end users, Planner is the right service for you. Planner integration can help you reach the
millions of users collaborating on Microsoft 365.

Organize your team’s work


Planner provides a shared space where you can build a team, create tasks, and assign
them to others on the team. Planner makes it easy for everyone to know who’s doing
what and if things are on track. You can update tasks with additional information like
due dates, progress, and descriptions, and then further organize tasks with customizable
buckets and category labels.

Collaborate across Microsoft 365


Planner integrates into collaboration experiences across Microsoft 365. In addition to
Planner web and mobile clients, users can view and update Planner plans and tasks from
within SharePoint and Microsoft Teams.

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.

Business scenario support


Planner supports business scenarios. Using the business scenarios API, you can create
tasks and plans for your business processes, and control the tasks and the user
experience around these tasks from the scenario configuration. Learn more about
business scenarios.

Top Planner API tasks


Operation URL

See all the plans for a group GET


https://graph.microsoft.com/v1.0/groups/{id}/planner/plans

See tasks in a plan GET


https://graph.microsoft.com/v1.0/planner/plans/{id}/tasks

See all my tasks assigned to me GET https://graph.microsoft.com/v1.0/me/planner/tasks/


across plans

Create a new task POST https://graph.microsoft.com/v1.0/planner/tasks

Update a task PATCH


https://graph.microsoft.com/v1.0/planner/tasks/{task-id}

Delete a task DELETE https://graph.microsoft.com/v1.0/planner/tasks/{id}

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.

Business scenarios currently allow Microsoft Planner data to be generated through a


scenario.

Why use the business scenarios API?


Business scenarios are all about integrating data into existing Microsoft Graph entities,
resulting in a consistent experience for your end users with data they depend on
without having to switch between different applications for common operations. All the
data you care about can be surfaced consistently in the external or Microsoft user
experiences. Additionally, all data is also available in Microsoft Graph, allowing
additional semantics and processes to be built consistently through the Microsoft Graph
API regardless of the origin of the data.

Least privileged access


Business scenario applications do not require control over all the data in a tenant in
order to accomplish their goals. Business scenarios only provide access to the data
created for the scenario through the business scenario API path, and require business
scenario-specific permission scopes to be consented to in order to have this access.
Applications can use other API paths to gather or manipulate other data with additional
permissions if needed in order to build a complete solution.

Control over user experience


Business scenarios control how the users and other applications can interact with the
data created for the scenario through scenario-managed data containers and
configurable permissions. Applications can specify granular permissions and behaviors
on the data to make sure the data cannot be manipulated in ways that are incompatible
with the scenario requirements.

Control over data


The business scenario controls the scenario-related data. The data created from the
scenario is always tied to the scenario, and the configurations set on the scenario apply
to all scenario data, even if the data was created before the configuration change.
Administrators can control which apps have access to manage the data, or add new
applications that can manage existing scenario data. If no longer required, the scenarios
can be deleted, which will delete all associated data for the scenario.

Central control over configuration


Business scenarios provide a single configurationn point. The behavior of data and the
user experience around them can be changed globally by simply updating the scenario,
instead of finding and updating each data object separately.

Integrate data from other sources


Business scenarios are built for integrations. Data created for the scenario can be
accessed with application-specified identifiers and therefore does not require
applications to create mapping of identifiers when integrating data from any kind of
data source.

API reference
Looking for the API reference for this service?

Use the business scenarios API in Microsoft Graph beta

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:

Add recurrence behavior to an existing task, thus creating a recurring series.


Alternately, create a new task with recurrence defined. The end result for both is
the same: a recurring task, the first in a recurring series. Users specify the schedule
for recurrence.

Edit the recurrence schedule for an existing recurring series.

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.

Terminate a series by:


Deleting the active task in the series (and choosing yes to terminate the series).
Terminating the series without deleting the active task.

Revive a series. If recurrence was terminated, it should be possible to reinstate the


series.

Conceptual differences between recurring meetings and


recurring tasks
This section describes a real-life scenario for recurring tasks, to illustrate the interesting
differences between recurring meetings and recurring tasks, and to explore the problem
space of changes to a recurrence pattern.
The following example involves a report that must be completed regularly and utilizes a
recurring task to track completion of the report.

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:

Should the December 10 due date be changed?


When should the next task be due?

The following is the current state of the recurring task, and decision:

The current task has a due date of December 10, 2021.


The previous completed task was due on November 26, 2021.
A decision is made to change the cadence from 2 weeks to 3 weeks; the change
applies retroactively for the overdue reports.

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:

Definition of a task with active recurrence


If the following three conditions are met, a plannerTask has active recurrence:

percentComplete property has a value less than 100 .


recurrence.nextInSeriesTaskId is null or undefined.
recurrence.schedule contains a valid plannerRecurrenceSchedule with a non-null
nextOccurrenceDateTime.

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.

Definition of a recurrence series


A recurrence series (also known as recurring series) is a sequential series of tasks. The
series begins when recurrence is first defined on one task, and the series continues
through automatic creation of new tasks with the same recurrence.seriesId.

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.

Resource type details


Working with recurrence for Planner tasks entails the use of many resource types:
plannerTaskRecurrence, plannerRecurrenceSchedule, and recurrencePattern. the
following sections provide more details about the latter two resource types.

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.

The nextOccurrenceDateTime is a read-only system-generated field. It provides the


service-calculated date that is used as the dueDateTime for the next plannerTask in the
series. The nextOccurrenceDateTime is calculated from the pattern along with either
the patternStartDateTime or an anchor value that tracks the originally scheduled date
of the given task.

Note: Planner doesn't currently use the recurrenceRange resource type.


Planner-specific notes about the recurrencePattern
The following are Planner-specific restrictions for recurrencePattern:

relativeMonthly and relativeYearly patterns might not specify more than one

day for daysOfWeek.


For weekly patterns, if daysOfWeek contains more than one day, the interval must
be 1 .

Clarifications about recurrencePattern:

Whenever any property within a recurrencePattern is changed, all relevant pattern


properties must be specified. For example, a pattern with type = daily and
interval = 1 can't be patched with only interval = 2 ; otherwise, the service returns
a 400 Bad Request response code. The type = daily property must also be
specified, even though the type isn't changing. This is normal behavior for the
recurrencePattern resource type, although some other Planner properties work
differently.

Unused properties are automatically assigned a default value.


For example, the month property is only used for yearly patterns, with valid
values from 1 to 12 . However, daily , weekly , and monthly patterns have 0
assigned to the month property, because 0 is the default for an integer value.
Enum properties, including firstDayOfWeek and index, get default values that
correspond to the first enum value: sunday and first , respectively.

For absoluteMonthly patterns, if the selected dayOfMonth doesn't exist in a


particular month, the last day of the month is substituted.
Example: if dayOfMonth is 31 and you recur for April, the selected date is April
30.
Example: if dayOfMonth is 29 , 30 , or 31 and you recur for February, the
selected date is the last day of February.

Similarly, for absoluteYearly patterns with month = 2 and dayOfMonth = 29 , the


selected date in non-leap years is February 28.

For weekly patterns, the firstDayOfWeek property is used to distinguish between


what is considered this week and what is considered next week. This is relevant
when you change a weekly pattern. The next task is scheduled for next week, and
firstDayOfWeek determines when next week begins.
Examples of how firstDayOfWeek affects changes to a weekly
pattern

Given a task with active recurrence with the following properties:

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.

Pattern change Resulting


nextOccurrenceDateTime

Weekly every Tuesday Tuesday 2/8

Weekly every Thursday Thursday 2/10

Weekly every Thursday and firstDayOfWeek changed to Thursday 2/3


Thursday

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.

Notes about the schedule and due date


The dueDateTime may be edited by clients to have a different value (including null ),
without affecting the schedule and the nextOccurrenceDateTime. For example, if a task
is late and the due date is changed to accommodate that lateness, the next task in the
series appears as originally scheduled, unless the pattern and/or the
patternStartDateTime are explicitly updated. Hence, postponing the due date doesn't
result in skipping dates according to the defined schedule. This differs from a meeting
model, where today's date plays a role in determining when the next meeting occurs.
Knowing today's date is relevant for calculating the next meeting or event date, but it
isn't relevant for calculating the next task due date.

Example 1: Changing the pattern with and without changes to


patternStartDateTime
Given a task with active recurrence with the following properties:

The recurrence pattern specifies every 2 weeks on Friday, for example, type =
weekly , interval = 2 , daysOfWeek = [ friday ], and firstDayOfWeek = sunday .

The previous completed task was due on November 26, 2021.


The current task is due on December 10, 2021.
The nextOccurrenceDateTime is December 24, 2021 (two weeks after the current
due date).

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:

Change description Resulting nextOccurrenceDateTime

Change the patternStartDateTime to December 10, 2021 December 31, 2021

Change the patternStartDateTime to December 17, 2021 January 7, 2022

Don't change the patternStartDateTime December 31, 2021

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.

In the second example, the patternStartDateTime is set to be 3 weeks after November


26, being December 17. Again, the nextOccurrenceDateTime is set to 3 weeks after the
patternStartDateTime, this time January 7. Conceptually, this represents the cadence
change taking effect from November 26 (the previous task) rather than from December
10 (original due date of the current task).

We generally recommend that the dueDateTime of a task be changed to coincide with a


new patternStartDateTime; however this isn't required. If the dueDateTime isn't
changed along with the patternStartDateTime in the second example, users continue to
see a December 10 due date for the current task. When it is complete, the next task in
the series is scheduled for January 7. Because this might be confusing for users, we
recommend that you assign the dueDateTime and patternStartDateTime together.

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.

Example 2: Due date doesn't affect next occurrence

Given a task with active recurrence with the following properties:

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.

The following is an examination of three possible changes.

Change Resulting
nextOccurrenceDateTime

No change Tuesday 2/9

pattern changed to be weekly every Thursday; no change to Thursday 2/10


patternStartDateTime

patternStartDateTime changed to 2/9; no change to pattern Wednesday 2/16

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 default behavior, when patternStartDateTime isn't explicitly reassigned, is


that the schedule continues based on the original due date. In this case, the
original due date is 2/2, while the current dueDateTime is 2/16.
If the patternStartDateTime is changed, the nextOccurrenceDateTime is
recalculated using that new start date.
If the due date is changed to null rather than 2/16, or to any other date in the
future or past, the previous examples would be unaffected.
Developer scenarios

Create a recurring series


The recurrence.schedule is the only client-editable sub-property of recurrence. By
adding a recurrence.schedule (whether or not recurrence is already defined), clients can
change a non-recurring task into a task with active recurrence.

The other two conditions mentioned in the definition of active recurrence influence
whether a recurrence.schedule can be added:

The percentComplete property must be less than 100 .


The recurrence.nextInSeriesTaskId property must be null or unassigned.

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.

Discover the next task in a series


If task C has recurrence defined, and a user marks task C complete (percentComplete =
100 ), then task D is created to continue the recurrence series. Task C has its
recurrence.nextInSeriesTaskId property populated with the ID of task D.

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.

Edit a recurring series


A task with active recurrence can have its recurrence schedule edited. Note that
recurrence.schedule is the only sub-property of recurrence that can be edited.

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.

Terminate a recurring series


To terminate a recurring series, set the recurrence.schedule property to null . You can
only do this when nextInSeriesTaskId is null or unassigned.

Revive recurrence after termination


After removing the recurrence.schedule, you can add a new recurrence.schedule to the
task that revives the series.

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.

Identify the task with active recurrence, within a


recurrence series
Given a recurrence.seriesId, a maximum of one task with that seriesId can have active
recurrence.

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.

Two tasks with active recurrence in the same recurrence series

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.

A task with active recurrence has a smaller occurrenceId than


another in the same recurrence series

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.

Zero tasks with active recurrence in a series

This is a truly ambiguous situation, as either of the following might be the case:

The recurrence mechanism was delayed by a transient failure; it will be retried.


The recurrence mechanism succeeded but the new task hasn't yet been added to
the fast client-facing store.
The new task was created, but then it was deleted by another client.

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.

Find all the tasks in a recurring series


Developers working with Planner are familiar with the existing API to get all tasks in a
plan. Planner doesn't yet have an API to get all tasks in a recurrence series; however, by
getting all tasks in a plan, you can usually obtain all the tasks in a recurrence series.

The recurrence.seriesId property on each plannerTask is an identifier that is distinct to a


particular recurring series that one or more tasks belong to. When assigned, this value
can never change. The recurrence.occurrenceId is an integer value that indicates the
ordering of the tasks within a series. The first task in a series (the task where recurrence
was first added) is given an occurrenceId of 1 .

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.

REST operation examples


The following requests and responses represent an ordered sequence of operations.
They might be used as test cases for clients implementing Planner task recurrence, by
substituting appropriate identifiers (for task, plan, recurrence series, and so on.) Many
error cases are interspersed to illustrate incorrect changes to particular states.

Add a due date and recurrence to an existing plannerTask


The following example request and response show how to recurrence to a task. The task
with ID Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV already exists and has recurrence = null . To add
recurrence, you need to assign the required properties of recurrence.schedule. The
unused recurrencePattern properties (month, dayOfMonth, firstDayOFWeek, and
index) shouldn't be included.

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

HTTP/1.1 204 NO CONTENT

Get the previous task


The following example request and response show how to retrieve the task with newly
added recurrence.

Request

JSON

GET
https://graph.microsoft.com/beta/planner/tasks/Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV
Response
The following are notes about the response:

The unused recurrencePattern properties (month, dayOfMonth, firstDayOFWeek,


and index) are assigned default values by the service.
The nextOccurrenceDateTime is calculated from the schedule. In this case, the
patternStartDateTime is November 13, and the pattern defines every-other-day;
this gives a nextOccurrenceDateTime of two days after the patternStartDateTime,
being November 15.
The seriesId and occurrenceId are automatically generated. The seriesId is a new
GUID, encoded in the Planner identifier format. Because this is the first task in a
series, it gets an occurrenceId of 1 .
The recurrenceStartDateTime gets assigned the same value as the
patternStartDateTime. This is true for the first task in a series (occurrenceId = 1 ).
However, for future tasks in the series, the value of recurrenceStartDateTime
doesn't change even if the patternStartDateTime changes; it tracks the beginning
of recurrence, as contrasted with pattern changes.
The previousInSeriesTaskId is always null , because this is the first task in the
series (occurrenceId = 1 ).
The nextInSeriesTaskId is assigned if and when the next task is created to continue
the series.

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
}

Mark the task complete, triggering recurrence (1st task in


the series)
The following example request and response show how to set percentComplete to 100
(also referred to as completing the task or marking the task complete).

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

HTTP/1.1 204 NO CONTENT

Get the now-complete task and discover the ID of the


next (2nd) task in the series
The following example request and response show how to retrieve the task after it has
been marked complete.

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",
}

Get the new task in the series (2nd occurrence)


The following example request and response show how to retrieve the new task in the
series, ID for which was discovered from the nextInSeriesTaskId in the previous
response.

Request

The example request ( GxOo0ms1iEu3eBI1-6lk85UAI5FI ) contains the following differences


when compared with the previous example ( Q7SNdWp5ekeJTpRRSCcZ3pUAD6kV ):

dueDateTime has been assigned the value from the previous


nextOccurrenceDateTime of the task.
nextOccurrenceDateTime has been calculated according to the schedule: the next
occurrence after the previous dueDateTime.
occurrenceId is 2 rather than 1
percentComplete is 0 .

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"
}

Edit recurrence on the task to be one day per week and


set the due date to null
The following example request and response show how to assign a null dueDateTime
and a different pattern to a task with active recurrence.

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

HTTP/1.1 204 NO CONTENT

Get the task again to see the result of the edit


The following example request and response show how to retrieve the task after the
previous edits. You can expect to see the recurrence.schedule.pattern specified
previously: weekly on Tuesdays, along with dueDateTime = null .

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
}

Remove the recurrence schedule


The following example request and response show how to assign a null
recurrence.schedule, thereby terminating recurrence on this task.

Request

JSON

PATCH https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI

{
"recurrence": {
"schedule": null
}
}

Response

JSON

HTTP/1.1 204 NO CONTENT

Get the task with the recurrence schedule deleted


The following example request and response show how to retrieve the task after the
previous edits.

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
}

Error case: Attempt to add a new recurrence schedule


without specifying the patternStartDateTime
The following example request and response show a bad request, an attempt to add a
new recurrence.schedule without specifying the patternStartDateTime.

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

HTTP/1.1 400 BAD REQUEST


Content-type: application/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"
}
}
}

Reinstate recurrence on the task by adding a new


schedule
The following example request and response show how to assign a new
recurrence.schedule to a task that currently has recurrence.schedule = null .

Note: The dueDateTime isn't assigned.

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

HTTP/1.1 204 NO CONTENT

Get the task with the new recurrence schedule


The following example request and response show how to retrieve the task with the new
recurrence schedule. The recurrence properties (except schedule) remain unchanged,
and the task has active recurrence, even while the dueDateTime property remains null .

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

HTTP/1.1 400 BAD REQUEST


Content-type: application/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"
}
}
}

Mark the task complete, triggering recurrence (2nd task


in the series, with null dueDateTime)
The following example request and response show how to set percentComplete to 100
(also referred to as completing the task or marking the task complete).
Request
The following request is identical for a task with or without recurrence.

JSON

PATCH https://graph.microsoft.com/beta/planner/tasks/GxOo0ms1iEu3eBI1-
6lk85UAI5FI

{
"percentComplete": 100
}

Response

JSON

HTTP/1.1 204 NO CONTENT

Get the now-complete task and discover the ID of the


next (third) task in the series
The following example request and response show how to retrieve the task after it has
been marked complete.

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
}

Error case: Attempt to delete the recurrence schedule


when the nextInSeriesTaskId is already assigned
The following example request and response show a bad request, an attempt to assign a
value to the recurrence.schedule property after the nextInSeriesTaskId property has
been assigned.

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

HTTP/1.1 400 BAD REQUEST


Content-type: application/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"
}
}
}

Get the new task in the series (3rd occurrence)


The following example request and response show how to retrieve the new task in the
series, ID for which you discovered from the nextInSeriesTaskId in the previous
response. The dueDateTime has been assigned to the value presented in the previous
nextOccurrenceDateTime of the task, even though the previous dueDateTime of the
task was null .

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:

block : Task can't be deleted.

allow : Task can be deleted.

The collection must contain only one of these values.

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:

block : Task can't be moved.

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

belong to the same container.


allow : Task can be moved between buckets and across plans.

The collection must contain only one of these values.

order
Specifies whether the task can be reordered in shared views. Accepted values are:

block : Task can't be reordered.


allow : Task can be reordered.

The collection must contain only one of these values.

Configurable properties

appliedCategories
The appliedCategories property is configured with fieldRules, providing default values
and overrides for specific conditions. Accepted values are:

block : Applied categories can't be changed.

allow : Categories can be added or removed.

The collection must contain only one of these values.

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:

block : Assignments of the task can't be changed.

addSelf : Users can assign the task to themselves.


removeSelf : Users can remove themselves as assignees.

addOther : Users can assign the task to people other than themselves.

removeOther : Users can remove assignees other than themselves.


add : Assignees can be added.
remove : Assignees can be removed.

allow : Assignees can be added or removed.

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.

userCreated : Rules apply if the assignment was created by a user.

applicationCreated : Rules apply if the assignment was created using application


permissions.

checkLists
The checkLists property is configured with fieldRules, providing default values and
overrides for specific conditions. Accepted values are:

block : Checklist can't be changed.

check : Checklist items can be checked.


reorder : Checklist items can be reordered.

add : New checklist items can be added.


update : Existing checklist items can be updated.

remove : Existing checklist items can be removed.

allow : All checklist actions are allowed.

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.

userCreated : Rules apply if the checklist item was created by a user.

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.

allow : Task due date can be changed, added, or removed.

The collection must contain only one of these values.

notes
Specifies whether the task notes can be changed. Accepted values are:

block : Task notes can't be changed.

allow : Task notes can be changed.

The collection must contain only one of these values.

percentComplete
Specifies whether the task percentComplete property can be changed. Accepted values
are:

block : The task percentComplete property can't be changed.

setToComplete : The task percentComplete property can be set to 100 .


setToInProgress : The task percentComplete property can be set to values from 1

to 99 .
setToNotStarted : The task percentComplete property can be set to 0 .

allow : The task percentComplete property can be changed.

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:

block : Task preview type can't be changed.

allow : Task preview type can be changed.

The collection must contain only one of these values.

priority
Specifies whether the task priority can be changed. Accepted values are:
block : Task priority can't be changed.

allow : Task priority can be changed.

The collection must contain only one of these values.

references
Thereferences property is configured with fieldRules, providing default values and
overrides for specific conditions. Accepted values are:

block : Task references can't be changed.


add : New references can be added.

remove : Existing references can be removed.

allow : All task reference actions are allowed.

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.

userCreated : Rules apply if the task reference was created by a user.

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:

block : Task start date can't be changed.

allow : Task start date can be changed.

The collection must contain only one of these values.

title
Specifies whether the task title can be changed. Accepted values are:

block : Task title can't be changed.


allow : Task title can be changed.

The collection must contain only one of these values.


Overview for using Microsoft Teams,
Shifts, and Viva Learning to foster
teamwork
Article • 03/04/2023

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

Why integrate with Microsoft Teams, Shifts,


and Viva Learning?
The rich features and APIs for Microsoft Teams, Shifts, and Viva Learning open up many
scenarios for app developers. The following sections list a few of them.

Automate workflows

Use Microsoft Graph in any kind of app


Automate team lifecycles
Create and manage multiple teams and channels
Get work done even when no one is around
Create teams linked to your app
Deploy apps to teams

Call or meet virtually

Handle incoming calls


Collaborate through group calls
Send reminders reliably
Set up online meetings
Cultivate workforce

Manage shifts and staff schedules


Enable employee learning using the collaborative capabilities in Teams

Automate workflows

Use Microsoft Graph in any kind of app


Microsoft Teams apps give work groups a new tool to make collaboration a more
productive and compelling experience. These apps let work group users share assets,
interact through chat, and schedule events on the team calendar. These apps can also
automate creating teams, channels, and conversations, enhancing the value of Microsoft
Teams.

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.

Types of apps enabled for Microsoft Teams

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

Tabs Surface your content in Microsoft Teams.

Bots Help users get tasks done in conversations.

Connectors Post updates from external services to channels.

Actionable Add enhanced interaction to your connector cards.


messaging

Messaging Allow users to query and share information in conversations.


extensions

Websites Surface enhanced content in your webpages.

Services Enhance your client applications with Microsoft Graph data via your web service.

Activity feed Engage users via feed notifications.

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)

Automate team lifecycles


Use Microsoft Graph to create a new virtual team when a new business issue arises, add
the right people to the team, and configure the team with channels, tabs, and apps. If
you want to get the new team together to discuss the business issue, add a new event
to the team calendar.
When the business issue is resolved and you no longer need the team, use the Microsoft
Teams API to archive or delete the team. If you know the maximum duration of the team
when you create it, set an Microsoft 365 group expiration policy for the team that
automatically removes the team according to the policy.

Create and manage multiple teams and channels


Microsoft Graph makes it easy to create large numbers of teams and populate them
with users and channels, by automating the creation and management of teams,
channels, tabs, and apps. Microsoft Graph also lets you find and archive the teams you
are no longer using. This is the same API that the Microsoft Teams Admin Center and
Teams PowerShell cmdlets are built on.

Get work done even when no one is around


Use application permissions to work with teams, channels, and tabs without human
intervention. Create a new channel when your customer files an order. Automatically
create teams for classes at the beginning of the school year, and archive them at the
end.

Create teams linked to your app


Let customers create new teams and channels. Install your Teams app in the new teams.
Pin your app to a tab in the new channel. Send messages to the channel linking back to
your website.

Deploy apps to teams


List the teams in your tenant, and install apps to them. Create tabs in channels to give
users easy access to apps.

Call or meet virtually

Handle incoming calls


It can be overwhelming at times when an organization receives a high volume of
business calls and it isn't possible, or productive, to answer all of them. A bot can serve
as a front-desk assistant, handling calls by rejecting what may seem like spam calls or
redirecting (forwarding) specific calls to a different number. You can use the cloud
communications API to:

Call a bot through VoIP.


Redirect an incoming call to the appropriate agent if necessary.
Answer or reject a call.
Play a prompt to inform and prompt a customer for a selection.
Record a short audio clip of a customer speaking.
Subscribe to a tone to gather the DTMF from a customer.
Transfer a customer to an agent.
Integrating with a natural language processing service means that the customer's
speech can be analyzed for its sentiment. The bot can then respond to the customer's
request accordingly.

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.

Collaborate through group calls


Enable users to engage with coworkers or customers by creating a group call so that
everyone can contribute to the conversation. You can use the cloud communications API
to:

Create a group call with multiple participants.


Invite a bot or a user to an existing group call.
Join an existing group call as a bot.
List call participants in the group call.
Mute a participant.

Send reminders reliably


To enable users to receive reminders for an appointment or a payment deadline that is
approaching, you can have a bot call a customer automatically.

Call a customer on Teams.


Play a recorded prompt to serve as a reminder.
End a call.

Set up online meetings


Whether scheduling a meeting between a doctor and a patient or between a user and
their direct reports, it is possible to build solutions that create meetings that users can
rely on. For added flexibility, users can call other users and invite them to the meeting
while it's ongoing. You can use the cloud communications API to:

Create an online meeting.


Retrieve meeting details of an online meeting.
Join an online meeting.

Cultivate workforce

Manage shifts and staff schedules


Available on Teams, the Microsoft Shifts app manages shifts, staff scheduling, and time
tracking. Being integrated with Teams, Shifts provides users the convenience of
dedicated channels and teams, streamlining communications to connect the workforce
and fostering community building. Use the Shifts API to pull shift data into your staffing
systems, provide frontline workers with shift information they need in one place, and
empower them to own their schedules, request shift in a schedule, and swap or offer
shifts.

Enable employee learning using the collaborative


capabilities in Teams
Viva Learning built for Microsoft Teams and Microsoft 365 brings employee learning into
the flow of work. Viva Learning lets employers register learning providers, upload and
manage content metadata, learner assignments, and completion records. Employees can
share learning content in Teams messages, meeting chats, or emails, encouraging peer
learning and mentoring conversations.

Use the employee learning APIs for Viva Learning to:

Register and manage a learning provider.


Insert, update, retrieve, and delete learning content metadata.

API reference
Looking for the API reference for Teams, Shift, and Viva Learning?

Teams API in Microsoft Graph v1.0


Teams API in Microsoft Graph beta
Shifts API in Microsoft Graph v1.0
Shifts API in Microsoft Graph beta
Employee learning API to integrate with Viva Learning in Microsoft Graph v1.0
Employee learning API to integrate with Viva Learning in Microsoft Graph beta
Next steps
Calls permissions
Communications API samples
Delegated and application permissions
Drill down on the methods, properties, and relationships of the team, channel, and
group resources.
Get a jump-start with sample code: Contoso Airlines , C# mini-samples
Learn how to use the Microsoft Teams API.
Online meeting permissions
Read more about the Microsoft Teams programming model.
Try the API in the Graph Explorer.
Watch the overview video .
Send activity feed notifications to users
in Microsoft Teams
Article • 04/19/2023

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.

Understand the basics of activity feed


notification
Activity feed notifications in Microsoft Teams are comprised of multiple bits of
information, displayed together, as shown in the following image.

The components include:

The actor who initiated the activity


An icon that represents the activity type
The reason the actor did the activity
A text preview
A time stamp
The location of the activity

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.

Teams app manifest changes


This section describes the changes that need to be added to Teams app manifest. Note
that you must be using the Teams app manifest version 1.7 or greater.

JSON

"$schema": "https://developer.microsoft.com/json-
schemas/teams/v1.7/MicrosoftTeams.schema.json",
"manifestVersion": "1.7",

webApplicationInfo section changes

JSON

"webApplicationInfo":
{
"id": "a3111f15-658e-457c-9689-fd20fe907330",
"resource": "https://contosoapp.com"
}

Parameter Type Description

id string Azure AD app ID (client ID).


Parameter Type Description

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.

activities section changes

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}"
}
]
}

Parameter Type Description

type string Type of activity. This needs to be unique in a specific manifest.

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.

Install the Teams app


Teams apps can be installed in a team, a chat, or for a user personally, and can be
distributed in multiple ways. For details, see Teams app distribution methods. Typically,
sideloading is preferred for development purposes. After development, you can choose
the right distribution method based on whether you want to distribute to one tenant or
to all tenants.

You can also use Teams app installation APIs to manage Teams app installations.

Send activity feed notifications to users


Because a Teams app can be installed for a user, in a team, or in a chat, the notifications
can be sent in these three contexts as well:

Send notification to user in a chat


Send notification to user in a team
Send notification to user

Additionally, notifications can be sent in bulk up to 100 users at a time:

Send notifications to multiple users in bulk

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.

Example 1: Notify a user about a task created in a chat


This example shows how you can send an activity feed notification for a new task
created in a chat. In this case, the Teams app must be installed in a chat with Id chatId
and user 569363e2-4e49-4661-87f2-16f245c5d66a must be part of the chat as well.
Request

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

HTTP/1.1 204 No Content

Example 2: Notify a user about a task created in a team


This example shows how you can send an activity feed notification for a team. This
example notifies the team owner about a new task created that requires their attention.

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

HTTP/1.1 204 No Content

Example 3: Notify a user about an event using a custom


topic
As seen in the previous examples, you can link to different aspects of a team or a chat.
However, if you want to link to an aspect that is not part of the team or is not
represented by Microsoft Graph, or if you want to customize the name, you can set the
source of the topic to text and pass in a custom value for it. Additionally, webUrl is
required when you use topic source as text .
The Yammer notification example shown earlier uses a custom topic because Yammer's
resources are not supported by Microsoft Graph.

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

HTTP/1.1 204 No Content

Example 4: Notify the team members about an event


This example shows how you can send an activity feed notification to all team members.
This example notifies the team members about a new event.

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

HTTP/1.1 204 No Content

Example 5: Notify the channel members about an event


This example shows how you can send an activity feed notification to all channel
members. This example notifies the channel members about a new event.

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

HTTP/1.1 204 No Content

Example 6: Notify the chat members about an event


This example shows how you can send an activity feed notification to all chat members.
This example notifies the chat members about a new event.

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

HTTP/1.1 204 No Content

Example 7: Notify multiple users about pending finance


approval requests
The following example shows how to send an activity feed notification to multiple users
in bulk. This example notifies multiple stakeholders about pending finance approval
requests.

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

HTTP/1.1 202 Accepted

Customize how the notifications alert you


Microsoft Teams users can customize the notifications they see in their feed, as a
banner, and so on. Notifications generated through activity feed APIs can also be
customized. Users can choose how they are notified via settings in Microsoft Teams.
Teams apps will appear in the list for the user to choose from, as shown in the following
screenshot.

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.

Can a user send notifications to themselves?


No, a user cannot send notifications to themselves. For this scenario, use application
permissions.

Can a Teams app control how the notifications are shown


to the user?
No, only users are allowed to change notification settings.

I installed my app; why don't I see notification settings


under the user account?
The settings will appear after the first notification is sent by the Teams app. This reduces
the number of settings that users see.

I started getting a 409 (conflict) error; how do I resolve it?


Conflict errors primarily occur when multiple Teams apps installed in the same scope
(team, chat, user, and so on) have the same Azure AD appId in the webApplicationInfo
section of the manifest. When this happens, you will get an error such as Found multiple
applications with the same Azure AD App ID 'Your AzureAD AppId'. . Make sure that

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:

Creating call-to-action notifications


Requesting responses to notifications
Creating notifications about external events

The following image shows an example of an activity feed notification in Teams:

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.

Enhance the notification experience


Microsoft Teams displays notifications in both activity feed and toast formats. Users
receive notifications from multiple sources across chats, channels, meetings, or other
apps. To enhance the user experience, apply the following recommendations:

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.

Activity feed notifications


Activity feed notifications appear in the Teams activity feed and can include links to
various locations. These notifications:

Allow the user to take action or triage the notification.


Lead the user to a tab in a chat or channel, a personal app, or a chat or channel
message.

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.

Bot framework messages


Bot messages are delivered as chat or channel messages. If the user turns on chat or
channel notifications, the notifications that are triggered are sent as chat or channel
messages. To send bot messages, @mention the name of the user for the notification to
appear in the activity feed.

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.

Administrators who want to allow an application to access online meeting resources on


behalf of a user can use the New-CsApplicationAccessPolicy and Grant-
CsApplicationAccessPolicy PowerShell cmdlets to configure access control.

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.

Configure application access policy


To configure an application access policy and allow applications to access online
meetings with application permissions:

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.

Identify the app’s application (client) ID in the Azure app registration


portal .
Identify the user's user (object) ID in the Azure user management portal

2. Connect to Skype for Business PowerShell with an administrator account. For


details, see Manage Skype for Business Online with PowerShell.

3. Create an application access policy containing a list of app IDs.

Run the following cmdlet, replacing the Identity, AppIds, and Description
(optional) arguments.
PowerShell

New-CsApplicationAccessPolicy -Identity Test-policy -AppIds "ddb80e06-


92f3-4978-bc22-a0eee85e6a9e", "ccb80e06-92f3-4978-bc22-a0eee85e6a9e",
"bbb80e06-92f3-4978-bc22-a0eee85e6a9e" -Description "description here"

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

Grant-CsApplicationAccessPolicy -PolicyName Test-policy -Identity


"748d2cbb-3b55-40ed-8c34-2eae5932b22a"

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.

Run the following cmdlet, replacing the PolicyName argument.

PowerShell

Grant-CsApplicationAccessPolicy -PolicyName Test-policy -Global

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.

Supported permissions and additional


resources
Administrators can use ApplicationAccessPolicy cmdlets to control online meeting
access for an app that has been granted any of the following application permissions:

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

for the built-in tab types.

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.

Property Type Description

entityId string Null

contentUrl string URL of the website

removeUrl string Null

websiteUrl string URL of the website

Word, Excel, PowerPoint, and PDF tabs


The following table lists the teamsAppId for each app.

App teamsAppId type (extension)

Word com.microsoft.teamspace.tab.file.staticviewer.word docx


App teamsAppId type (extension)

Excel com.microsoft.teamspace.tab.file.staticviewer.excel xlsx

PowerPoint com.microsoft.teamspace.tab.file.staticviewer.powerpoint pptx

PDF com.microsoft.teamspace.tab.file.staticviewer.pdf pdf

The following is the configuration.

Property Type Description

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}.

contentUrl string The URL of file in the format {folder-webUrl}/{item-name} . {folder-webUrl}


is the webUrl of the SharePoint folder containing the file, which can be
found by opening the file in SharePoint and looking at the address bar, or
by using the webUrl property from GET /groups/{group-
id}/drive/items/{folder-item-id}. {item-name} is the file name (for example,
file.docx), which is the name property in GET /groups/{group-
id}/drive/items/{item-id}.

removeUrl string Null

websiteUrl string Null

Example: Create a configured Word tab


The following example creates a configured Word tab.

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
}
}

Document library tabs


For document library tabs, the teamsAppId is
com.microsoft.teamspace.tab.files.sharepoint . The following is the configuration.

Property Type Description

entityId string Empty string ("")

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.

removeUrl string Null

websiteUrl string Null

Example: Create a configured document library tab


The following example creates a configured document library tab.

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.

Microsoft Stream tabs


For Microsoft Stream tabs, the teamsAppId is com.microsoftstream.embed.skypeteamstab .
Configuration is not supported.

Microsoft Forms tabs


For Microsoft Forms tabs, the teamsAppId is 81fef3a6-72aa-4648-a763-de824aeafb7d .
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.

SharePoint page and list tabs


For SharePoint page and list tabs, the teamsAppId is 2a527703-1f6f-4559-a332-
d8a7d288cd88 . Configuration is not supported.

SharePoint Framework-based tabs


Custom tabs built using SharePoint Framework can be created using Microsoft Graph,
but 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.

Supported GET operations


The following GET operations support system messages:

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}

For details, see chatMessage.

Supported change notifications


The following change notifications support system messages:

Subscribe to messages in a channel - /teams/{team-id}/channels/{channel-


id}/messages
Subscribe to messages in a chat - /chats/{chat-id}/messages

For details, see Change notifications for messages.

Supported system message events


Event System message type Applicable
to

Call ended callEndedEventMessageDetail Chat,


Channel

Call recording callRecordingEventMessageDetail Chat,


Channel

Call started callStartedEventMessageDetail Chat,


Channel

Call transcript callTranscriptEventMessageDetail Chat,


Channel

Channel added channelAddedEventMessageDetail Team

Channel deleted channelDeletedEventMessageDetail Team

Channel description channelDescriptionUpdatedEventMessageDetail Channel


updated

Channel renamed channelRenamedEventMessageDetail Channel

Channel set as favorite channelSetAsFavoriteByDefaultEventMessageDetail Channel

Channel unset as favorite channelUnsetAsFavoriteByDefaultEventMessageDetail Channel

Chat renamed chatRenamedEventMessageDetail Chat

Conversation member role conversationMemberRoleUpdatedEventMessageDetail Channel,


updated Team

Meeting policy updated meetingPolicyUpdatedEventMessageDetail Chat

Members added membersAddedEventMessageDetail Chat,


Channel,
Team

Members deleted membersDeletedEventMessageDetail Chat,


Channel,
Team

Members joined membersJoinedEventMessageDetail Chat

Members left membersLeftEventMessageDetail Chat

Message pinned messagePinnedEventMessageDetail Chat

Message unpinned messageUnpinnedEventMessageDetail Chat


Event System message type Applicable
to

Tab updated tabUpdatedEventMessageDetail Chat,


Channel

Team archived teamArchivedEventMessageDetail Team

Team created teamCreatedEventMessageDetail Team

Team description updated teamDescriptionUpdatedEventMessageDetail Team

Team joining disabled teamJoiningDisabledEventMessageDetail Team

Team joining enabled teamJoiningEnabledEventMessageDetail Team

Team renamed teamRenamedEventMessageDetail Team

Teams app installed teamsAppInstalledEventMessageDetail Chat,


Channel,
Team

Teams app removed teamsAppRemovedEventMessageDetail Chat,


Channel,
Team

Teams app upgraded teamsAppUpgradedEventMessageDetail Chat,


Channel,
Team

Team unarchived teamUnarchivedEventMessageDetail Team

7 Note

System messages applicable to a team are posted in the primary channel.

JSON response examples


The following JSON examples show the responses for each supported event type.

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"
}
}
}
}

Channel description 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.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"
}
}
}
}

Channel set as favorite by default


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.channelSetAsFavoriteByDefaultEventMessageDetail",
"channelId": "19:[email protected]",
"initiator": {
"application": null,
"device": null,
"user": {
"id": "1fb8890f-423e-4154-8fbf-db6809bc8756",
"displayName": null,
"userIdentityType": "aadUser"
}
}
}
}

Channel unset as favorite by default


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.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"
}
}
}
}

Conversation member role 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.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"
}
}
}
}

Meeting policy updated


JSON

{
"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"
}
}
}
}

Team description updated


JSON

{
"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"
}
}
}
}

Team joining disabled


JSON

{
"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"
}
}
}
}

Team joining enabled


JSON

{
"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"
}
}
}
}

Teams app installed


JSON

{
"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"
}
}
}
}

Teams app removed


JSON

{
"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"
}
}
}
}

Teams app upgraded


JSON

{
"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:

Application: An application that is hosted on Azure, also referred to as a bot.

Application instance: A disabled-user object that can be assigned to a phone


number that can be used by a bot. This is also known as a resource account. This is
the only way a phone number can be assigned to a bot.

One application can have multiple application instances, and each tenant can have
multiple application instances, as shown in the following image.

Prerequisite: register a bot


To get started, follow the instructions to register a calling bot . You’ll need config
values such as bot ID, Microsoft app ID, and Microsoft app password to use in your
code.
Add the following permissions to your bot. A tenant admin needs to consent to these
permissions as well:

Calls.AccessMedia.All
Calls.Initiate.All
Calls.JoinGroupCall.All
Calls.JoinGroupCallAsGuest.All

For more information about call-related permissions, see the Permissions reference.

Assign a phone number to your bot


Assigning a phone number to your bot involves three steps:

1. Create an application instance.


2. Assign Microsoft 365 licenses to your application instance.
3. Assign a phone number to the application instance (only tenant admin).

Create an application instance


If it hasn't been installed already, a tenant admin needs to install the Teams module for
PowerShell. The tenant admin must sign in using their credentials before running the
cmdlet.

To create a new application instance, the tenant admin runs the following cmdlet:

PS C:\> New-CsOnlineApplicationInstance -UserPrincipalName <[email protected]> -

ApplicationId <app_id> -DisplayName <bot_display_name>

For more information, see New-CsOnlineApplicationInstance

Assign Microsoft 365 licenses to your application instance


Assign a virtual user license to your application instance. For details, see Phone system
virtual user license.

Assign a calling plan to your application instance. For details, see Calling plans for
Microsoft 365.

Assign a phone number to the application instance (only


tenant admin)
Before you can set up users in your organization to make and receive phone calls, you
must get phone numbers for them. For details, see Getting phone numbers for your
users.

To assign the phone number to the application instance, the tenant admin assigns a
service phone number (+11D format) using the following cmdlet:

PS C:\> Set-CsPhoneNumberAssignment -Identity <[email protected]> -PhoneNumber

<phone_number> -PhoneNumberType <type>

For more information, see Set-CsPhoneNumberAssignment.

Unassign a bot phone number


Use the following cmdlet to unassign a phone number:

PS C:\> Remove-CsPhoneNumberAssignment -Identity <[email protected]> -PhoneNumber


<phone_number> -PhoneNumberType <type>

Update a bot phone number


After unassigning the number, you can assign a different number to the bot by using
the following cmdlet:

PS C:\> Set-CsPhoneNumberAssignment -Identity <[email protected]> -PhoneNumber


<phone_number> -PhoneNumberType <type>

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.

Manage the state of the bot


After you register your bot, decide whether you want your audio and video-based
media to be application-hosted or service-hosted. At a high level, this involves deciding
whether or not you want to access a live-stream of raw media.

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

Service-hosted media bots can be stateful or stateless. Application-hosted media


bots must be stateful in order to use the Bot Media SDK .

Use the SDKs


The following SDKs are available in C#. We will provide support for other languages in
the future.

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.

For more examples, see the Communications samples repository .

Privacy and compliance


In the requests to our APIs, sensitive data should not be sent in any client-side
generated IDs (such as scenario IDs, request IDs, or other correlation IDs) in headers or
the request body. These IDs will be logged on the server side for diagnostics.
See also
Teams API overview
Send proactive installation messages
Article • 01/11/2023

Proactive messaging in Teams


Proactive messages are initiated by bots to start conversations with a user. They serve
many purposes including sending welcome messages, conducting surveys or polls, and
broadcasting organization-wide notifications. Proactive messages in Teams can be
delivered as either ad-hoc or dialog-based conversations:

Message type Description

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

Proactive app installation in Teams


Before your bot can proactively message a user, it must be installed either as a personal
app or in a team where the user is a member. At times, you need to proactively message
users that haven't installed or previously interacted with your app. For example, If you
need to message important information to everyone in your organization, then you can
use the Microsoft Graph API to proactively install your bot for your users.

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:

Application permission Description

TeamsAppInstallation.ReadWriteSelfForUser.All Allows a Teams app to read, install, upgrade,


and uninstall itself for any user, without prior
sign in or use.
Application permission Description

TeamsAppInstallation.ReadWriteSelfForTeam.All Allows a Teams app to read, install, upgrade,


and uninstall itself in any team, without prior
sign in or use.

To use these permissions, you must add a webApplicationInfo key to your app manifest
with the following values:

id: Your Azure Active Directory app ID.


resource: The resource URL for the app.

7 Note

Your bot requires application and not user delegated permissions because the
installation is for others.

An Azure AD tenant administrator must explicitly grant permissions to an


application. After the application is granted permissions, all members of the
Azure AD tenant get the granted permissions.

Enable proactive app installation and


messaging

) Important

Microsoft Graph can only install apps published to your organization's app store or
the Teams store.

Create and publish your proactive messaging bot for


Teams
To get started, you need a bot for Teams with proactive messaging capabilities that is in
your organization's app store or the Teams store.

 Tip

The production-ready Company Communicator app template permits broadcast


messaging and is a good start to build your proactive bot application.
Get the teamsAppId for your app
You can retrieve the teamsAppId in the following ways:

From your organization's app catalog:

Microsoft Graph page reference: teamsApp resource type

HTTP GET request:

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:

Microsoft Graph page reference: List apps installed for user

HTTP GET request:

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:

Microsoft Graph page reference: List apps in team

HTTP GET request:

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.

Determine whether your bot is currently installed for a


message recipient
You can determine whether your bot is currently installed for a message recipient as
follows:

Microsoft Graph page reference: List apps installed for user

HTTP GET request:

HTTP

GET https://graph.microsoft.com/v1.0/users/{user-id}/teamwork/installedApps?
$expand=teamsApp&$filter=teamsApp/id eq '{teamsAppId}'

The request returns:

An empty array if the app isn't installed.


An array with a single teamsAppInstallation object if the app is installed.

Install your app


You can install your app as follows:

Microsoft Graph page reference: Install app for user

HTTP POST request:


HTTP

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.

Retrieve the conversation chatId


When your app is installed for the user, the bot receives a conversationUpdate event
notification that contains the necessary information to send the proactive message.

Microsoft Graph page reference: Get chat

1. You must have your app's {teamsAppInstallationId} . If you don't have it, use the
following:

HTTP GET request:

HTTP

GET https://graph.microsoft.com/v1.0/users/{user-
id}/teamwork/installedApps?$expand=teamsApp&$filter=teamsApp/id eq
'{teamsAppId}'

The id property of the response is the teamsAppInstallationId .

2. Make the following request to fetch the chatId :

HTTP GET request (permission— TeamsAppInstallation.ReadWriteSelfForUser.All ):

HTTP

GET https://graph.microsoft.com/v1.0/users/{user-
id}/teamwork/installedApps/{teamsAppInstallationId}/chat

The id property of the response is the chatId .


You can also retrieve the chatId with the following request but it requires the
broader Chat.Read.All permission:

HTTP GET request (permission— Chat.Read.All ):

HTTP

GET https://graph.microsoft.com/v1.0/users/{user-id}/chats?
$filter=installedApps/any(a:a/teamsApp/id eq '{teamsAppId}')

Send proactive messages


Your bot can send proactive messages after the bot has been added for a user or a
team, and has received all the user information.

Code snippets
The following code provides an example of sending proactive messages:

C#

SDK reference

Sample code reference

C#

public async Task<int>


SendNotificationToAllUsersAsync(ITurnContext<IMessageActivity>
turnContext, CancellationToken cancellationToken)
{
int msgSentCount = 0;

// Send notification to all the members.


foreach (var conversationReference in _conversationReferences.Values)
{
await
turnContext.Adapter.ContinueConversationAsync(_configuration["MicrosoftA
ppId"], conversationReference, BotCallback, cancellationToken);
msgSentCount++;
}

return msgSentCount;
}

private async Task BotCallback(ITurnContext turnContext,


CancellationToken cancellationToken)
{
// Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync("Proactive hello.");
}

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.

Additional code samples

Teams proactive messaging code samples

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

Use discretion when granting the CallRecords.Read.All permission to applications.


Call records can provide insights into the operation of your business, and therefore
can be a target for malicious actors. Only grant this permission to applications you
trust to meet your data protection requirements.

Subscribe to call records


Organizations and partners often have their own tooling for generating reports about
calls and online meetings. Using webhooks, they can receive a continuous feed of call
records as they are created. This push-model enables organizations and partners to
build their own real-time reporting solutions. A call record and its respective notification
are created after a call or meeting ends.

Look up a call record by its call ID


Applications can retrieve a call record by its ID. This ID can be determined from a
webhook notification or retrieved from administrative tools. A call record is generated
after a call concludes and the record is retained for 30 days.

Get call record reports


Organizations that use Microsoft Teams to connect to the public switched telephone
network (PSTN) usually want to track this usage to understand the associated costs. The
getPstnCalls and getDirectRoutingCalls functions return a projection of call record data
in a tabular format.

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:

Create group calls


Join exisiting group calls
Invite other participants into an existing group call
Be invited into existing group calls

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.

Create an online meeting


When you create an online meeting, you'll receive coordinates for the meeting. When
participants join the meeting using these meeting coordinates, a group call is created.

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

The created meetings do not appear on calendars.

Join an online meeting


After an online meeting is created, users can join in two ways:
1. Through the browser, using the joinWebURL that was returned as part of the
meeting coordinates.

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:

Calendar API: use the event resource.


Cloud communications API: use the onlineMeeting resource.

The choice is between:

A convenient programmatic way to set up an online meeting in the Outlook


calendar where attendees click to join the meeting, and continue their experience
in Teams or Skype.
A richer programmatic integration of Teams or Skype features in an app for a more
customized experience.

Considerations when choosing an API for your


scenario
Choose the calendar API for a streamlined, built-in integration with Outlook calendar
that results in an online meeting event in the Outlook calendar:

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.

Comparing the APIs


The following table details the differences at the API level.

Online Calendar API (event resource) Cloud communications API


meeting (onlineMeeting resource)
feature

Main API event resource: onlineMeeting resource


members - isOnlineMeeting property audioConferencing resource
- onlineMeeting property of the
onlineMeetingInfo type
- onlineMeetingProvider property
calendar resource:
-
allowedOnlineMeetingProviders
property
- defaultOnlineMeetingProvider
property
Online Calendar API (event resource) Cloud communications API
meeting (onlineMeeting resource)
feature

Integration - Create API returns an onlineMeeting


with a - Create or update event API resource that is independent of a particular
calendar item automatically sets the resultant calendar type.
Outlook calendar event as an - Does not create or update any Outlook
online meeting. event.
- Use the isOnlineMeeting, - Integrate the returned onlineMeeting
onlineMeeting, and resource information in an app experience
onlineMeetingProvider properties appropriate for your scenario.
of the returned Outlook calendar - Use createOrGet to return an online
event. meeting that has a specified externalId
value, or create one if none already exists,
to streamline embedding the resultant
meeting in a third-party calendar.

Changing to - No - once you enable an event No - once you create an onlineMeeting


offline for joining online, you cannot resource, you can only delete it but cannot
meeting update it to make it an offline change it to an offline meeting.
meeting.
- Cannot change the
onlineMeetingProvider property,
nor set isOnlineMeeting to false
to disable the meeting online.

Locale-based No direct API integration. - Use the Accept-Language HTTP header


join when creating an online meeting.
information - See example.

Joining over Through the onlineMeeting Use the joinWebUrl property.


Internet (VoIP) property, access joinUrl.

Joining by Through the onlineMeeting Through the audioConferencing property,


dial-in property, access: access:
- conferenceId, quickDial, - conferenceId, tollFreeNumber,
phones, tollFreeNumbers, tollNumber.
tollNumber. - dialinUrl property for an externally-
accessible web page that contains dial-in
info to facilitate integration with third-party
apps.

Joining by No direct API integration. Use the videoTeleconferenceId property.


video
conferencing
(audio and
video)
Online Calendar API (event resource) Cloud communications API
meeting (onlineMeeting resource)
feature

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.

Relating to a No direct API integration. Use the chatInfo property.


Teams chat
Choose a media hosting option
Article • 09/02/2022

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.

Service-hosted media (remote hosting)


If you want your bot to play a custom prompt when a customer dials your business's
number, or to detect phone tones, record short voice clips, or perform any of the
various Interactive Voice Response (IVR) scenarios, consider using the service-hosted
media APIs.

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 .

Application-hosted media (local hosting)


If you want your bot to access a live stream of your customers' audio and video to use
for recording, transcribing, translating, or sentiment analysis through a natural language
processing service, consider hosting your media locally.

) 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:

Attendance report of an online meeting, in the form of a JSON response.


Attendance reports have the following characteristics:
Available for meetings other than Teams live events
Only available when the meeting has concluded
Only the meeting organizer can access
Includes guest and federated users that were part of the online meeting
Recordings of a Teams live event, in the form of a download link that expires in 60
seconds. Recordings have the following characteristics:
Only available for Teams live events
Only available when the Teams live event has concluded
Only the Teams live event organizer can access
Attendee report of a Teams live event, in the form of a download link that expires
in 60 seconds. Attendee reports have the following characteristics:
Only available for Teams live events
Only available when the Teams live event has concluded
Only the Teams live event organizer can access

Permissions
The following permissions are available to manage meeting artifacts:

Delegated (work or school account) - OnlineMeetingArtifact.Read.All


Application - OnlineMeetingArtifact.Read.All

Only the OnlineMeetingArtifact.Read.All permissions are required to fetch online


meeting artifacts. Until January 15, 2022, you can use the following permissions to get
meeting artifacts in beta:

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.

Roster example with large gallery view


participant
The following example shows a roster that the application receives after the large gallery
view is successfully added to a call.

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"
}
]
}
]
}

Identify large gallery view participants


Use the following data from the roster example to identify a large gallery view
participant:

The ApplicationType of the participant will be set as LargeGallery-V2 .


The direction of the video media stream will be set to sendReceive .
The metadata will be included that will contain more details such as paging.

Participant data example


The following example shows the data for a large gallery view participant in the roster.

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"
}

Definition for deserializing metadata


Use the following definition to deserialize the metadata property and extract the
relevant information.

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.

The onlineMeeting resource contains the watermarkProtection property to indicate the


watermark option for a sensitive Teams meeting.

Use the following REST calls to manage watermark protection for sensitive Teams
meetings.

Create an online meeting with the watermark


option
The following example shows the watermark properties configured for a new
onlineMeeting. For more details about how to create an online meeting, see Create
onlineMeeting.

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
},
...
}

Update the watermark option in an online


meeting
The following example shows how to update the watermark properties of an
onlineMeeting. For more details about how to update an online meeting, see Update
onlineMeeting.

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
}
}

Get the watermark option in an online meeting


The following example shows how to get an onlineMeeting with its watermark
properties. For more details about how to get an online meeting, see Get
onlineMeeting.

Request
HTTP

GET /me/onlineMeetings/{meetingId}

Response
HTTP

HTTP/1.1 200 OK
Content-type: application/json

{
...
"watermarkProtection": {
"isEnabledForContentSharing" : true,
"isEnabledForVideo" : false
}
}

Restricted experience for meetings with the


watermark option
When a watermark is in use (either watermark option is turned on), applications that use
cloud communications calling APIs get a restricted (audio only) media experience.

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

The maximum time a subscription can last is 60 minutes; however, subscriptions


can be renewed until the caller has permissions to access the resource.

Change notification types


Microsoft Teams supports two types of change notifications:

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 channel Changes to channels in all teams: Yes


/teams/getAllChannels
Changes to channel in a specific team:
/teams/{id}/channels

Teams chat Changes to any chat in the tenant: Yes


/chats
Changes to a specific chat:
/chats/{id}
Changes to any chat in the tenant where a particular Teams
app is installed:
/appCatalogs/teamsApps/{id}/installedToChats

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

Teams Changes to membership in a specific team: Yes


conversationMember /teams/{id}/members
Changes to membership in a specific chat:
/chats/{id}/members
Changes to membership in all chats:
/chats/getAllMembers
Changes to membership in all channels under a specific team:
teams/{id}/channels/getAllMembers
Changes to membership in all the chats in the tenant where a
particular Teams app is installed:
/appCatalogs/teamsApps/{id}/installedToChats/getAllMembers
Changes to membership in all channels across the tenant:
teams/getAllChannels/getAllMembers
Resource Supported resource paths Resource
data can be
included in
notifications

Teams team Changes to any team in the tenant: Yes


/teams
Changes to a specific team:
/teams/{id}

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.

Notifications with resource data


For notifications with resource data, the payload looks like the following. This payload is
for a notification corresponding to the chat message resource. The actual notification
includes the resource and resourceData properties, which represent the resource that
has triggered the notification.

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": []
}

Notifications without resource data


Notifications without resource data give you enough information to make GET calls to
get the resource. Subscriptions for notifications without resource data don't require an
encryption certificate (because actual resource data is not sent over).

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')"
}
}

Previous example above shows a notification that corresponds to a chat message


resource. The actual notification includes the resource and resourceData properties,
which represent the resource that has triggered the notification. The resource and
@odata.id properties can be used 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 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

Change notifications in Microsoft Graph enable you to subscribe to call started/ended


and call roster updates for Microsoft Teams online meetings. 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.

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.

To get change notifications for a meeting's call events, subscribe to


/communications/onlineMeetings/?$filter=JoinWebUrl eq '{JoinWebUrl}' .

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

Permission type Permissions (from least to most Supported


privileged) versions

Delegated (work or school Not supported. Not supported.


account)

Delegated (personal Microsoft Not supported. Not supported.


account)

Application OnlineMeetings.Read.All, beta


OnlineMeetings.ReadWrite.All

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.

Notifications with encrypted resource data


JSON

{
"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.

Event notifications types


The following are the supported meeting events:

CallStarted - Occurs when the meeting call has started.


CallEnded - Occurs when the meeting call has ended.
CallRosterUpdate - Occurs when a participant joins or exits the meeting call.

Decrypted payload examples

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"
}
}
}
]
}

CallRosterUpdate events include two properties, activeParticipants@joined to depict


participants added to a meeting call and activeParticipants@exited for participants
leaving the meeting call.
An active participant is represented as follows:

JSON

{
"Id": "string",
"Identity": "microsoft.graph.communicationsIdentitySet"
}

The Id property corresponds to participant ID, which is a unique identifier assigned


to each participant in the meeting call.
The Identity property corresponds to the communicationsIdentitySet. For details,
see communicationsIdentitySet resource type.

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"
]
}

The following example shows the response.

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')"
}

The following example shows the response.

Note: The response object shown might be shortened for readability. All the
properties will be returned from an actual call.

HTTP

HTTP/1.1 202 Accepted


Content-Type: application/json
Location: /teams/{teamId}/operations/{operationId}
Content-Location: /teams/{teamId}
{
}

The created team has the same ID as the group.

5. After this process finishes, all owners and members should be able to see the
newly created team in their Teams client.

Add or manage members


To add members after a team is created, you use the add member operation. We
recommend adding a 1 second delay between add operations. Note the following with
respect to membership changes:

1. Membership changes made to Microsoft 365 groups sync to Teams via a


background sync mechanism that typically takes 24 hours (or more in some cases).

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.

Validate team creation


1. Verify that the Microsoft 365 group backing the team is created via the Azure AD
or Microsoft 365 admin centers.

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.

Validate addition of members


1. Verify that newly members show up in the group via the Azure AD or Microsoft
365 admin center.

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.

Get a list of groups

Example 1: Get a list of groups that contain a team


To get a list of all groups in the organization that have teams, get a list of all groups, and
then in code find the ones that have a resourceProvisioningOptions property that
contains "Team".

Use the API with $filter to return only the groups that have teams.

Request

HTTP

GET /groups?$filter=resourceProvisioningOptions/Any(x:x eq 'Team')

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.

Note: The response object shown might be shortened for readability.

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"
}
]
}

Example 2: Get a list of groups by selecting required


properties only
Because groups are large objects, use $select to only get the properties of the group
you care about.

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"
]
}
]
}

Get team information for a group


To get team information for the team in a particular group, call the get team API and
include the group ID.

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.

Step 1: Design and set up architecture


The following diagram shows the suggested high-level architecture for an app that
integrates with Teams.

The architecture includes three components:


A chat UI that gets user inputs and displays messages. The chat UI makes API
requests (such as POST / GET chats, POST / GET messages) to Teams APIs. It also gets
new messages in real time from the server component.

A server component that subscribes to change notifications in real time to get


new messages from Teams APIs. When Teams APIs send change notifications, a
webhook URL is required to listen to the change notifications, and your UI, such as
the users' mobile phone, might not have a webhook URL. The server component,
however, has a stable webhook URL. The new messages are then pushed from the
server component to the chat UI, using communication methods such as ASP.NET
SignalR.

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.

Step 2: Create a new chat


Before sending a new chatMessage, you must create a chat by assigning members. The
following example shows how to create a group chat. For more examples that show how
to create different chat types, see Create chat.

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

HTTP/1.1 201 Created


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",
"viewpoint": null,
"onlineMeetingInfo": null
}

Step 3: Send a message in the chat


Members within the chat can send messages to each other. The following example
shows how to send a simple message. For more examples, including sending other
media such as file attachments and adaptive cards, see Send chatMessage.

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

HTTP/1.1 201 Created


Content-type: application/json

{
"@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": []
}

Step 4: Retrieve messages


Use the GET HTTP method on the chatMessages resource to retrieve messages.

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.

Microsoft Graph provides several ways to retrieve chat messages:

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.

We recommend that your app monitors to the chatMessage.policyViolation.dlpAction


field, watches for change notifications to this field, and hides or flags the messages
according to the data loss prevention (DLP) or similar rules defined by your
organization. The valid values are None , NotifySender , and BlockAccess . Currently,
Teams ignores BlockAccessExternal . For details about these values, see
chatMessagePolicyViolation resource type.
Some messages are system messages. For example, the following system message
shows that a new member joined the chat.

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"
}
}
}
}

Step 5: Cache messages


Because each message you get from getAllMessages or change notification is subject to
consumption charges, you will want to minimize reading the same message multiple
times. We recommend that you cache messages for at least a few hours so a user can
quickly reopen a recent chat. Do not cache messages for longer than what is allowed
per your organization's retention policies.

In Step 6, you will decide whether the cache is per-user or not.

Step 6: Subscribe to change notifications


Microsoft Graph offers several kinds of change notifications for messages, as specified
by the corresponding resource properties:

Per chat: "resource": "/chats/{id}/messages"


Per user, across all chats: "resource": "/users/{id}/chats/getAllMessages"
Per tenant, across all chats: "resource": "/chats/getAllMessages"
Per app, across all chats in a tenant where the app is installed: "resource":
"/appCatalogs/teamsApps/{id}/installedToChats/getAllMessages"

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.

Change notification subscriptions have consumption charges. Specify the model


parameter on the resource property, as shown in the following example.

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.

For more details about this example, see Create subscription.

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

HTTP/1.1 201 Created


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?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
}

Step 7: Receive and decrypt change


notifications
Whenever there is a change to the subscribed resource, a change notification is sent to
the notificationUrl. For security reasons, the content is encrypted. To decrypt the
content, see Decrypting resource data from change notifications.

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.

Request (sent by Microsoft Graph)


HTTP

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.

Step 8: Renew change notification


subscriptions
For security reasons, subscriptions for chatMessage expire in 60 minutes. We
recommend that you renew every 30 minutes to allow for some buffer. Lifecycle
notifications for expiring subscriptions are not currently available; therefore, you have to
keep track of the subscriptions and renew them before they expire by updating the
expirationDateTime property, as described in Update subscription. Because renewing
thousands of subscriptions takes time, this is a reason to avoid per-chat change
notifications.

If a subscription expires before it gets renewed, some change notifications might be


missed. Resync the messages by repeating Step 4: Retrieve messages.

The following example shows how to renew a subscription.

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
}

Step 9: Get and set viewpoints


A viewpoint in a chat marks the timestamp at which the chat was last read by users, so
that users can see that any messages under the viewpoint are unread.

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:

50 recipients x (20 senders x 300 messages/month/sender)/recipient x


$0.00075/message = 300,000 messages/month x $0.00075/message =
$225/month.

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

Export Teams content channel: getAllMessages


chats: getAllMessages

Update (DLP patch) Update channel


Update chat
Update chatMessage

Create subscription (change notifications) channel


chat
chatMessage
conversationMember

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:

model=A is restricted to applications performing a security or compliance


function , and requires a supported license.
model=B is restricted to applications that do not perform a security or compliance
function . There are no licensing requirements for model=B .

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

model=A is restricted to applications performing a security or compliance function. For


details, see the API Terms for Security & Compliance Applications section of the product
terms for Microsoft Azure Services .

The following APIs support the model=A parameter.

API Who Seeded Price for Notes


needs a capacity additional
license use

chatMessage change Message 800 $0.00075 Seeded capacity is shared with


notifications sender messages per conversationMember change
per user per message notifications
month per
app

conversationMember Any user 800 $0.00075 Seeded capacity is shared with


change notifications in the notifications per chatMessage change
tenant per user per notification notifications
month per
app

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

Updat a Message 800 $0.00075


chatMessage sender messages per
policyViolation per user per message
month per
app

Required licenses for model=A


The user will need a license that supports the Microsoft Communications DLP service
plan, such as one of these supported licenses. Which user needs the license varies by
API; for details, see model=A requirements.

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.

The following APIs support the model=B parameter.

API Seeded Price for use Notes


capacity

chatMessage change None $0.00075 per


notifications message

conversationMember None $0.00075 per


change notifications notification

chat change notifications None $0.00075 per


message

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.

Evaluation mode (default) requirements


The following APIs support evaluation mode.

API Seeded capacity Price for Notes


additional
use

chatMessage change 500 messages per N/A


notifications month per app

conversationMember 500 messages per N/A


change notifications month per app

chat change 500 messages per N/A


notifications month per app

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.

Update a chatMessage 500 messages per N/A


policyViolation month per app
Seeded capacity
Seeded capacity is the amount of capacity that an app can use before a consumption
meter is charged. Capacity is pooled at the tenant level—the seeded capacity for all
users in the tenant is compared against the app's usage in the tenant. Seeded capacity is
per app per tenant—an app won't run out of seeded capacity if another app runs out.
Seeded capacity is reset at the beginning of each calendar month, and any unused
amount does not get carried over to the next month.

Billing Use cases Seeded License Azure


model capacity required subscription
required

model=A Security and Compliance See model=A Yes (Microsoft Yes


requirements 365 E5 eligible
license)

model=B Backup and restore, migration, None No Yes


sentiment analysis, analytics and
insights

evaluation Backup and restore, migration, 500 messages No No


model sentiment analysis, analytics and per month per
insights app

Payment and billing


On July 5, 2022, billing changes for Teams APIs took effect.

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.

chatMessage: delta – Change notifications API


chats: getAllMessages – Export API
channel: getAllMessages – Export API
Update chatMessage

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.

Error code Scenario Sample error message

402 Passing model=A ...needs a valid license to access this API... ,


(Payment without a Microsoft E5 ...tenant needs a valid license to access this API...
Required) license

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.

View the costs billed for the metered Microsoft


Teams APIs
This section describes how to monitor costs billed for the metered Microsoft Teams
APIs.

A subscription owner, or anyone with appropriate RBAC (Roles Based Access Control)
permissions, can use Cost Analysis to track metered API consumption, as follows:

1. Sign in to the Azure portal at https://portal.azure.com .


2. Go to Cost Management + Billing > Cost Management > Cost analysis .
3. For the filter near the top, select Service name: Microsoft Graph Servies.
4. For the Group by dropdown menu near the right, select Meter.
This view offers a convenient way to observe API consumption per day over a period of
time.

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.

Monitor the number of messages billed for the


metered Teams APIs
This section describes how to monitor the number of messages billed for the metered
Teams APIs. Unlike with cost analysis, this allows you to analyze the usage of messages
within the seeded capacity, not just those above the seeded capacity for billing, if
applicable to the selected licensing models.

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?

Do I need to We recommend that you provide an Azure subscription because most


provide an Azure scenarios use metered APIs. See also protected APIs.
subscription if my
application is not
calling metered
APIs?

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.

Who is responsible The organization that owns the app registration.


for the payment in
the case of
multitenant apps?

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.

Is there a volume Flat rates apply.


discount?

Are these APIs Not at this time.


enrolled in
Microsoft Azure
Consumption
Commitment
(MACC) program?
Protected APIs in Microsoft Teams
Article • 07/22/2022

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:

List channel messages


Get chatMessages in a channel delta
Get channel message
Create subscription for new channel messages
List replies to a message
Get a reply to a message
(List chats doesn't exist, with or without protected API access)
List messages in a chat
Get message in chat
Create subscription for new chat messages
List all hosted content
Get hosted content
Get messages in a deleted team

7 Note

Send message is not a protected API.

Request access to protected APIs


To request access to these protected APIs, complete the following request form . We
usually review access requests every Wednesday and deploy approvals every Friday or
Monday, except during major holiday weeks in the U.S. Submissions during those weeks
are processed the following non-holiday week.

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.

Implementation differences in Microsoft Graph


for US Government L4 cloud
This section describes implementation differences in the Microsoft Graph for US
Government L4 cloud, including the Microsoft 365 GCC and Microsoft 365 GCC High
environments.

List messages in a chat API doesn't support OrderBy


The List messages in a chat API doesn't support the OrderBy OData query parameter in
the Microsoft 365 GCC environment in the Microsoft Graph for US Government L4
national cloud.

List chats API doesn't support OrderBy


The List chats API doesn't support the OrderBy OData query parameter in the Microsoft
Graph for US Government L4 national cloud.

APIs for managing apps installed in a user's personal


scope are not supported
APIs for managing apps installed in a user's personal scope are not supported in
application context in the Microsoft 365 GCC High environment in the Microsoft Graph
for US Government L4 cloud. This includes the following APIs:

List apps installed for user


Install app for user
Get app installed for user
Get chat between user and app
Upgrade installed app for user
Uninstall app for user

Get chat doesn't support chats with meetings


The Get chat API doesn't support chats with meetings associated with them in
application context in the Microsoft 365 GCC High environment in the Microsoft Graph
for US Government L4 national cloud.

Meeting transcript APIs are not supported


APIs associated with meeting transcripts are not supported in the Microsoft Graph for
US Government L4 national cloud. This includes the following APIs:

List transcripts
Get transcript

Soft delete a message is not supported


The Soft delete a message API doesn't work in the Microsoft 365 GCC High environment
in Microsoft Graph for US Government L4 national cloud.

Channel-based APIs are not supported in the context of


shared channels
All the channels based APIs are not supported in the context of shared channels in the
Microsoft Graph for US Government L4 national cloud.
To Do API overview
Article • 03/03/2023

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

Why integrate with To Do?

Ease of organizing and tracking tasks


Microsoft To Do helps you create a list for anything, from work assignments to home
projects to groceries. You can keep track of deadlines by adding reminders, due dates,
and notes. You can access your lists from anywhere with the Microsoft To Do apps for
iOS, Android, Mac, Windows, and the web.

Integrate across Microsoft 365


To Do is the single destination for personal tasks in Microsoft 365. So it’s deeply
integrated with Microsoft 365 hubs, Outlook, and Teams. Tasks created in those
products sync with To Do so you can access and manage them across devices. To Do
integration can help you reach millions of users who use To Do to gather tasks from
Outlook and Teams into one integrated view.

Support task completion using linked resources


Microsoft To Do provides a new entity called linked resource, which you can use to
create tasks that can link back to their original sources. You can use this to seamlessly
integrate To Do in your workflow by creating tasks that link to your product or service.

Common To Do API operations


Operation Request

List all the GET https://graph.microsoft.com/v1.0/me/todo/lists


task lists

List all GET https://graph.microsoft.com/v1.0/me/todo/lists/{todoTaskListId}/tasks


tasks in a
task list

Create a POST https://graph.microsoft.com/v1.0/me/todo/lists/{todoTaskListId}/tasks


new task

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?

To Do API in Microsoft Graph v1.0


To Do API in Microsoft Graph beta
Attach files to a To Do task
Article • 03/02/2023

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.

Step 1: Create an upload session


Create an upload session to attach a file to a todoTask. Specify the file in the input
parameter attachmentInfo.

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.

The uploadSession object in the response also includes the nextExpectedRanges


property, which indicates that the initial upload starting location should be byte 0 .

Permissions
One of the following permissions is required to call this API. To learn more, including
how to choose permissions, see Permissions.

Permission type Permissions (from least to most privileged)

Delegated (work or school account) Tasks.ReadWrite

Delegated (personal Microsoft account) Tasks.ReadWrite

Application Not supported.


Example: Create an upload session for a todoTask

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-"
]
}

Step 2: Use the upload session to upload a


range of bytes of the file
To upload the file, or a portion of the file, append /content to the URL returned in step
1 in the uploadUrl property of the uploadSession resource and make a PUT request on
the appended URL. You can upload the entire file, or split the file into multiple byte
ranges. Each byte range needs to be less than 4 MB.

Specify the request headers and the request body as described in the following sections.

Request headers

Name Type Description

Authorization String Bearer {token}. Required.

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.

Content-Type String The MIME type. Specify application/octet-stream . 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).

Example: First upload to the todoTask

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"]
}

Step 3: Continue uploading byte ranges until


the entire file has been uploaded
Following the initial upload in step 2, continue to upload the remaining portion of the
file, using a similar PUT request as described in step 2, before you reach the expiration
date/time for the session. Use the nextExpectedRanges collection to determine where
to start the next byte range to upload. You might see multiple ranges specified,
indicating parts of the file that the server has not yet received. This is useful if you need
to resume a transfer that was interrupted and your client is unsure of the state on the
service.

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.

Example: Final upload to the todoTask

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

Alternative step: Cancel the upload session


At any point of time before the upload session expires, if you have to cancel the upload,
you can use the same initial URL to delete the upload session. A successful operation
returns an HTTP 204 No Content response code.

Example: Cancel the upload session

Request

The following is an example of a request.

HTTP

DELETE https://graph.microsoft.com/beta/users/6f9a2a92-8527-4d64-837e-
b5312852f36d/todo/lists/AAMDiFkfh=/tasks/AAMkADliMm=/attachmentSessions/AAMk
ADliMm=

Response

The following is an example of the response.

HTTP

HTTP/1.1 204 No content


Excel workbooks and charts API
overview
Article • 06/29/2022

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

Why integrate with Excel?


You can use Microsoft Graph to allow web and mobile applications to read and modify
Excel workbooks stored in OneDrive, SharePoint, or other supported storage platforms.

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.

Generate reports and analyze results


Excel is a flexible reporting and analysis tool, from simple data tables to complex
professional dashboards. Today, we give you full access to all of Excel’s reporting
features, making Excel an online reporting service within Microsoft 365. Imagine any of
the reporting scenarios users create and rely on today pulled into a custom app to
create professional charts or analyze large sets of data intelligently, seamlessly blending
Excel into those customized experiences.
Store and track data
Excel is also a great tool to store and track data. If your information is stored in a
workbook, that data is available to any app that integrates with Microsoft 365. Its
contents are available to read from custom solutions, and those solutions can use Excel
for data storage.

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.

Use the Excel REST API


You can use Microsoft Graph to allow web and mobile applications to read and modify
Excel workbooks stored in OneDrive, SharePoint, or other supported storage platforms.
The Workbook (or Excel file) resource contains all the other Excel resources through
relationships. You can access a workbook through the Drive API by identifying the
location of the file in the URL. For example:

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?

Excel API in Microsoft Graph v1.0


Excel API in Microsoft Graph beta

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.

Excel APIs are called in one of three modes:

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:

CreateSession request: Used to create either a persistent or a non-persistent


session. In a successful response, the session ID will be returned in the id property
in the response body. For details, see Create session.
Sessionful request: Subsequent requests that follow a CreateSession request. They
usually include a workbook-session-id: {session-id} header. The exception is a
poll status request, which uses the long-running operation pattern. For details, see
Work with APIs that take a long time to complete.
Sessionless request: Used in Sessionless mode. These requests don't have a
workbook-session-id: {session-id} header.

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

<img src="data:image/png;base64,{base-64 chart image string}/>

For default behavior, use Image(width=0,height=0,fittingMode='fit') .

Following is an example of a chart image returned with the default parameters.

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

indicates successful execution of the function.

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:

lookup_value (required): The value you want to look up.

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

HTTP code: 200 OK


content-type: application/json;odata.metadata

{
"@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.

Inside a cell, the median function looks like this example:

=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

HTTP code: 200 OK


content-type: application/json;odata.metadata

{
"@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.

Example 1: cell 1 alignment and height


This request updates the vertical alignment, row height, and column height of the first
cell.

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
}

Example 2: cell 1 font style, size, and color


This request updates the font style, size, and color of the first cell.

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"
}

Example 3: cell 1 background color


This request updates the background color of the first cell.

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"
}

Example 4: cell 2 alignment and height


This request updates the vertical alignment, horizontal alignment, row height, and
column height of the second cell.

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
}

Example 5: cell 2 font style and size


This request updates the font style and size of the second cell.

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"
}

Example 6: cell 2 background color


This request updates the background color of the second cell.

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"
}

Example 7: cell 3 alignment and height


This request updates the horizontal alignment, vertical alignment, row height, and
column height of the third cell.

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
}

Example 8: cell 3 font style, size, and color


This request updates the font style, size, and color of the third cell.

Note: The underline property takes Single or Double as values.

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"
}

Example 9: cell 3 background color


This request updates the background color of the third cell.

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.

Add a row or rows to an Excel workbook with a


single REST request
The Excel REST API requires you to POST a simple request body to the REST endpoint
that represents the row collection of an Excel workbook. If you're working with a
notebook in the root folder of the signed-in user's OneDrive account, the REST endpoint
will look like this:

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 .

The POST body looks like this:

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.

Add a row or rows to an Excel workbook in


ASP.NET
You'll find the ASP.NET code that constructs and sends the request in the
GraphResources.cs and GraphService.cs files of the Microsoft Graph Excel Starter
Sample for ASP.NET 4.6 .

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#

public class UserInfo


{
public string Name { get; set; }
public string Address { get; set; }

public class UserInfoRequest


{
public string index { get; set; }
public string[][] values { get; set; }
}

The GraphService.cs class contains an AddInfoToExcel method that populates these


classes, serializes the request information into a JSON object, and then passes that
object as the POST request body.

C#

public async Task<string> AddInfoToExcel(string accessToken, string name,


string address)
{
string endpoint =
"https://graph.microsoft.com/v1.0/me/drive/root:/demo.xlsx:/workbook/tables/
Table1/rows/add";
using (var client = new HttpClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Post,
endpoint))
{
// Populate UserInfoRequest object
string[] userInfo = { name, address };
string[][] userInfoArray = { userInfo };
UserInfoRequest userInfoRequest = new UserInfoRequest();
userInfoRequest.index = null;
userInfoRequest.values = userInfoArray;

// Serialize the information in the UserInfoRequest object


string jsonBody = JsonConvert.SerializeObject(userInfoRequest);
request.Headers.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new
AuthenticationHeaderValue("Bearer", accessToken);
request.Content = new StringContent(jsonBody, Encoding.UTF8,
"application/json");

using (var response = await client.SendAsync(request))


{
if (response.IsSuccessStatusCode)
{
return Resource.Graph_UploadToExcel_Success_Result;
}
return response.ReasonPhrase;
}
}
}
}

Add a row or rows to an Excel workbook in


Angular
You'll find the Angular code that constructs and sends the request in the home.service.ts
file of the Microsoft Graph Excel Starter Sample for Angular .

Since this sample uses TypeScript, it takes advantage of the Microsoft Graph JavaScript
Client Library and the Microsoft Graph TypeScript Types .

The addInfoToExcel function in the home.service.ts file constructs the two-dimensional


string array and the request body that contains the array. It then uses the Microsoft
Graph JavaScript Client Library to construct and send the request. The response comes
back in the form of a Promise.

TypeScript

addInfoToExcel(user: MicrosoftGraph.User) {
const userInfo = [];
const userEmail = user.mail || user.userPrincipalName;
userInfo.push([user.displayName, userEmail]);

const userInfoRequestBody = {
index: null,
values: userInfo
};

const body = JSON.stringify(userInfoRequestBody);

var client = this.getClient();


var url =
`${this.url}/me/drive/root:/${this.file}:/workbook/tables/${this.table}/rows
/add`
return Observable.fromPromise(client
.api(url)
.post(body)
);
}
Add a row or rows to an Excel workbook in
React
You'll find the code that constructs and sends the request in the home.js file of the
Microsoft Graph Excel Starter Sample for React .

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;

const myEmailAddress = me.mail || me.userPrincipalName;


const values = [];

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.

Manage sessions in the most efficient way


If you have more than one call to make within a certain period of time, we recommend
that you create a session and pass the session ID with each request. To represent the
session in the API, use the workbook-session-id: {session-id} header. By doing so, you
can use the Excel APIs in the most efficient way.

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.

Step 1: Create a session

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
}

Step 2: Add a new row to the table

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]]
}

Step 3: Look up a value in the updated table

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

HTTP code: 200 OK


content-type: application/json

{
"value": 5
}

Step 4: Close the session after all the requests are


completed

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

HTTP/1.1 204 No Content

For more details, see Create session and Close session.

Work with APIs that take a long time to


complete
You might notice that some operations take an indeterminate amount time to complete;
for example, opening a large workbook. It is easy to hit timeout while waiting for the
response to these requests. To resolve this issue, we provide the long-running operation
pattern. When you use this pattern, you don't need to worry about the timeout for the
request.

Currently, the session creation Excel API in Microsoft Graph has the long-running
operation pattern enabled. This pattern involves the following steps:

1. Add a Prefer: respond-async header to the request to indicate that it is a long-


running operation when you crate a session.
2. A long-running operation will return a 202 Accepted response along with a
Location header to retrieve the operation status. If the session creation completes
in several seconds, it will return a regular create session response instead of using
the long-running operation pattern.
3. With the 202 Accepted response, you can retrieve the operation status at the
specified location. Operation status values include notStarted , running ,
succeeded , and failed .

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.

Initial request to create session

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

HTTP/1.1 202 Accepted


Location: https://graph.microsoft.com/v1.0/me/drive/items/{drive-item-
id}/workbook/operations/{operation-id}
Content-type: application/json

{
}

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

HTTP/1.1 201 Created


Content-type: application/json

{
"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

HTTP/1.1 500 Internal Server Error


Content-type: application/json

{
"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."
}
}
}
}

Poll status of the long-running create session


With the long-running operation pattern, you can get the creation status at specified
location by using the following request. The suggested interval to poll status is around
30 seconds. The maximum interval should be no more than 4 minutes.

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"
}

The following is the response when the operation status is succeeded .

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}')
}

The following is the response when the operation status is failed .

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.

Acquire session information

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

The following is the 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.

Reduce throttling errors


Excel APIs in Microsoft Graph affect the resource usage of multiple dependency services.
The impact can vary between different requests: for example, you might expect that
updating a short string in a single cell of a small workbook would consume fewer
resources than adding a big table with complex formulas to a large workbook.

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.

Throttling and concurrency


Another factor related to throttling is request concurrency. We don't recommend
increasing concurrency when using Excel APIs (for example, parallelizing the requests to
the same workbook), especially for write requests. Instead, unless there is a specific
concern, such as significant networking overhead compared to very short request
execution time, we recommend sequential usage in the most common case: for each
workbook, only send the next request after receiving a successful response to the
current request.

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.

Error codes and messages


The following table lists the current error codes and messages. The service might add
new error codes at any time.

Status Error Code Error Message


Code

400 badRequest The request is malformed or incorrect.

401 unauthorized The caller is not authenticated.

403 forbidden The caller doesn't have permission to perform the action.

404 notFound The resource could not be found.

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.

413 payloadTooLarge The request size exceeds the maximum limit.

429 tooManyRequests The app or user has been throttled.

500 internalServerError An internal server error occurred while processing the request.

501 notImplemented The requested feature isn’t implemented.

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.

Detailed error codes


The following are required error codes that your app might encounter within the first-
level of nested innerError objects. The service might add new error codes at any time.

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.

Types of error responses


Excel APIs in Microsoft Graph return two types of errors. One is the regular error
response, which looks like the following.

HTTP

HTTP/1.1 <HTTP status code>


Content-type: application/json
Retry-After: <Cooldown duration in seconds> (optional)

{
"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" }
}
}

Steps to handle error responses


Microsoft Graph clients are expected to use the following steps to handle errors that
occur with Excel APIs.

1. Determine whether it is a long-running operation error


Before handling an error, the first step is to determine whether the error response is
from a long-running operation pattern or a regular pattern. A long-running operation
error will return a 200 OK HTTP status code and failed operation status in response
body. A regular error response will return a corresponding HTTP error status code.

2. Parse second-level error code


For both the long-running operation pattern and the regular pattern, the client should
first parse required second-level error codes and handle them according to the
instructions. Optionally, the client can also handle other second-level error codes, or
choose to fall back to top-level error codes or status codes.

The error codes are case insensitive.


Required second-level error codes
The following table lists instructions for required second-level error codes that Microsoft
Graph clients are expected to handle. The service might add new error codes at any
time.

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.

badRequestUncategorized An unspecified error is found in the failed request. The


Microsoft Graph client is not expected to resend the failed
request.

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.

forbiddenUncategorized The failed request is not allowed. The Microsoft Graph


client is not expected to resend the failed request. An end
user can choose to manually perform the same operations
with Excel Online to get more details about the restrictions.

gatewayTimeoutUncategorized The service wasn’t able to complete the request within the
time limit.

internalServerErrorUncategorized An unspecified error has occurred. The Microsoft Graph


client is not expected to resend the failed request. If a
session is specified in the failed request, further access to
the session is not expected either.

invalidSessionAccessConflict The session specified in the request is invalid due to


conflicts with other clients that are accessing the workbook
(for example, another client has locked the workbook for
edit). Further access to the session specified in the failed
request is not expected. Recreating sessions with the same
createSession request is not expected until the conflict is
resolved. Recreating sessions with a different createSession
request might or might not succeed. An end user can
choose to manually perform the same operations with Excel
Online to get more details about the conflict.
Code Instructions

invalidSessionAuthentication The session specified in the request is invalid due to an


authentication error. Further access to the session specified
in the failed request is not expected. Recreating sessions
with the same createSession request is not expected until
appropriate authentication information is provided.

invalidSessionNotFound The session specified in the request is invalid because the


workbook can’t be found. Further access to the session
specified in the failed request is not expected. Recreating
sessions with the same createSession request is not
expected.

invalidSessionReCreatable The session specified in the request does not exist or is


invalid due to a transient error. The Microsoft Graph client
can try to recreate a session and resume the work. Further
access to the session specified in the failed request is not
expected.

invalidSessionRestricted The session specified in the request is invalid due to service


configurations or restrictions. Further access to the session
specified in the failed request is not expected. Recreating
sessions with the same createSession request is not
expected until the restrictions or configurations blocking
the request changes. Recreating sessions with a different
createSession request might or might not succeed. An end
user can choose to manually perform the same operations
with Excel Online to get more details of the restrictions.

invalidSessionUnexpected The session specified in the request is invalid due to an


unexpected issue. Further access to the session specified in
the failed request is not expected. Recreating sessions with
the same createSession request is not expected. Recreating
sessions with a different createSession request might or
might not succeed.

invalidSessionUnsupportedWorkbook The session specified in the request is invalid because the


workbook contains unsupported features or exceeds the
size limit. Usually the unsupported factors are introduced
by another client accessing the workbook. Further access to
the session specified in the failed request is not expected.
Recreating sessions with the same createSession request is
not expected until the unsupported factors are removed.
Recreating sessions with a different createSession request
might or might not succeed. An end user can choose to
manually perform the same operations with Excel Online to
get more details of the unsupported factors, or with Excel
Desktop where the workbook might be supported.
Code Instructions

methodNotAllowedUncategorized 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.

notFoundUncategorized The requested resource cannot be found. The Microsoft


Graph client is not expected to resend the failed request.

notImplementedUncategorized The requested feature is not currently implemented. The


Microsoft Graph client is not expected to resend the failed
request.

payloadTooLargeUncategorized The request payload exceeds the size limit. The Microsoft
Graph client is not expected to resend the failed request.

serviceUnavailableUncategorized The service is temporarily unavailable or is overloaded. The


Microsoft Graph client is not expected to resend the failed
request until the specified cooldown duration passes.

tooManyRequestsUncategorized The failed request exceeds certain frequency limitation. The


Microsoft Graph client is not expected to resend the failed
request until the specified cooldown duration passes. For
best practices to reduce throttling, see Reduce throttling
errors.

transientFailure The request failed due to a transient error. The Microsoft


Graph client is not expected to resend the failed request
until the specified cooldown duration passes.

unauthorizedUncategorized Required authentication information for the resource is


either missing or invalid. The Microsoft Graph client is not
expected to resend the failed request.

unsupportedWorkbook The request failed. The workbook contains unsupported


features or exceeds the size limit. The Microsoft Graph
client is not expected to resend the failed request until the
unsupported factors are removed.

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.

Optional second-level error code examples


The following table lists examples of optional second-level error codes, including the
corresponding handling instructions for each error code. The service might add new
error codes at any time.

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.

insertDeleteConflict The insert or delete operation attempted resulted in a conflict. The


Microsoft Graph client is not expected to resend the failed request. An
end user can choose to manually perform the same operations with
Excel Online to get more details about the conflict.

invalidArgument The argument is invalid, missing or has an incorrect format. 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.

3. Parse the top-level error code


If you can't find any known second-level error code, you should follow the instructions
provided for top-level errors. The top-level error codes are bound to the status code
and you can take action according to the corresponding status codes. For details about
top-level error codes and messages, see Error codes and messages.

4. Parse the status code


For the regular pattern, if you couldn't find any known second-level error code or top-
level error code, you should take action according to the HTTP status code.

5. Error recovery cooldown


For some of the responses in the regular pattern, a recovery cooldown duration in
seconds might be provided via a Retry-After header. When a recovery cooldown
duration is present, the Microsoft Graph client is not expected to send any follow-up
requests before the specified duration passes. For best practices related to Retry-After
header and throttling, see Reduce throttling errors.

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.

Special case handling


For sessionful requests, if you encounter a 502/badGateway or 503/serviceUnavailable
error, when a known second-level error code is found, follow the corresponding
instructions; otherwise, you should recreate the session directly.

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

Authentication and authorization basics

App registration

Choose an authentication provider

Permissions overview

q VIDEO

Microsoft Graph and app registration (7:29)

How delegated permissions work (1:21)

Authorize your app

c HOW-TO GUIDE

Get access on behalf of a user

Get access without a user

i REFERENCE

Permissions reference

Manage your app

c HOW-TO GUIDE

Manage app access

Limit mailbox access

i REFERENCE

Authorization errors

Auth SDKs - MSAL

a DOWNLOAD

Android

Angular

ASP.NET

iOS

JavaScript

Python

UWP

Xamarin

Auth SDKs - Open source

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.

Register the application


Before your app can get an access token from the Microsoft identity platform, it must be
registered in the Azure portal . Registration integrates your app with the Microsoft
identity platform and establishes the information that it uses to get tokens, including:

Application ID: A unique identifier assigned by the Microsoft identity platform.


Redirect URI/URL: One or more endpoints at which your app receives responses
from the Microsoft identity platform. (For native and mobile apps, the URI is
assigned by the Microsoft identity platform.)
Client secret: A password that your app uses to authenticate with the Microsoft
identity platform. You can optionally use a certificate or a federated identity
credential. This property isn't required for public clients like native, mobile and
single page applications.

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, an app acting on behalf of a signed-in user.


App-only access, an app acting with its own identity.
Delegated access (access on behalf of a user)
In this access scenario, a user has signed into a client application and the client
application calls Microsoft Graph on behalf of the user. Both the client and the user must
be authorized to make the request.

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.

App-only access (access without a user)


In this access scenario, the application can interact with data on its own, without a
signed in user. App-only access is used in scenarios such as automation and backup, and
is mostly used by apps that run as background services or daemons. It's suitable when
it's undesirable to have a user signed in, or when the data required can't be scoped to a
single user.

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 permissions


Microsoft Graph exposes granular permissions that control the access that apps have to
Microsoft Graph resources, like users, groups, and mail. As a developer, you decide
which Microsoft Graph permissions to request for your app based on the access
scenario and the operations you want to perform.

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:

May be preauthorized for the application by an administrator.


May be consented by the user directly.
If not preauthorized, may require administrator privileges to grant consent. For
example, for permissions with a greater potential security impact.

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).

The following example shows a Microsoft identity platform access token:

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

GET https://graph.microsoft.com/v1.0/me/ HTTP/1.1


Host: graph.microsoft.com
Authorization: Bearer EwAoA8l6BAAU ... 7PqHGsykYj7A0XqHCjbKKgWSkcAg==

Get an access token


We recommend that you use authentication libraries to manage your token interactions
with the Microsoft identity platform. Authentication libraries abstract many protocol
details like validation, cookie handling, token caching, and maintaining secure
connections, that lets you focus your development on your app's functionality. Microsoft
publishes open-source client libraries and server middleware.

For the Microsoft identity platform endpoint:

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:

Get access on behalf of a user


Get access without a user

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.

Follow these steps to create the app registration:

1. Sign in to the Azure portal .


2. If you have access to multiple tenants, use the Directories + subscriptions filter
in the top menu to switch to the tenant in which you want to register the
application.

3. Search for and select Azure Active Directory.

4. Under Manage, select App registrations > New registration.

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.

This type of app is known as a multitenant application in the Microsoft


identity platform.

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.

8. Select Register to complete the initial app registration.


When registration finishes, the Azure portal displays the app registration's Overview
pane. You see the Application (client) ID. Also called the client ID, this value uniquely
identifies your application in the Microsoft identity platform.

) 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.

Your application's code, or more typically an authentication library used in your


application, also uses the client ID. The ID is used as part of validating the security
tokens it receives from the identity platform.
Add a redirect URI
A redirect URI is the location where the Microsoft identity platform redirects a user's
client and sends security tokens after authentication.

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.

Configure platform settings


Settings for each application type, including redirect URIs, are configured in Platform
configurations in the Azure portal. Some platforms, like Web and Single-page
applications, require you to manually specify a redirect URI. For other platforms, like
mobile and desktop, you can select from redirect URIs generated for you when you
configure their other settings.

To configure application settings based on the platform or device you're targeting,


follow these steps:

1. In the Azure portal, in App registrations, select your application.

2. Under Manage, select Authentication.


3. Under Platform configurations, select Add a platform.

4. Under Configure platforms, select the tile for your application type (platform) to
configure its settings.

Platform Configuration 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.

Select this platform if you're building a client-side web app by using


JavaScript or a framework like Angular, Vue.js, React.js, or Blazor
WebAssembly.
Platform Configuration settings

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

For desktop applications using system browser, we recommend


http://localhost

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.

5. Select Configure to complete the platform configuration.

Redirect URI restrictions


There are some restrictions on the format of the redirect URIs you add to an app
registration. For details about these restrictions, see Redirect URI (reply URL) restrictions
and limitations.

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.

1. In the Azure portal, in App registrations, select your application.


2. Select Certificates & secrets > Certificates > Upload certificate.
3. Select the file you want to upload. It must be one of the following file types: .cer,
.pem, .crt.
4. Select Add.

Option 2: Add a client secret


Sometimes called an application password, a client secret is a string value your app can
use in place of a certificate to identity itself.

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.

Option 3: Add a federated credential


Federated identity credentials are a type of credential that allows workloads, such as
GitHub Actions, workloads running on Kubernetes, or workloads running in compute
platforms outside of Azure access Azure AD protected resources without needing to
manage secrets using workload identity federation.

To add a federated credential, follow these steps:

1. In the Azure portal, in App registrations, select your application.

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:

1. Understand the authentication and authorization concepts in the Microsoft identity


platform. For more information, see Authentication and authorization basics.
2. Register the app with Azure AD. For more information, see Register an application
with the Microsoft identity platform.

Authentication and authorization steps


For an app to get authorization and access to Microsoft Graph using the authorization
code flow, you must follow these five steps:

1. Register the app with Azure AD.


2. Request authorization.
3. Request an access token.
4. Use the access token to call Microsoft Graph.
5. [Optional] Use the refresh token to renew an expired access token.
 Tip

Try steps 2-5 in Postman. Don't forget to replace tokens and IDs!

1. Register the app


Before the app can call the Microsoft identity platform endpoints or Microsoft Graph, it
must be properly registered. Follow the steps to register your app on the Azure portal.

From the app registration, save the following values:

The application ID (object ID) assigned by the app registration portal.


A redirect URI (or reply URL) for the app to receive responses from Azure AD.
A client secret (application password), a certificate, or a federated identity
credential. This property isn't needed for public clients like native, mobile and
single page applications.

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

// Line breaks for legibility only

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

Parameter Required Description

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

scope Required A space-separated list of the Microsoft Graph permissions that


you want the user to consent to. Don't percent-encode the
spaces. These permissions can include resource permissions,
such as User.Read and Mail.Read, and OIDC scopes, such as
offline_access , which indicates that the app needs a refresh
token for long-lived access to resources.

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.

User consent experience


After the app sends the authorization request, the user is asked to enter their credentials
to authenticate with Microsoft. The Microsoft identity platform v2.0 endpoint ensures
that the user has consented to the permissions indicated in the scope query parameter.
If there is any permission that the user or administrator has not consented to, they're
asked to consent to the required permissions. For more information about the Azure AD
consent experience, see Application consent experience and Introduction to permissions
and consent.

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.

3. Request an access token


The app uses the authorization code received in the previous step to request an access
token by sending a POST request to the /token endpoint.

Token request

HTTP

// Line breaks for legibility only

POST /{tenant}/oauth2/v2.0/token HTTP/1.1


Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

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

Parameter Required Description

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.

grant_type Required Must be authorization_code for the authorization code flow.

scope Required A space-separated list of scopes. Don't percent-encode the spaces.


The scopes that your app requests in this leg must be equivalent to or
a subset of the scopes that it requested in the authorization leg in Step
2. If the scopes specified in this request span multiple resource servers,
then the v2.0 endpoint returns a token for the resource specified in the
first scope.

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..."
}

Response body properties

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.

expires_in How long the access token is valid (in seconds).

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.

4. Use the access token to call Microsoft Graph


After you have an access token, the app uses it to call Microsoft Graph by attaching the
access token as a Bearer token to the Authorization header in an HTTP request. The
following request gets the profile of the signed-in user.

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"
}

5. Use the refresh token to renew an expired


access token
Access tokens are short lived, and the app must refresh them after they expire to
continue accessing resources. The app does so by submitting another POST request to
the /token endpoint, this time:

Providing the refresh_token instead of the code in the request body


Specifying refresh_token as the grant_type, instead of authorization_code .

Request

HTTP

// Line breaks for legibility only

POST /{tenant}/oauth2/v2.0/token HTTP/1.1


Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

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

Parameter Required Description

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.

grant_type Required Must be refresh_token .

scope Optional A space-separated list of permissions (scopes). Don't percent-encode


the spaces. The permissions that your app requests must be
equivalent to or a subset of the permissions that it requested in the
original authorization code request in Step 2.
Parameter Required Description

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...",
}

Response body parameters

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 .

expires_in How long the access token is valid (in seconds).

scope The permissions (scopes) that the access_token is valid for.

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.

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 authorization
code 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.

1. Article 1: Authentication and authorization basics


2. Article 2: Register an application with the Microsoft identity platform
3. Article 3: Get access on behalf of a user
4. Article 4: Get access without a user

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:

1. Understand the authentication and authorization concepts in the Microsoft identity


platform. For more information, see Authentication and authorization basics.
2. Register the app with Azure AD. For more information, see Register an application
with the Microsoft identity platform.

Authentication and authorization steps


For an app to get authorization and access to Microsoft Graph using the client
credentials flow, you must follow these five steps:

1. Register the app with Azure AD.


2. Configure Microsoft Graph application permissions on the app.
3. Request administrator consent.
4. Request an access token.
5. Call Microsoft Graph using the access token.
 Tip

Try steps 2-5 in Postman. Don't forget to replace tokens and IDs!

1. Register the app


Before the app can use the Microsoft identity platform endpoint or call Microsoft Graph,
it must be properly registered. Follow the steps to register your app on the Azure portal.

From the app registration, save the following values:

The application ID (object ID) assigned by the app registration portal.


A client secret (application password), a certificate, or a federated identity
credential.
A redirect URI for the app to receive token responses from Azure AD.
A redirect URI for the service to receive admin consent responses if the app
implements functionality to request administrator consent.

2. Configure permissions for Microsoft Graph


Microsoft Graph exposes application permissions for apps that call Microsoft Graph
under their own identity. These permissions always require administrator consent.

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:

Under the application's API permissions page, choose Add a permission.


Select Microsoft Graph.
Select Application permissions.
In the Select Permissions dialog, choose the permissions to configure to the app.

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.

3. Request administrator consent


Administrators can grant the permissions your app needs at the Azure portal .
However, when you don't have access to the Azure portal, you can provide a sign-up
experience for administrators by using the Microsoft identity platform /adminconsent
endpoint.

) 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

// Line breaks are for legibility only.

GET https://login.microsoftonline.com/{tenant}/adminconsent
?client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&state=12345
&redirect_uri=https://localhost/myapp/permissions

Parameter Condition Description

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.

Administrator consent experience


With requests to the /adminconsent endpoint, Azure AD enforces that only an
authorized administrator can sign in to complete the request. The administrator is asked
to approve all the application permissions that you've requested for your app in the app
registration portal.

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

// Line breaks are for legibility only.

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.

admin_consent Set to True.

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

4. Request an access token


In the OAuth 2.0 client credentials grant flow, you use the application ID and client
secret values that you saved when you registered your app to request an access token
directly from the Microsoft identity platform /token endpoint.

You specify the pre-configured permissions by passing


https://graph.microsoft.com/.default as the value for the scope parameter in the
token request.

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

// Line breaks are for legibility only.

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

Parameter Condition Description

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.

grant_type Required Must be client_credentials .

Token response

A successful response looks like this:

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.

expires_in How long the access token is valid (in seconds).

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 .

5. Use the access token to call Microsoft Graph


After you have an access token, the app uses it to call Microsoft Graph by attaching the
access token as a Bearer token to the Authorization header in an HTTP request. The
following request gets all users in the tenant. The app must have the User.Read.All
permission to call this API.

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"
}
]
}

Supported app scenarios and resources


Apps that call Microsoft Graph under their own identity fall into one of two categories:

Background services (daemons) that run on a server without a signed-in user.


Apps that have a signed-in user but also call Microsoft Graph with their own
identity. For example, to use functionality that requires more elevated privileges
than the user has.

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.

1. Article 1: Authentication and authorization basics


2. Article 2: Register an application with the Microsoft identity platform
3. Article 3: Get access on behalf of a user
4. Article 4: Get access without a user

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.

Microsoft Graph tutorials >


Overview of Microsoft Graph
permissions
Article • 05/25/2023

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:

Tom created or owns the files.


The files were shared directly with Tom, or indirectly shared with him through a
team or group membership.
Tom has been granted permissions through a role-based access control (RBAC)
system such as Azure AD RBAC.

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.

Comparison of delegated and application permissions

Delegated permissions Application permissions

Types of apps Web app / Mobile / Single-page app Web / Daemon


(SPA)

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

Other names Scopes App roles


OAuth2 permissions App-only permissions
Direct access permissions

Result of oAuth2PermissionGrant appRoleAssignment


consent

Supported AzureADMyOrg AzureADMyOrg


signInAudience AzureADMultipleOrgs AzureADMultipleOrgs
types AzureADandPersonalMicrosoftAccount AzureADandPersonalMicrosoftAccount
PersonalMicrosoftAccount

The following image illustrates an app's privileges in delegated vs app-only access


scenarios.
Permissions naming pattern
Microsoft Graph exposes granular permissions that help you control the access that
apps have to Microsoft Graph resources, like users, groups, and mail. These permissions
are named in the following pattern:

{resource}.{operation}.{constraint}

Value Description Examples

{resource} Refers to a Microsoft Graph resource to which the permission User ,


allows access. For example, the user resource. Application ,
or Group

{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.

Limited information returned for inaccessible


member objects
Container objects such as groups support members of various types, for example users
and devices. When an application with the right privileges queries the membership of a
container object, it receives a 200 OK response and a collection of objects. However, if
the app doesn't have the permissions to read a certain object type in the container,
objects of that type are returned but with limited information, for example, only the
object type and ID may be returned and other properties are indicated as null .
Complete information is returned for the object types that the app has permissions to
read.

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

The following object is an example of the 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
}
]
}

Best practices for using Microsoft Graph


permissions
Microsoft Graph exposes granular permissions that allow an app to request only the
permissions it requires to function. Granular permissions allow you to apply the principle
of least privilege when assigning and granting permissions to an app, by granting the
app the minimum permission it needs for the operation.

Consider the following examples:

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.

Limits on requested permissions per app


Azure AD limits the number of permissions that can be requested and consented by a
client app. These limits depend on the signInAudience value for an app, shown in the
app's manifest.

signInAudience Allowed Maximum Maximum Maximum


users permissions Microsoft permissions
the app can Graph that can be
request permissions consented
the app can in a single
request request

AzureADMyOrg Users from 400 400 About 155


the delegated
organization permissions
where the and about
app is 300
registered application
permissions

AzureADMultipleOrgs Users from 400 400 About 155


any Azure delegated
AD permissions
organization and about
300
application
permissions

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

Retrieve permission IDs through Microsoft


Graph
To set permissions using the Azure CLI, PowerShell, or infrastructure as code
frameworks, you may need the identifier for the permission that you want to use instead
of the name.
To find the IDs for all Microsoft Graph permissions, see All permissions and IDs.
Alternatively, you can read the permissions programmatically through the Get
servicePrincipal API in Microsoft Graph.

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.

Access reviews permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin


Consent
Required

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.

Administrative units permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

AdministrativeUnit.Read.All Read Allows the app to read administrative Yes No


administrative units and administrative unit
units membership on behalf of the signed-in
user.

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.

AdministrativeUnit.Read.All and AdministrativeUnit.ReadWrite.All are valid only for work or school


accounts.

Example usage

7 Note

The v1.0 endpoint for the administrative units API is /v1.0/directory/administrativeUnits .

AdministrativeUnit.Read.All: Read administrative units ( GET /beta/administrativeUnits )


AdministrativeUnit.Read.All: Read members list of an administrative unit ( GET
/beta/administrativeUnits/<id>/members )

AdministrativeUnit.ReadWrite.All: Create an administrative unit ( POST /beta/administrativeUnits )


AdministrativeUnit.ReadWrite.All: Update an administrative unit ( PATCH
/beta/administrativeUnits/<id> )
AdministrativeUnit.ReadWrite.All: Add members to an administrative unit ( POST
/beta/administrativeUnits/<id>/members )

For more complex scenarios involving multiple permissions, see Permission scenarios.

Analytics resource permissions

Delegated permissions

Permission Display Description Admin


String Consent
Required
Permission Display Description Admin
String Consent
Required

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

Analytics.Read: List related settings for a user ( GET /beta/me/analytics/settings )

Application

None.

AppCatalog resource permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required Required

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.

Application resource permissions

Delegated permissions

Permission Display Description Admin


String Consent
Required

Application.Read.All Read Allows the app to read applications and Yes


applications service principals on behalf of the signed-in
user.

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

DelegatedPermissionGrant.ReadWrite.All Manage Allows the app to manage delegated Yes


delegated permission grants for any API (including
permission Microsoft Graph), on behalf of the signed-in
grants user.

Application permissions

Permission Display Description Admin


String Consent
Required

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.

Application.ReadWrite.OwnedBy Manage Allows the calling app to create other Yes


apps that applications and service principals, and fully
this app manage those applications and service
creates or principals (read, update, update application
owns secrets and delete), without a signed-in user. It
cannot update any applications that it is not an
owner of. 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

Permissions that allow granting authorization, such as AppRoleAssignment.ReadWrite.All, allow an


application to grant additional privileges to itself, other applications, or any user. Likewise,
permissions that allow managing credentials, such as Application.ReadWrite.All, allow an application
to act as other entities, and use the privileges they were granted. Use caution when granting any of
these permissions.

The Application.ReadWrite.OwnedBy permission allows the same operations as Application.ReadWrite.All


except that the former allows these operations only on applications and service principals that the calling
app is an owner of. Ownership is indicated by the owners navigation property on the target application or
service principal resource.

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

Application.Read.All: List all applications ( GET /v1.0/applications )

Application.ReadWrite.All: Delete a service principal ( DELETE /v1.0/servicePrincipals/{id} )

Application.ReadWrite.OwnedBy: Create an application ( POST /v1.0/applications )

Application.ReadWrite.OwnedBy: List all applications owned by the calling application ( GET


/v1.0/servicePrincipals/{id}/ownedObjects )

Application.ReadWrite.OwnedBy: Add another owner to an owned application ( POST


/v1.0/applications/{id}/owners/$ref ).

NOTE: This may require additional permissions.

Audit log permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported
Permission Display Description Admin Microsoft
String Consent Account
Required supported

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

Permission Display String Description Admin Consent


Required

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.

Authentication events flow permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

EventListener.Read.All Read your Allows the app to read your Yes No


organization's organization's authentication event
authentication event listeners on behalf of the signed-in
listeners user.

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

Permission Display String Description Admin


Consent
Required

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.

BitLocker recovery key permissions


Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

Bookings.Read.All Allows an app to read Intended for read-only No No


Bookings applications. Typical target
appointments, user is the customer of a
businesses, customers, booking business.
services, and staff on
behalf of the signed-in
user.
Permission Display String Description Admin Microsoft
Consent Account
Required supported

BookingsAppointment.ReadWrite.All Allows an app to read Intended for scheduling No No


and write Bookings applications which need to
appointments and manipulate appointments
customers, and and customers. Cannot
additionally allows change fundamental
reading businesses, information about the
services, and staff on booking business, nor its
behalf of the signed-in services and staff members.
user. Typical target user is the
customer of a booking
business.

Bookings.ReadWrite.All Allows an app to read Intended for management No No


and write Bookings applications that manipulate
appointments, existing businesses, their
businesses, customers, services and staff members.
services, and staff on Cannot create, delete, or
behalf of the signed-in change the publishing
user. Does not allow status of a booking
create, delete, or business. Typical target user
publish of Bookings is the support staff of an
businesses. organization.

Bookings.Manage.All Allows an app to read, Allows the app to have full No 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.

Application permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

Bookings.Read.All Allows an app to read Intended for read-only Yes No


Bookings applications. Typical target
appointments, user is the customer of a
businesses, customers, booking business.
services, and staff on
behalf of the signed-in
user.
Permission Display String Description Admin Microsoft
Consent Account
Required supported

BookingsAppointment.ReadWrite.All Allows an app to read Intended for scheduling Yes No


and write Bookings applications which need to
appointments and manipulate appointments
customers, and and customers. Cannot
additionally allows change fundamental
reading businesses, information about the
services, and staff on booking business, nor its
behalf of the signed-in services and staff members.
user. Typical target user is the
customer of a booking
business.

Bookings.ReadWrite.All Allows an app to read Intended for management Yes No


and write Bookings applications that manipulate
appointments, existing businesses, their
businesses, customers, services and staff members.
services, and staff on Cannot create, delete, or
behalf of the signed-in change the publishing
user. Does not allow status of a booking
create, delete, or business. Typical target user
publish of Bookings is the support staff of an
businesses. organization.

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 ).

Browser management permissions


Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

BrowserSiteLists.Read.All Read browser Allows an app to read the browser site No No


site lists for your lists configured for your organization,
organization on behalf of the signed-in user.

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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} )

Business scenarios permissions


Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

BusinessScenarioConfig.Read.All Read business Allows the app to read the Yes No


scenario configurations for the
configurations business scenarios of your
organization, on behalf of
the signed-in user.

BusinessScenarioConfig.Read.OwnedBy Read business Allows the app to read the Yes No


scenario configurations of business
configurations scenarios it owns, on
this app behalf of the signed-in
creates or user.
owns

BusinessScenarioConfig.ReadWrite.All Read and write Allows the app to read Yes No


business and write the
scenario configurations for the
configurations business scenarios of your
organization, on behalf of
the signed-in user.

BusinessScenarioConfig.ReadWrite.OwnedBy Read and write Allows the app to create Yes No


business new business scenarios
scenario and fully manage the
configurations configurations of
this app scenarios it owns, on
creates or behalf of the signed-in
owns user.

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.

BusinessScenarioData.ReadWrite.OwnedBy Read and write Allows the app to fully Yes No


all data for manage all data
business associated with the
scenarios this business scenarios it owns.
app creates or Data access and changes
owns will be attributed to the
signed-in user.

Application permissions

Permission Display String Description Admin


Consent
Required
Permission Display String Description Admin
Consent
Required

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 )

BusinessScenarioData.ReadWrite.OwnedBy: Delete a Planner task in a business scenario ( DELETE


/solutions/businessScenarios/c5d514e6c6864911ac46c720affb6e4d/planner/tasks/M60dlXLEkk-

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

Permission Display String Description Admin


Consent
Required

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

Permission Display Description Admin


String Consent
Required

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 ).

Note: For request examples, see Create call.

For more complex scenarios involving multiple permissions, see Permission scenarios.

Call records permissions

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

e={start date and time),toDateTime={end date and time)) )


CallRecord-PstnCalls.Read.All: Retrieve PSTN call records within the specified time range ( GET
/v1.0/communications/callRecords/microsoft.graph.callRecords.getPstnCalls(fromDateTime={start

date and time),toDateTime={end date and time)) )

For more complex scenarios involving multiple permissions, see Permission scenarios.
Channel permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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.

Channel.Create Create channels. Create channels in any team, on Yes No


behalf of the signed-in user.

Channel.Delete.All Delete channels. Delete channels in any team, on Yes No


behalf of the signed-in user.

Application permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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.

Channel.Create Create channels. Create channels in any team, Yes No


without a signed-in user.

Channel.Delete.All Delete channels. Delete channels in any team, Yes No


without a signed-in user.

Teamwork.Migrate.All Manage migration to Creating and managing resources Yes Yes


Microsoft Teams for migration to Microsoft Teams

Channel member permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

ChannelMember.Read.All Read the Read the members of channels, on behalf of Yes No


members the signed-in user.
of
channels.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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.

Channel message permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

ChannelMessage.Edit Edit user's Allows an app to edit channel messages in Yes No


(private preview) channel Microsoft Teams, on behalf of the signed-in
messages user.

ChannelMessage.Read.All Read user Allows an app to read a channel's messages Yes No


channel in Microsoft Teams, on behalf of the signed-
messages in user.

ChannelMessage.Send Send Allows an app to send channel messages in No No


channel Microsoft Teams, on behalf of the signed-in
messages user.

Application permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported
Permission Display Description Admin Microsoft
String Consent Account
Required supported

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.

ChannelMessage.UpdatePolicyViolation.All Flag Allows the app to update Yes No


channel Microsoft Teams channel
messages messages by patching a set of
for Data Loss Prevention (DLP) policy
violating violation properties to handle the
policy output of DLP processing.

Note: See also Group.Read.All.

Channel settings permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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.

Note: For messages in a channel, see ChannelMessage permissions.

Chat membership permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

ChatMember.Read Read the members Read the members of chats on Yes No


of chats. behalf of the signed-in user.

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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.

ChatMember.ReadWrite.All Add and remove Read names and members Yes No


members of all of all chat threads.
chats.

Chat resource-specific consent permissions

Application permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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.

Chat.Manage.Chat Manage this Allows the app to manage the chat, No No


chat. the chat's members, and grant access
to the chat's data, 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.

TeamsTab.Create.Chat Create tabs in Allows the app to create tabs in this No No


this chat. chat, without a signed-in user.

TeamsTab.Delete.Chat Delete this Allows the app to delete this chat's No No


chat's tabs. tabs, without a signed-in user.

TeamsTab.ReadWrite.Chat Manage this Allows the app to manage this chat's No No


chat's tabs. 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

OnlineMeeting.ReadBasic.Chat Read basic Allows the app to read basic No No


properties of a properties—such as name, schedule,
meeting organizer, and join link—of a meeting
associated with associated with this chat, without a
this chat. signed-in user.

Calls.AccessMedia.Chat Access media Allows the app to access media No No


streams in calls streams in calls associated with this
associated with chat or meeting, without a signed-in
this chat or user.
meeting.

Calls.JoinGroupCalls.Chat Join calls Allows the app to join calls associated No No


associated with with this chat or meeting, without a
this chat or signed-in user.
meeting.

TeamsActivity.Send.Chat Send activity Allows the app to create new No No


feed notifications in the teamwork activity
notifications to feeds of the users in this chat, without
users in this a signed-in user.
chat.

7 Note

Currently, these permissions are supported only in the beta version of Microsoft Graph.

ChatMessage permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported
Permission Display Description Admin Microsoft
String Consent Account
Required supported

CloudPC.Read.All Read Allows the app to read Cloud PC objects such as No No


Cloud provisioning policies, on behalf of the 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, on behalf of
Cloud the user.
PCs

Application permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

CloudPC.Read.All: View the properties of all Cloud PCs ( GET


/deviceManagement/virtualEndpoint/cloudPCs ).

CloudPC.ReadWrite.All: Edit the Cloud PC provisioning policy ( PATCH


/deviceManagement/virtualEndpoint/provisioningPolicies/{id} ).

Application

CloudPC.Read.All: View the properties of all Cloud PCs ( GET


/deviceManagement/virtualEndpoint/cloudPCs ).

CloudPC.ReadWrite.All: Edit the Cloud PC provisioning policy ( PATCH


/deviceManagement/virtualEndpoint/provisioningPolicies/{id} ).

Consent requests permissions


Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin


String Consent
Required

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.

Cross-tenant user profile sharing permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

CrossTenantUserProfileSharing.Read Read shared cross- Allows the Yes Yes


tenant user profile application to list
and export data and query user
profile information
associated with the
current tenant on
behalf of the signed-
in user. It also
permits the
application to export
external user data
(e.g. customer
content or system-
generated logs),
associated with the
current tenant on
behalf of the signed-
in user.
Permission Display String Description Admin Microsoft
Consent Account
Required supported

CrossTenantUserProfileSharing.Read.All Read all shared Allows the Yes Yes


cross-tenant user application to list
profiles and export and query any
their data shared user profile
information
associated with the
current tenant on
behalf of the signed-
in user. It also
permits the
application to export
external user data
(e.g. customer
content or system-
generated logs), for
any user associated
with the current
tenant on behalf of
the signed-in user.

CrossTenantUserProfileSharing.ReadWrite Read shared cross- Allows the Yes No


tenant user profile application to list
and export or delete and query user
data profile information
associated with the
current tenant on
behalf of the signed-
in user. It also
permits the
application to export
and remove external
user data (e.g.
customer content or
system-generated
logs), associated with
the current tenant on
behalf of the signed-
in user.
Permission Display String Description Admin Microsoft
Consent Account
Required supported

CrossTenantUserProfileSharing.ReadWrite.All Allows the Yes No


application to list and
query any shared
user profile
information
associated with the
current tenant on
behalf of the signed-
in user. It also
permits the
application to export
and remove external
user data (e.g.
customer content or
system-generated
logs), for any user
associated with the
current tenant on
behalf of the signed-
in user.

Application permissions

Permission Display String Description Admin


Consent
Required

CrossTenantUserProfileSharing.Read.All Allows the application to list and query any Yes


shared user profile information associated
with the current tenant without a signed-in
user. It also permits the application to
export external user data (e.g. customer
content or system-generated logs), for any
user associated with the current tenant
without a signed-in user.

CrossTenantUserProfileSharing.ReadWrite.All Allows the application to list and query any Yes


shared user profile information associated
with the current tenant without a signed-in
user. It also permits the application to
export and remove external user data (e.g.
customer content or system-generated
logs), for any user associated with the
current tenant without a signed-in user.

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

Permission Display String Description Admin


Consent
Required

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.

Custom authentication extensions permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

CustomAuthenticationExtension.Read.All Read your Allows the app to read Yes No


oganization's your organization's
custom custom authentication
authentication extensions on behalf of
extensions the signed-in user.

CustomAuthenticationExtension.ReadWrite.All Read and write Allows the app to read Yes No


your or write your
organization's organization's custom
custom authentication
authentication extensions on behalf of
extensions the signed-in user.

Application permissions

Permission Display String Description Admin


Consent
Required

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

Custom security attributes permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported
Permission Display Description Admin Microsoft
String Consent Account
Required supported

CustomSecAttributeAssignment.Read.All Read custom Allows the app to read Yes No


security custom security attribute
attribute assignments for all principals
assignments in the tenant on behalf of a
signed in user.

CustomSecAttributeAssignment.ReadWrite.All Read and Allows the app to read and Yes No


write custom write custom security
security attribute assignments for all
attribute principals in the tenant on
assignments behalf of a signed in user.

CustomSecAttributeDefinition.Read.All Read custom Allows the app to read Yes No


security custom security attribute
attribute definitions for the tenant on
definitions behalf of a signed in user.

CustomSecAttributeDefinition.ReadWrite.All Read and Allows the app to read and Yes No


write custom write custom security
security attribute definitions for the
attribute tenant on behalf of a signed
definitions in user.

Application permissions

Permission Display String Description Admin


Consent
Required

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

Device local credential permissions


Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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 ).

Granular delegated admin privileges (GDAP) permissions

Delegated permissions
Permission Display Description Admin Microsoft
String Consent Account
Required supported

DelegatedAdminRelationship.Read.All Read Allows the app to read details Yes No


Delegated of delegated admin
Admin relationships with customers
relationships like access details (that includes
with roles) and the duration as well
customers as specific role assignments to
security groups on behalf of
the signed-in user.

DelegatedAdminRelationship.ReadWrite.All Manage Allows the app to manage Yes No


Delegated (create-update-terminate)
Admin Delegated Admin relationships
relationships with customers and role
with assignments to security groups
customers for active Delegated Admin
relationships on your behalf.

Application permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

DelegatedAdminRelationship.Read.All Read Allows the app to read details Yes No


Delegated of delegated admin
Admin relationships with customers
relationships like access details (that includes
with roles) and the duration as well
customers as specific role assignments to
security groups without a
signed-in user.

DelegatedAdminRelationship.ReadWrite.All Manage Allows the app to manage Yes No


Delegated (create-update-terminate)
Admin Delegated Admin relationships
relationships with customers and role
with assignments to security groups
customers for active Delegated Admin
relationships without a signed-
in user.

Device permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported
Permission Display Description Admin Microsoft
String Consent Account
Required supported

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.

Device.Command Communicate Allows the app to launch another app or No Yes


with user communicate with another app on a user's device on
devices behalf of the signed-in user.

Application permissions

Permission Display Description Admin


String Consent
Required

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

Device.ReadWrite.All: Read all registered devices in the organization ( GET /devices ).

For more complex scenarios involving multiple permissions, see Permission scenarios.

Directory permissions
Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin


String Consent
Required

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.

The Directory.ReadWrite.All permission grants the following privileges:

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:

No rights to reset user passwords.


Updating another user's businessPhones, mobilePhone, or otherMails property 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. This is the case for apps granted either the
User.ReadWrite.All or Directory.ReadWrite.All delegated or application permissions.
No rights to delete resources (including users or groups).
Specifically excludes create or update for resources not listed above. This includes: application,
oAuth2PermissionGrant, appRoleAssignment, device, servicePrincipal, organization, domains,
and so on.

Example usage

Delegated

Directory.Read.All: List all administrative units in an organization ( GET /beta/administrativeUnits )


Directory.ReadWrite.All: Add members to a directory role ( POST /directoryRoles/{id}/members/$ref )

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.

Directory recommendations permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

DirectoryRecommendations.Read.All Read all Allows the app to read Yes No


recommendations recommendations on
behalf of the signed-in
user.

DirectoryRecommendations.ReadWrite.All Manage all Allows the app to read and Yes No


recommendations write recommendations on
behalf of the signed-in
user.

Application permissions

Permission Display String Description Admin


Consent
Required

DirectoryRecommendations.Read.All Read all Allows the app to read Yes


recommendations recommendations without a signed-in
user.

DirectoryRecommendations.ReadWrite.All Manage all Allows the app to read and write Yes
recommendations recommendations without a signed-in
user.

Domain permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display String Description Admin Consent


Required

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

EduAdministration.Read Read Allows the app to read education app Yes No


education settings on behalf of the user.
app settings

EduAdministration.ReadWrite Manage Allows the app to manage education app Yes No


education settings on behalf of the user.
app settings

EduAssignments.ReadBasic Read users' Allows the app to read assignments Yes No


class without grades on behalf of the user
assignments
without
grades

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.ReadBasic Read a Allows the app to read a limited subset of Yes No


limited the properties from the structure of
subset of schools and classes in an organization's
users' view roster and a limited subset of properties
of the roster about users to be read on behalf of the
user. Includes name, status, education role,
and email address.

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

Permission Display String Description Admin


Consent
Required

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} )

EduAssignments.ReadWriteBasic: Submit signed-in student assignment ( GET


/education/classes/{id}/assignments/{id}submit )

EduRoster.ReadBasic: Classes a signed-in user attends or teaches ( GET


/education/classes/{id}/members )

For more complex scenarios involving multiple permissions, see Permission scenarios.

Employee learning permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

LearningContent.Read.All Read Allows the app to read learning content in Yes No


learning the organization's directory, on behalf of
content the signed-in user.

LearningContent.ReadWrite.All Manage Allows the app to manage all learning Yes No


learning content in the organization's directory, on
content behalf of the signed-in user.

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported
Permission Display Description Admin Microsoft
String Consent Account
Required supported

LearningContent.Read.All Read all Allows the app to read all Yes No


learning learning content in the
content organization's directory, without a
signed-in user.

LearningContent.ReadWrite.All Manage all Allows the app to manage all Yes No


learning learning content in the
content organization's directory, without a
signed-in user.

LearningAssignedCourse.Read.All Read Allows the app to read data for Yes No


learning learning assignment record in
assignment organization's directory, without a
signed-in user.

LearningSelfInitiatedCourse.Read.All Read Allows the app to read data for Yes No


learning learning self-initiated course
self- record in organization's directory,
initiated without a signed-in user.
course

LearningAssignedCourse.ReadWrite.All Manage all Allows the app to Yes No


learning create/read/update/delete data
assignment for learning assignment record in
for learner organization's directory, without a
signed-in user.

LearningSelfInitiatedCourse.ReadWrite.All Manage all Allows the app to Yes No


self- create/read/update/delete data
initiated for self-initiated course record in
course for organization's directory, without a
learner signed-in user.

Entitlement management permissions

Delegated permissions

Permission Display String Description Admin


Consent
Required

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.Read.All Read Allows the app to request access to read Yes


entitlement access packages and related entitlement
management management resources on behalf of the
resources signed-in user.
Application permissions

Permission Display String Description Admin


Consent
Required

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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.Selected Read files that Limited support in Microsoft Graph; see No No


the user selects Remarks
(Preview) Allows the app to read files that
the user selects. The app has access for
several hours after the user selects a file.

Files.ReadWrite.Selected Read and write Limited support in Microsoft Graph; see No No


files that the Remarks
user selects (Preview) Allows the app to read and write
files that the user selects. The app has
access for several hours after the user
selects a file.
Application permissions

Permission Display String Description Admin


Consent
Required

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 )

Files.ReadWrite.AppFolder: Write files into the app's folder in OneDrive ( PUT


/me/drive/special/approot/children/file.txt/content )

For more complex scenarios involving multiple permissions, see Permission scenarios.

Financials permissions

Delegated permissions

Permission Display String Description Admin Consent


Required

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin


String Consent
Required
Permission Display Description Admin
String Consent
Required

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.

To set a Microsoft 365 group's preferredDataLocation attribute, an app needs Directory.ReadWrite.All


permission. When users in a multi-geo environment create a Microsoft 365 group, the
preferredDataLocation value for the group is automatically set to that of the user. For more information
about groups' preferred data location, see Create a Microsoft 365 group with a specific PDL.

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 ).

Group.ReadWrite.All: Update group properties, like photo ( PUT /groups/{id}/photo/$value ).


GroupMember.ReadWrite.All: Update group members ( POST /groups/{id}/members/$ref ).

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 ).

Group.Create: Creates a new group ( POST /groups ).

For more complex scenarios involving multiple permissions, see Permission scenarios.

Identity provider permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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:

IdentityProvider.Read.All: Read all identity providers configured in the tenant ( GET


/beta/identityProviders )
IdentityProvider.Read.All: Read an existing identity provider ( GET /beta/identityProviders/{id} )
IdentityProvider.ReadWrite.All Create an identity provider ( POST /beta/identityProviders )
IdentityProvider.ReadWrite.All Update an existing identity provider ( PATCH
/beta/identityProviders/{id} )
IdentityProvider.ReadWrite.All Delete an existing identity provider ( DELETE
/beta/identityProviders/{id} )

For more complex scenarios involving multiple permissions, see Permission scenarios.

Identity protection risk permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

IdentityRiskEvent.Read.All Read Allows the app to read identity Yes No


identity risk risk event information for all
event users in your organization on
information behalf of the signed-in user.

IdentityRiskyUser.Read.All Read Allows the app to read identity Yes No


identity user risk information for all users
user risk in your organization on behalf of
information the signed-in user.

IdentityRiskyUser.ReadWrite.All Read and Allows the app to read and Yes No


update update identity user risk
identity information for all users in your
user risk organization on behalf of the
information signed-in user.

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

IdentityRiskyServicePrincipal.ReadWrite.All Read and Allows the app to read and Yes No


write all update risky service principal
risky information for all service
service principals in your organization,
principal on behalf of the signed-in user.
information Update operations include
dismissing risky service
principals.

Application permissions

Permission Display String Description Admin


Consent
Required

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 risk events


Read all risk events generated for all users in the tenant ( GET /identityProtection/riskDetections )
Read most recent 50 risk events ( GET /identityProtection/riskDetections?
$orderBy=detectedDateTime desc&top=50 )
Read risky users
Read all risky users and properties in the tenant ( GET /identityProtection/riskyUsers )
Read all risky users whose aggregate risk level is Medium ( GET /identityProtection/riskyUsers?
$filter=riskLevel eq 'medium' )
Read the risk information for a specific user ( GET /identityProtection/riskyUsers?$filter=id eq
'userId' )

Read risky service principals

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.

Identity user flow permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Delegated and Application


The following usages are valid for both delegated and application permissions:

IdentityUserFlow.Read.All: Read all user flows in an Azure AD B2C tenant ( GET


beta/identity/b2cUserFlows )

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} )

IdentityUserFlow.ReadWrite.All: Create a user attribute assignment in an Azure AD B2C user flow


( POST beta/identity/b2cUserFlows/{id}/userAttributeAssignments )

For more complex scenarios involving multiple permissions, see Permission scenarios.

Incidents permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

SecurityIncident.Read.All Read Allows the app to read incidents, on Yes No


incidents behalf of the signed-in user.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

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

Permission Display String Description Admin


Consent
Required

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

SecurityIncident.Read.All: Read all incidents in an organization ( GET /security/incidents )


SecurityIncident.ReadWrite.All: Read and write to all incidents in an organization ( GET
/security/incidents )

Industry data permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported
Permission Display String Description Admin Microsoft
Consent Account
Required supported

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- View data Allows the app to read data Yes No


DataConnector.Read.All connector connectors on behalf of the signed-in
definitions user.

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- View reference Allows the app to read reference Yes No


ReferenceDefinition.Read.All definitions definitions 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

Permission Display String Description Admin


Consent
Required
Permission Display String Description Admin
Consent
Required

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.

Information protection policy permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

InformationProtectionPolicy.Read Read user Allows an app to read information Yes No


sensitivity protection sensitivity labels and label
labels and policy settings, on behalf of the signed-
label policies in user.

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.

Intune device management permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

DeviceManagementApps.Read.All Read Allows the Yes No


Microsoft app to read
Intune apps the
properties,
group
assignments
and status of
apps, app
configurations
and app
protection
policies
managed by
Microsoft
Intune.

DeviceManagementApps.ReadWrite.All Read and Allows the Yes No


write app to read
Microsoft and write the
Intune apps properties,
group
assignments
and status of
apps, app
configurations
and app
protection
policies
managed by
Microsoft
Intune.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

DeviceManagementConfiguration.Read.All Read Allows the Yes No


Microsoft app to read
Intune device properties of
configuration Microsoft
and policies Intune-
managed
device
configuration
and device
compliance
policies and
their
assignment to
groups.

DeviceManagementConfiguration.ReadWrite.All Read and Allows the Yes No


write app to read
Microsoft and write
Intune device properties of
configuration Microsoft
and policies Intune-
managed
device
configuration
and device
compliance
policies and
their
assignment to
groups.

DeviceManagementManagedDevices.PrivilegedOperations.All Perform Allows the Yes No


user- app to
impacting perform
remote remote high
actions on impact
Microsoft actions such
Intune as wiping the
devices device or
resetting the
passcode on
devices
managed by
Microsoft
Intune.

DeviceManagementManagedDevices.Read.All Read Allows the Yes No


Microsoft app to read
Intune the properties
devices of devices
managed by
Microsoft
Intune.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

DeviceManagementManagedDevices.ReadWrite.All Read and Allows the Yes No


write app to read
Microsoft and write the
Intune properties of
devices devices
managed by
Microsoft
Intune. Does
not allow high
impact
operations
such as
remote wipe
and password
reset on the
device's
owner.

DeviceManagementRBAC.Read.All Read Allows the Yes No


Microsoft app to read
Intune RBAC the properties
settings relating to the
Microsoft
Intune Role-
Based Access
Control
(RBAC)
settings.

DeviceManagementRBAC.ReadWrite.All Read and Allows the Yes No


write app to read
Microsoft and write the
Intune RBAC properties
settings relating to the
Microsoft
Intune Role-
Based Access
Control
(RBAC)
settings.

DeviceManagementServiceConfig.Read.All Read Allows the Yes No


Microsoft app to read
Intune Intune service
configuration properties
including
device
enrollment
and third
party service
connection
configuration.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

DeviceManagementServiceConfig.ReadWrite.All Read and Allows the Yes No


write app to read
Microsoft and write
Intune Microsoft
configuration Intune service
properties
including
device
enrollment
and third
party service
connection
configuration.

Application permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

DeviceManagementApps.Read.All Read Allows the Yes No


Microsoft app to read
Intune apps the
properties,
group
assignments
and status of
apps, app
configurations
and app
protection
policies
managed by
Microsoft
Intune.

DeviceManagementApps.ReadWrite.All Read and Allows the Yes No


write app to read
Microsoft and write the
Intune apps properties,
group
assignments
and status of
apps, app
configurations
and app
protection
policies
managed by
Microsoft
Intune.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

DeviceManagementConfiguration.Read.All Read Allows the Yes No


Microsoft app to read
Intune device properties of
configuration Microsoft
and policies Intune-
managed
device
configuration
and device
compliance
policies and
their
assignment to
groups.

DeviceManagementConfiguration.ReadWrite.All Read and Allows the Yes No


write app to read
Microsoft and write
Intune device properties of
configuration Microsoft
and policies Intune-
managed
device
configuration
and device
compliance
policies and
their
assignment to
groups.

DeviceManagementManagedDevices.PrivilegedOperations.All Perform Allows the Yes No


user- app to
impacting perform
remote remote high
actions on impact
Microsoft actions such
Intune as wiping the
devices device or
resetting the
passcode on
devices
managed by
Microsoft
Intune.

DeviceManagementManagedDevices.Read.All Read Allows the Yes No


Microsoft app to read
Intune the properties
devices of devices
managed by
Microsoft
Intune.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

DeviceManagementManagedDevices.ReadWrite.All Read and Allows the Yes No


write app to read
Microsoft and write the
Intune properties of
devices devices
managed by
Microsoft
Intune. Does
not allow high
impact
operations
such as
remote wipe
and password
reset on the
device's
owner.

DeviceManagementRBAC.Read.All Read Allows the Yes No


Microsoft app to read
Intune RBAC the properties
settings relating to the
Microsoft
Intune Role-
Based Access
Control
(RBAC)
settings.

DeviceManagementRBAC.ReadWrite.All Read and Allows the Yes No


write app to read
Microsoft and write the
Intune RBAC properties
settings relating to the
Microsoft
Intune Role-
Based Access
Control
(RBAC)
settings.

DeviceManagementServiceConfig.Read.All Read Allows the Yes No


Microsoft app to read
Intune Intune service
configuration properties
including
device
enrollment
and third
party service
connection
configuration.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

DeviceManagementServiceConfig.ReadWrite.All Read and Allows the Yes No


write app to read
Microsoft and write
Intune Microsoft
configuration Intune service
properties
including
device
enrollment
and third
party service
connection
configuration.

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.

These permissions are only valid for work or school accounts.

Example usage

Delegated

DeviceManagementServiceConfiguration.Read.All: Check the current state of the Intune subscription


( GET /deviceManagement/subscriptionState ).
DeviceManagementServiceConfiguration.ReadWrite.All: Create new Terms and Conditions ( POST
/deviceManagement/termsAndConditions ).
DeviceManagementConfiguration.Read.All: Find the status of a device configuration ( GET
/deviceManagement/deviceConfigurations/{id}/deviceStatuses ).
DeviceManagementConfiguration.ReadWrite.All: Assign a device compliance policy to a group ( POST
deviceCompliancePolicies/{id}/assign ).

DeviceManagementApps.Read.All: Find all the Windows Store apps published to Intune ( GET
/deviceAppManagement/mobileApps?$filter=isOf('microsoft.graph.windowsStoreApp') ).

DeviceManagementApps.ReadWrite.All: Publish a new application ( POST


/deviceAppManagement/mobileApps ).

DeviceManagementRBAC.Read.All: Find a role assignment by name ( GET


/deviceManagement/roleAssignments?$filter=displayName eq 'My Role Assignment' ).
DeviceManagementRBAC.ReadWrite.All: Create a new custom role ( POST
/deviceManagement/roleDefinitions ).
DeviceManagementManagedDevices.Read.All: Find a managed device by name ( GET
/managedDevices/?$filter=deviceName eq 'My Device' ).
DeviceManagementManagedDevices.ReadWrite.All: Remove a managed device ( DELETE
/managedDevices/{id} ).
DeviceManagementManagedDevices.PrivilegedOperations.All: Reset the passcode on a user's
managed device ( POST /managedDevices/{id}/resetPasscode ).

Application

DeviceManagementServiceConfiguration.Read.All: Check the current state of the Intune subscription


( GET /deviceManagement/subscriptionState ).
DeviceManagementServiceConfiguration.ReadWrite.All: Create new Terms and Conditions ( POST
/deviceManagement/termsAndConditions ).
DeviceManagementConfiguration.Read.All: Find the status of a device configuration ( GET
/deviceManagement/deviceConfigurations/{id}/deviceStatuses ).
DeviceManagementConfiguration.ReadWrite.All: Assign a device compliance policy to a group ( POST
deviceCompliancePolicies/{id}/assign ).

DeviceManagementApps.Read.All: Find all the Windows Store apps published to Intune ( GET
/deviceAppManagement/mobileApps?$filter=isOf('microsoft.graph.windowsStoreApp') ).

DeviceManagementApps.ReadWrite.All: Publish a new application ( POST


/deviceAppManagement/mobileApps ).

DeviceManagementRBAC.Read.All: Find a role assignment by name ( GET


/deviceManagement/roleAssignments?$filter=displayName eq 'My Role Assignment' ).
DeviceManagementRBAC.ReadWrite.All: Create a new custom role ( POST
/deviceManagement/roleDefinitions ).
DeviceManagementManagedDevices.Read.All: Find a managed device by name ( GET
/managedDevices/?$filter=deviceName eq 'My Device' ).

DeviceManagementManagedDevices.ReadWrite.All: Remove a managed device ( DELETE


/managedDevices/{id} ).

DeviceManagementManagedDevices.PrivilegedOperations.All: Reset the passcode on a user's


managed device ( POST /managedDevices/{id}/resetPasscode ).

For more complex scenarios involving multiple permissions, see Permission scenarios.

Lifecycle workflows permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display String Description Admin


Consent
Required

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin


String Consent
Required

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 ).

Mail.ReadWrite: Mark a message read ( PATCH /me/messages/{id} ).


Mail.Send: Send a message ( POST /me/sendmail ).
MailboxSettings.ReadWrite: Update the user's automatic reply ( PATCH /me/mailboxSettings ).

Application

Mail.Read: Find messages from [email protected] ( GET /users/{id | userPrincipalName}/messages?


$filter=from/emailAddress/address eq '[email protected]' ).

Mail.ReadWrite: Create a new folder in the Inbox named Expense Reports ( POST /users/{id |
userPrincipalName}/mailfolders ).

Mail.Send: Send a message ( POST /users/{id | userPrincipalName}/sendmail ).


MailboxSettings.Read: Get the default timezone for the user's mailbox ( GET /users/{id |
userPrincipalName}/mailboxSettings/timeZone )

For more complex scenarios involving multiple permissions, see Permission scenarios.

Managed tenant permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display String Description Admin


Consent
Required

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

Member.Read.Hidden: Read the members of an administrative unit with hidden membership on


behalf of the signed-in user ( GET /administrativeUnits/{id}/members ).
Member.Read.Hidden: Read the members of a group with hidden membership on behalf of the
signed-in user ( GET /groups/{id}/members ).

Application
Member.Read.Hidden: Read the members of an administrative unit with hidden membership ( GET
/administrativeUnits/{id}/members ).

Member.Read.Hidden: Read the members of a group with hidden membership ( GET


/groups/{id}/members ).

For more complex scenarios involving multiple permissions, see Permission scenarios.

Notes permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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.Read.All Read all Allows the app to read OneNote No No


OneNote notebooks that the signed-in user has
notebooks that access to in the organization.
user can access

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.

Notes.ReadWrite.CreatedByApp Limited Deprecated No No


notebook Do not use. No privileges are granted
access by this permission.
(deprecated)

Application permissions

Permission Display String Description Admin


Consent
Required

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 ).

Notes.ReadWrite: Update the page of the signed-in user ( PATCH /me/onenote/pages/{id}/$value ).


Notes.ReadWrite.All: Create a page in another user's notebook that the signed-in user has access to
within the organization ( POST /users/{id}/onenote/pages ).

Application

Notes.Read.All: Read all users notebooks in a group ( GET /groups/{id}/onenote/notebooks ).


Notes.ReadWrite.All: Update the page in a notebook for any user in the organization ( PATCH
/users/{id}/onenote/pages/{id}/$value ).

For more complex scenarios involving multiple permissions, see Permission scenarios.

Notifications permissions

Delegated permissions

Permission Display Description Admin


String Consent
Required

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

Notifications.ReadWrite.CreatedByApp: Publish a user-centric notification, which might then be


delivered to the user's multiple application clients running on different endpoints. (POST
/me/notifications/).

Online meetings permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

OnlineMeetings.Read Read Online Allows an app to read online No No


Meeting. meeting details on behalf of the
signed-in user.

OnlineMeetings.ReadWrite Read and Allows an app to create, read online No No


Create Online meetings on behalf of the signed-in
Meetings. user.

OnlineMeetingArtifact.Read.All Read Online Allows the app to read online No No


Meeting meeting artifacts on behalf of the
artifacts. signed-in user.

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

Permission Display String Description Admin


Consent
Required

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.

OnlineMeetings.ReadWrite.All Read Online Allows an app to create, read Online Yes


Meeting details Meetings without a signed-in user.
from the app

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} ).

OnlineMeetings.ReadWrite: Create an online meeting ( POST /beta/communications/onlinemeetings ).

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.

On-premises directory synchronization permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

OnPremDirectorySynchronization.Read.All Read all on- Allows the app to read Yes No


premises all on-premises
directory directory
synchronization synchronization
information information for the
organization, on behalf
of the signed-in user

OnPremDirectorySynchronization.ReadWrite.All Read and write Allows the app to read Yes No


all on-premises and write all on-
directory premises directory
synchronization synchronization
information information for the
organization, on behalf
of the signed-in user

Application permissions

None.
On-premises publishing profiles permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

OnPremisesPublishingProfiles.ReadWrite.All Access Allows the app to manage No No


On- hybrid identity service
Premises configuration by creating,
Publishing viewing, updating and deleting
Profiles on-premises published
resources, on-premises agents
and agent groups, on behalf of
the signed-in user.

Application permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

OnPremisesPublishingProfiles.ReadWrite.All Access Allows the app to create, view, Yes No


On- update and delete on-premises
Premises published resources, on-
Publishing premises agents and agent
Profiles groups, as part of a hybrid
identity configuration, without a
signed in user.

OpenID Connect (OIDC) scopes


Permission Display Description Admin Microsoft
String Consent Account
Required supported

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin


String Consent
Required

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

Organization.Read.All: Get organization information ( GET /organization ).


Organization.Read.All: Get the SKUs that the organization has subscribed to ( GET /subscribedSkus ).

Application
Organization.ReadWrite.All: Update organization information (such as technicalNotificationMails)
( PATCH /organization/{id} ).

Organizational contact permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported
Permission Display Description Admin Microsoft
String Consent Account
Required supported

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

Permission Display Description Admin


String Consent
Required

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

OrgContact.Read.All: Get all organizational contacts ( GET /contacts ).

People permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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.

Privileged access permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

PrivilegedAccess.ReadWrite.AzureAD Read and Allows the app Yes No


write to have read and
Privileged write access to
Identity Privileged
Management Identity
data for Management
Directory APIs for Azure
AD.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

PrivilegedAccess.ReadWrite.AzureADGroup Read and Allows the app Yes No


write to have read and
Privileged write access to
Identity Privileged
Management Identity
data for Management
privileged APIs for groups.
access
groups

PrivilegedAccess.ReadWrite.AzureResources Read and Allows the app Yes No


write to have read and
Privileged write access to
Identity Privileged
Management Identity
data for Management
Azure APIs for Azure
Resources resources.

PrivilegedAssignmentSchedule.Read.AzureADGroup Read Allows the app Yes No


assignment to read time-
schedules for based
access to assignment
Azure AD schedules for
groups access to Azure
AD groups, on
behalf of the
signed-in user.

PrivilegedEligibilitySchedule.Read.AzureADGroup Read Allows the app Yes No


eligibility to read time-
schedules for based eligibility
access to schedules for
Azure AD access to Azure
groups AD groups, on
behalf of the
signed-in user.

PrivilegedAssignmentSchedule.ReadWrite.AzureADGroup Read, create, Allows the app Yes No


and delete to read, create,
assignment and delete time-
schedules for based
access to assignment
Azure AD schedules for
groups access to Azure
AD groups, on
behalf of the
signed-in user.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

PrivilegedEligibilitySchedule.ReadWrite.AzureADGroup Read, create, Allows the app Yes No


and delete to read, create,
eligibility and delete time-
schedules for based eligibility
access to schedules for
Azure AD access to Azure
groups AD groups, on
behalf of the
signed-in user.

Application permissions

Permission Display String Description Admin


Consent
Required

PrivilegedAccess.Read.AzureAD Read Privileged Allows the app to have read Yes


Identity access to Privileged Identity
Management Management APIs for Azure
data for AD.
Directory

PrivilegedAccess.Read.AzureADGroup Read Privileged Allows the app to have read Yes


Identity access to Privileged Identity
Management Management APIs for
data for groups.
privileged
access groups

PrivilegedAccess.Read.AzureResources Read Privileged Allows the app to have read Yes


Identity access to Privileged Identity
Management Management APIs for Azure
data for Azure AD resources.
resources

PrivilegedAssignmentSchedule.Read.AzureADGroup Read Allows the app to read Yes


assignment time-based assignment
schedules for schedules for access to
access to Azure Azure AD groups, without a
AD groups signed-in user.

PrivilegedEligibilitySchedule.Read.AzureADGroup Read eligibility Allows the app to read Yes


schedules for time-based eligibility
access to Azure schedules for access to
AD groups Azure AD groups, without a
signed-in user.

PrivilegedAssignmentSchedule.ReadWrite.AzureADGroup Read, create, Allows the app to read, Yes


and delete create, and delete time-
assignment based assignment
schedules for schedules for access to
access to Azure Azure AD groups, without a
AD groups signed-in user.
Permission Display String Description Admin
Consent
Required

PrivilegedEligibilitySchedule.ReadWrite.AzureADGroup Read, create, Allows the app to read, Yes


and delete create, and delete time-
eligibility based eligibility schedules
schedules for for access to Azure AD
access to Azure groups, without a signed-in
AD groups user.

Places permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin


String Consent
Required

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

Policy.Read.All Read your Allows the app to read your Yes No


organization's organization's policies on
policies behalf of the signed-in user.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

Policy.Read.PermissionGrant Read consent Allows the app to read policies Yes No


and related to consent and
permission permission grants for
grant policies applications, on behalf of the
signed-in user.

Policy.ReadWrite.AccessReview Read and Allows the app to read and Yes No


write your write your organization's
organization's access review policy on behalf
access review of the signed-in user.
policy

Policy.ReadWrite.ApplicationConfiguration Read and Allows the app to read and Yes No


write your write your organization's
organization's application configuration
application policies on behalf of the
configuration signed-in user.
policies

Policy.ReadWrite.AuthenticationFlows Read and Allows the app to read and Yes No


write your write the authentication flow
organization's policies, on behalf of the
authentication signed-in user.
flow policies

Policy.ReadWrite.AuthenticationMethod Read and Allows the app to read and Yes No


write write the authentication
authentication method policies, on behalf of
method the signed-in user. The signed-
policies in user must also be assigned
the Global Administrator role.

Policy.ReadWrite.Authorization Read and Allows the app to read and Yes No


write your write your organization's
organization's authorization policy on behalf
authorization of the signed-in user. For
policy example, authorization policies
can control some of the
permissions that the out-of-
the-box user role has by
default.

Policy.ReadWrite.ConditionalAccess Read and Allows the app to read and Yes No


write your write your organization's
organization's conditional access policies on
conditional behalf of the signed-in user.
access
policies

Policy.ReadWrite.ConsentRequest Read and Allows the app to read and Yes No


write your write your organization's
organization's consent requests policy on
consent behalf of the signed-in user.
requests
policy
Permission Display Description Admin Microsoft
String Consent Account
Required supported

Policy.ReadWrite.CrossTenantAccess Read and Allows the app to read and Yes No


write your write your organization's
organization's cross-tenant access policy on
cross-tenant behalf of the signed-in user.
access policy

Policy.ReadWrite.FeatureRollout Read and Allows the app to read and Yes No


write your write your organization's
organization's feature rollout policies on
feature rollout behalf of the signed-in user.
policies Includes abilities to assign and
remove users and groups to
rollout of a specific feature.

Policy.ReadWrite.PermissionGrant Manage Allows the app to manage Yes No


consent and policies related to consent and
permission permission grants for
grant policies applications, on behalf of the
signed-in user.

Policy.ReadWrite.TrustFramework Read and Allows the app to read and Yes No


write your write your organization's trust
organization's framework policies on behalf
trust of the signed-in user.
framework
policies

Policy.ReadWrite.AuthenticationMethod Read and Allows the app to read and Yes No


write your write the authentication
organization's method policies, on behalf of
authentication the signed-in user.
method
policies

Policy.ReadWrite.MobilityManagement Read and Allows the app to read and Yes No


write your write the mobility
organization's management policies on
mobility behalf of the signed-in user.
management These control the settings for
policies. mobile device management
(MDM) and mobile application
management (MAM)
applications.

Application permissions

Permission Display Description Admin


String Consent
Required

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.PermissionGrant Manage Allows the app to manage policies related to Yes


consent and consent and permission grants for
permission applications, without a signed-in user.
grant policies

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.Read.All: Read your organization's policies ( GET /policies )


Policy.Read.All: Read your organization's trust framework policies ( GET
/beta/trustFramework/policies )
Policy.Read.All: Read your organization's feature rollout policies ( GET
/beta/directory/featureRolloutPolicies )
Policy.ReadWrite.AccessReview: Read and write your organization's access review policies ( PATCH
/beta/policies/accessReviewPolicy )

Policy.ReadWrite.ApplicationConfiguration: Read and write your organization's application


configuration policies ( POST /beta/policies/tokenLifetimePolicies )
Policy.ReadWrite.AuthenticationFlows: Read and write your organization's authentication flows policy
( PATCH /beta/policies/authenticationFlowsPolicy )
Policy.ReadWrite.AuthenticationMethod: Use this permission to manage the settings of the
authentication methods policy, including enabling and disabling authentication methods, allowing
users and groups to use those methods, and configuring other settings related to the authentication
methods that users may register and use in a tenant.
Policy.ReadWrite.ConditionalAccess: Read and write your organization's conditional access policies
( POST /beta/identity/conditionalAccess/policies )
Policy.ReadWrite.CrossTenantAccess: Read and write your organization's cross tenant access policy
( PATCH /beta/policies/crossTenantAccessPolicy )
Policy.ReadWrite.FeatureRollout: Read and write your organization's feature rollout policies ( POST
/beta/directory/featureRolloutPolicies )

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

Permission Display String Description Admin


Consent
Required

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

Permission Display Description Admin


String Consent
Required

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 )

Set the preferred presence of a user as an application ( POST


/users/{id}/presence/setUserPreferredPresence )
Programs and program controls permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

ProgramControl.Read.All Read all Allows the app to read programs on Yes No


programs behalf of the signed-in user.

ProgramControl.ReadWrite.All Manage Allows the app to read and write Yes No


all programs on behalf of the signed-in
programs user.

Application permissions

Permission Display Description Admin Consent


String Required

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.

Records management permissions

Delegated permissions

Permission Display String Description Admin


Consent
Required

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

Permission Display String Description Admin


Consent
Required

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin


String Consent
Required

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.

Role management permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

RoleAssignmentSchedule.Read.Directory Read all Allows the app to read the Yes No


active role active role-based access
assignments control (RBAC) assignments
for your for your company's
company's directory, on behalf of the
directory. signed-in user. This includes
reading directory role
templates, and directory
roles.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

RoleEligibilitySchedule.Read.Directory Read all Allows the app to read the Yes No


eligible role eligible role-based access
assignments control (RBAC) assignments
for your for your company's
company's directory, on behalf of the
directory. signed-in user. This includes
reading directory role
templates, and directory
roles.

RoleManagement.Read.All Read role Allows the app to read the Yes No


management role-based access control
data for all (RBAC) settings for all
RBAC supported RBAC providers,
providers. on behalf of the signed-in
user. This includes reading
role definitions and role
assignments.

RoleManagement.Read.Directory Read role Allows the app to read the Yes No


management role-based access control
data for (RBAC) settings for your
Azure AD. company's directory, on
behalf of the signed-in user.
This includes reading
directory role templates,
directory roles and
memberships.

RoleManagementPolicy.Read.Directory Read all Allows the app to read Yes No


policies for policies for privileged role-
privileged based access control (RBAC)
role assignments for your
assignments company's directory, on
for your behalf of the signed-in user.
company's
directory.

RoleManagement.Read.Exchange Read Allows the app to read the Yes No


Exchange role-based access control
Online RBAC (RBAC) settings for your
configuration organization's Exchange
Online service, on behalf of
the signed-in user. This
includes reading Exchange
management role
definitions, role groups, role
group membership, role
assignments, management
scopes, and role assignment
policies.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

RoleAssignmentSchedule.ReadWrite.Directory Read, Allows the app to read and Yes No


update, and manage the active role-
delete all based access control (RBAC)
active role assignments for your
assignments company's directory, on
for your behalf of the signed-in user.
company's This includes managing
directory. active directory role
membership, and reading
directory role templates,
directory roles and active
memberships.

RoleEligibilitySchedule.ReadWrite.Directory Read, Allows the app to read and Yes No


update, and manage the eligible role-
delete all based access control (RBAC)
eligible role assignments for your
assignments company's directory, on
for your behalf of the signed-in user.
company's This includes managing
directory. eligible directory role
membership, and reading
directory role templates,
directory roles and eligible
memberships.

RoleManagement.ReadWrite.Directory Read and Allows the app to read and Yes No


write role manage the role-based
management access control (RBAC)
data for settings for your company's
Azure AD. directory, on behalf of the
signed-in user. This includes
instantiating directory roles
and managing directory role
membership, and reading
directory role templates,
directory roles and
memberships.

RoleManagementPolicy.ReadWrite.Directory Read, Allows the app to read, Yes No


update, and update, and delete policies
delete all for privileged role-based
policies for access control (RBAC)
privileged assignments for your
role company's directory, on
assignments behalf of the signed-in user.
for your
company's
directory.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

RoleManagement.ReadWrite.Exchange Read and Allows the app to read and Yes No


write manage the role-based
Exchange access control (RBAC)
Online RBAC settings for your
configuration organization's Exchange
Online service, on behalf of
the signed-in user. This
includes reading, creating,
updating, and deleting
Exchange management role
definitions, role groups, role
group membership, role
assignments, management
scopes, and role assignment
policies.

Application permissions

Permission Display Description Admin


String Consent
Required

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

Permissions that allow granting authorization, such as RoleManagement.ReadWrite.Directory, allow an


application to grant itself, other applications, or any user, additional privileges. Use caution when
granting any of these permissions.
With the RoleManagement.Read.Directory permission an application can read directoryRoles and
directoryRoleTemplates. This includes reading membership information for directory roles.

With the RoleManagement.ReadWrite.Directory permission an application can read and write


directoryRoles (directoryRoleTemplates are readonly resources). This includes adding and removing
members to and from directory roles.

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 activated roles in your directory ( GET


/directoryRoles )

RoleManagement.Read.Directory: Read the list of members for a role ( GET


/directoryRoles/<id>/members )

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 )

RoleManagement.ReadWrite.Directory: Add an administrative unit-scoped member to a directory role


( POST /directoryRoles/<id>/scopedMembers )

For more complex scenarios involving multiple permissions, see Permission scenarios.

Schedule management permissions

Application permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Schedule.ReadWrite.All Read and Allows an app to read and write No No


Write Shifts schedule, schedule groups, shifts, and
service associated entities in shifts applications
(Teams) on behalf of the signed-in user.
data

Schedule.Read.All Read Shifts Allows the app to read schedule, No No


service schedule groups, shifts, and associated
(Teams) entities in shifts applications on behalf
data of the signed-in user.

WorkforceIntegration.ReadWrite.All Read and Allows the app to manage workforce Yes No


(private preview) write integrations, to synchronize data from
workforce Microsoft Teams Shifts with an
integrations integrated system, on behalf of the
signed-in user.

WorkforceIntegration.Read.All Read and Allows the app to manage workforce Yes No


(private preview) write integrations, to synchronize data from
workforce Microsoft Teams Shifts with an
integrations integrated system, on behalf of the
signed-in user.

Search permissions

Application permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

Acronym.Read.All Read all Allows the app to read all No No


acronyms acronyms on behalf of a signed-in
user.

Bookmark.Read.All Read all Allows the app to read all No No


bookmarks bookmarks on behalf of a signed-
in user.

QnA.Read.All Read all Allows the app to read all question No No


qnas and answer sets on behalf of a
signed-in user.

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.Read.All Read Allow the app to read external Yes No


external datasets and content on behalf of
data the signed-in user.

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 ).

Search configuration permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

SearchConfiguration.Read.All Read your Allows the app to read search Yes No


organization's configuration, on behalf of the
search signed-in user.
configuration.

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

Permission Display String Description Admin


Consent
Required
Permission Display String Description Admin
Consent
Required

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

Delegated and Application


SearchConfiguration.Read.All: Read the list of all bookmarks created for your tenant ( GET
/beta/search/bookmarks )

SearchConfiguration.ReadWrite.All: Update or read all bookmarks created for your tenant ( PATCH
/beta/search/bookmarks/{id} )

Security permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

AttackSimulation.Read.All Read attack Allows the app to read attack Yes No


simulation simulation and training data for an
data of an organization for the signed-in user.
organization

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

SecurityActions.Read.All Read your Allows the app to read your Yes No


organization's organization's security actions on
security behalf of the signed-in user.
actions
Permission Display Description Admin Microsoft
String Consent Account
Required supported

SecurityActions.ReadWrite.All Read and Allows the app to read or update Yes No


update your your organization's security actions
organization's on behalf of the signed-in user.
security
actions

SecurityAlert.Read.All Read alerts Allows the app to read alerts, on Yes No


behalf of the signed-in user.

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.

SecurityEvents.Read.All Read your Allows the app to read your Yes No


organization's organization's security events on
security behalf of the signed-in user.
events

SecurityEvents.ReadWrite.All Read and Allows the app to read your Yes No


update your organization's security events on
organization's behalf of the signed-in user. Also
security allows the app to update editable
events properties in security events on
behalf of the signed-in user.

SecurityIncident.Read.All Read Allows the app to read incidents, on Yes No


incidents 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.ReadWrite.OwnedBy Manage Allows the app to create threat Yes No


threat indicators, and fully manage those
indicators this threat indicators (read, update and
app creates or delete) on behalf of the signed-in
owns 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

ThreatIndicators.ReadWrite.OwnedBy Manage Allows the app to create threat Yes No


threat indicators, and fully manage those
indicators this threat indicators (read, update and
app creates or delete) on behalf of the signed-in
owns user.

Application permissions

Permission Display String Description Admin


Consent
Required
Permission Display String Description Admin
Consent
Required

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} ).

Service communications permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported
Permission Display String Description Admin Microsoft
Consent Account
Required supported

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

Permission Display Description Admin


String Consent
Required

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.

Short Notes permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin


Consent
Required

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 )

Sites.Manage.All: Add a new list to a SharePoint site ( POST /v1.0/sites/root/lists )


Sites.FullControl.All: Complete access to SharePoint sites and lists.

Synchronization permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin


Consent
Required
Permission Display String Description Admin
Consent
Required

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 ).

Synchronization.ReadWrite.All: Create a subject rights request ( PUT


/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 ).

Subject rights request permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

SubjectRightsRequest.Read.All Read Allows the app to read subject rights Yes No


subject requests on behalf of the signed-in user.
rights
requests

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin


Consent
Required

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 ).

Tasks.ReadWrite: Create a Planner task ( POST /planner/tasks ).


Tasks.ReadWrite.Shared: Complete a task on behalf of another user ( POST /users/{id |
userPrincipalName}/outlook/tasks/id/complete ).

For more complex scenarios involving multiple permissions, see Permission scenarios.

Application

Tasks.Read.All: Get all Planner plans in a group ( GET /groups/{id}/planner/plans )


Tasks.ReadWrite.All: Delete a Planner task ( Delete /planner/tasks/{id} )

Taxonomy permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Team.Create Create teams Create teams, on behalf of the signed- Yes No


in user.

Application permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

Team.ReadBasic.All Get a list of all Get a list of all teams, without a Yes No
teams signed-in user.

Team.Create Create teams Create teams, without a signed-in Yes No


user.

Teamwork.Migrate.All Manage migration Creating and managing resources Yes Yes


to Microsoft Teams for migration to Microsoft Teams

Team templates permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

TeamTemplates.Read TeamTemplates.Read is "Sign-in and Allows read of the No No


read Teams templates available for available Teams
this user" Templates for the user

Application permissions
Permission Display String Description Admin Microsoft
Consent Account
Required supported

TeamTemplates.Read.All Read all available Allows read of the available Teams No No


Teams Templates Templates, without signed user

Team settings permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

TeamSettings.Read.All Read teams' Read this team's settings, on behalf Yes No


settings of the signed-in user.

TeamSettings.ReadWrite.All Read and Read and change all teams' Yes No


change teams' settings, on behalf of the signed-in
settings user.

Application permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

TeamSettings.Read.All Read all teams' Read this team's settings, Yes No


settings without a 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.

Teams activity permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

TeamsActivity.Send Send a Allows the app to create new notifications in users' No No


teamwork teamwork activity feeds on behalf of the signed in user.
activity as These notifications may not be discoverable or be held or
the user governed by compliance policies.

Application permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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.

Teams app permissions (deprecated)

7 Note

These permissions are deprecated. Use the equivalent TeamsAppInstallation.*.All permissions instead.

Delegated 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) 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.

Teams app installation permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

TeamsAppInstallation.ReadForUser Read user's Allows the app to No No


installed read the Teams
Teams apps that are
apps installed for the
signed-in user.
Does not give the
ability to read
application-specific
settings.

TeamsAppInstallation.ReadWriteForUser Manage Allows the app to Yes No


user's read, install,
installed upgrade, and
Teams uninstall Teams
apps apps installed for
the signed in user.
Does not give the
ability to read
application-specific
settings.

TeamsAppInstallation.ReadWriteSelfForUser Allow the Allows a Teams app No No


app to to read, install,
manage upgrade, and
itself in uninstall itself to
teams teams the signed-in
user can access.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

TeamsAppInstallation.ReadForTeam Read Allows the app to Yes No


installed read the Teams
Teams apps that are
apps in installed in teams
teams the signed-in user
can access. Does
not give the ability
to read application-
specific settings.

TeamsAppInstallation.ReadWriteForTeam Manage Allows the app to Yes No


installed read, install,
Teams upgrade, and
apps in uninstall Teams
teams apps in teams the
signed-in user can
access. Does not
give the ability to
read application-
specific settings.

TeamsAppInstallation.ReadWriteSelfForTeam Allow the Allows a Teams app Yes No


app to to read, install,
manage upgrade, and
itself in uninstall itself to
teams teams the signed-in
user can access.

TeamsAppInstallation.ReadWriteAndConsentForChat Manage Allows a Teams app Yes No


installed to read, install,
Teams upgrade, and
apps in uninstall itself to
chats teams the signed-in
user can access.

TeamsAppInstallation.ReadWriteAndConsentForTeam Manage Allows a Teams app Yes No


installed to read, install,
Teams upgrade, and
apps in uninstall itself to
teams teams the signed-in
user can access.

TeamsAppInstallation.ReadWriteAndConsentSelfForChat Allow the Allows a Teams app Yes No


Teams app to read, install,
to manage upgrade, and
itself and uninstall itself to
its teams the signed-in
permission user can access.
grants in
chats
Permission Display Description Admin Microsoft
String Consent Account
Required supported

TeamsAppInstallation.ReadWriteAndConsentSelfForTeam Allow the Allows a Teams app Yes No


Teams app to read, install,
to manage upgrade, and
itself and uninstall itself to
its teams the signed-in
permission user can access.
grants in
teams

Application permissions

Permission Display Description Admin


String Consent
Required

TeamsAppInstallation.ReadForUser.All Read Allows the app to read the Yes


installed Teams apps that are installed
Teams apps for any user, without a
for all users signed-in user. Does not give
the ability to read
application-specific settings.

TeamsAppInstallation.ReadWriteForUser.All Manage Allows the app to read, Yes


Teams apps install, upgrade, and uninstall
for all users Teams apps for any user,
without a signed-in user.
Does not give the ability to
read application-specific
settings.

TeamsAppInstallation.ReadWriteSelfForUser.All Allow the Allows a Teams app to read, Yes


app to install, upgrade, and uninstall
manage itself to any user, without a
itself for all signed-in user.
users

TeamsAppInstallation.ReadForTeam.All Read Allows the app to read the Yes


installed Teams apps that are installed
Teams apps in any team, without a
for all teams signed-in user. Does not give
the ability to read
application-specific settings.

TeamsAppInstallation.ReadWriteForTeam.All Manage Allows the app to read, Yes


Teams apps install, upgrade, and uninstall
for all teams Teams apps in any team,
without a signed-in user.
Does not give the ability to
read application-specific
settings.
Permission Display Description Admin
String Consent
Required

TeamsAppInstallation.ReadWriteSelfForTeam.All Allow the Allows a Teams app to read, Yes


Teams app install, upgrade, and uninstall
to manage itself in any team, without a
itself for all signed-in user.
teams

TeamsAppInstallation.ReadWriteAndConsentForChat.All Manage Allows the app to read, Yes


installation install, upgrade, and uninstall
and Teams apps in any chat,
permission without a signed-in user.
grants of Gives the ability to manage
Teams apps permission grants for
for all chats accessing those specific
chats' data.

TeamsAppInstallation.ReadWriteAndConsentForTeam.All Manage Allows the app to read, Yes


installation install, upgrade, and uninstall
and Teams apps in any team,
permission without a signed-in user.
grants of Gives the ability to manage
Teams apps permission grants for
for all teams accessing those specific
teams' data.

TeamsAppInstallation.ReadWriteAndConsentSelfForChat.All Allow the Allows a Teams app to read, Yes


Teams app install, upgrade, and uninstall
to manage itself for any chat, without a
itself and its signed-in user, and manage
permission its permission grants for
grants for accessing those specific
all chats chats' data.

TeamsAppInstallation.ReadWriteAndConsentSelfForTeam.All Allow the Allows a Teams app to read, Yes


Teams app install, upgrade, and uninstall
to manage itself for any team, without a
itself and its signed-in user, and manage
permission its permission grants for
grants for accessing those specific
all teams teams' data.

Teams app settings permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

TeamworkAppSettings.Read.All Read Teams Allows the app to read the Teams No No


app settings app settings on behalf of the
signed-in user.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

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

Permission Display String Description Admin


Consent
Required

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

Teams device management permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

TeamworkDevice.Read.All Read Allows the app to read the management Yes No


Teams data for Teams devices on behalf of the
devices. signed-in user.

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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.

Team resource-specific consent permissions

Application permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

TeamSettings.Read.Group Read this team's Read this team's settings, without No No


settings. a signed-in user.

TeamSettings.ReadWrite.Group Update the Read and write this team's No No


settings for this settings, without a signed-in user.
team.

ChannelSettings.Read.Group Read the names, Read this team's channel names, No No


descriptions, and channel descriptions, and channel
settings of this settings, without a signed-in user.
team's channels.
Permission Display String Description Admin Microsoft
Consent Account
Required supported

ChannelSettings.ReadWrite.Group Update the names, Update this team's channel No No


descriptions, and names, channel descriptions, and
settings of this channel settings, without a
team's channels. signed-in user.

Channel.Create.Group Create channels in Create channels in this team, No No


this team. without a signed-in user.

Channel.Delete.Group Delete this team's Delete this team's channels, No No


channels. without a signed-in user.

ChannelMessage.Read.Group Read the team's Allows an app to read this team's No No


channel messages. channel's messages, without a
signed-in user.

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.

TeamsTab.Read.Group Read this team's Read this team's tabs, without a No No


tabs. signed-in user.

TeamsTab.Create.Group Create tabs in this Create tabs in this team, without a No No


team. signed-in user.

TeamsTab.ReadWrite.Group Update this team's Update this team's tabs, without a No No


tabs. signed-in user.

TeamsTab.Delete.Group Delete this team's Delete this team's tabs, without a No No


tabs. signed-in user.

TeamMember.Read.Group Read this team's Read this team's members, No No


members. without a signed-in user.

Member.Read.Group Read this group's Read this group's members, No No


members. without a signed-in user.

Owner.Read.Group Read this group's Read this group's owners, without No No


owners. a signed-in user.

File.Read.Group Read this team's Limited support No No


files and folders. (Preview) Read this team's files
and folders, without a signed-in
users.

TeamsActivity.Send.Group Send activity feed Allows the app to create new No No


notifications to notifications in the teamwork
users in this team. activity feeds of the users in this
team, without a signed-in user.

Teams settings permissions

Delegated permissions
Permission Display String Description Admin Microsoft
Consent Account
Required supported

Team.ReadBasic.All Read the names Read the names and descriptions No No


and descriptions of of teams, on behalf of the signed-
teams in user.

TeamSettings.Read.All Read teams' Read all teams' settings, on behalf Yes No


settings of the signed-in user.

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

Team.ReadBasic.All Get a list of all Get a list of all teams, without a Yes No
teams. signed-in user.

TeamSettings.Read.All Read all teams' Read this team's settings, Yes No


settings without a 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.

Teams tab permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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.

TeamsTab.ReadWriteSelfForChat Allow the Allows a Teams app to read, install, Yes No


Teams app upgrade, and uninstall its own tabs in
to manage chats the signed-in user can access.
only its
own tabs in
chats.

TeamsTab.ReadWriteSelfForTeam Allow the Allows a Teams app to read, install, Yes No


Teams app upgrade, and uninstall its own tabs to
to manage teams the signed-in user can access.
only its
own tabs in
teams.

TeamsTab.ReadWriteSelfForUser Allow the Allows a Teams app to read, install, Yes No


Teams app upgrade, and uninstall its own tabs for the
to manage signed-in user.
only its
own tabs
for a user.

Application permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

TeamsTab.ReadWriteSelfForChat.All Allow the Allows a Teams app to read, install, Yes No


Teams app upgrade, and uninstall its own tabs for
to manage any chat, without a signed-in user.
only its own
tabs for all
chats.

TeamsTab.ReadWriteSelfForTeam.All Allow the Allows a Teams app to read, install, Yes No


Teams app upgrade, and uninstall its own tabs for
to manage any team, without a signed-in user.
only its own
tabs for all
teams.

TeamsTab.ReadWriteSelfForUser.All Allow the Allows a Teams app to read, install, Yes No


Teams app upgrade, and uninstall its own tabs for
to manage any user, without a signed-in user.
only its own
tabs for all
users.

Teams tag permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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.

TeamworkTag.Read.All Read tags in Allows the app to read tags in Yes No


Microsoft Teams. Teams without a signed-in user
Tenant information permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

CrossTenantInformation.ReadBasic.All Read basic Allows the app to read limited Yes No


information information about an external
about an tenant, on behalf of the signed-in
external tenant. user.

Application permissions

Permission Display String Description Admin


Consent
Required

CrossTenantInformation.ReadBasic.All Read basic Allows the app to read limited Yes


information about information about an external tenant,
an external tenant. without a signed-in user.

Terms of use permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required supported

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

The following usages are valid for both delegated permissions:

Agreement.Read.All: Read all terms of use agreements ( GET /beta/agreements )


Agreement.ReadWrite.All: Read and write all terms of use agreements ( POST /beta/agreements )
AgreementAcceptance.Read Read user terms of use acceptance statuses ( GET
/beta/me/agreementAcceptances )

For more complex scenarios involving multiple permissions, see Permission scenarios.

Threat assessment permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

ThreatAssessment.ReadWrite.All Read and Allows an app to read your organization's Yes No


write threat threat assessment requests on behalf of the
assessment signed-in user. Also allows the app to create
requests new requests to assess threats received by
your organization on behalf of the signed-
in user.

Application permissions

Permission Display String Description Admin


Consent
Required

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 )

Threat hunting permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported

ThreatHunting.Read.All Run Allows the app to run hunting queries, Yes No


hunting on behalf of the signed-in user.
queries

Application permissions

Permission Display String Description Admin Consent


Required

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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

Permission Display String Description Admin


Consent
Required

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

ThreatIntelligence.Read.All: Get host reputation information, without a signed-in user ( GET


/security/threatIntelligence/hosts/contoso.com/reputation )

Universal Print permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported
Permission Display Description Admin Microsoft
String Consent Account
Required supported

Printer.Create Register Allows the application to create (register) Yes No


printers printers on behalf of the signed-in user.

Printer.FullControl.All Register, read, Allows the application to create (register), Yes No


update, and read, update, and delete (unregister)
unregister printers on behalf of the signed-in user.
printers

Printer.Read.All Read printers Allows the application to read printers on Yes No


behalf of the signed-in user.

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.ReadBasic.All Read basic Allows the application to read basic No No


information information about printer shares on behalf
about printer of the signed-in user. Does not allow
shares reading access control information.

PrinterShare.Read.All Read printer Allows the application to read printer No No


shares shares on behalf of the signed-in user.

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.Create Create print Allows the application to create print jobs No No


jobs on behalf of the signed-in user and upload
document content to print jobs that the
signed-in user created.

PrintJob.Read Read user's Allows the application to read the metadata No No


print jobs and document content of print jobs that
the signed-in user created.

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 Read basic Allows the application to read the metadata No No


information of of print jobs that the signed-in user
user's print created. Does not allow access to print job
jobs document content.

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 Read and Allows the application to read and update No No


write user's the metadata and document content of
print jobs print jobs that the signed-in user created.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

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 Read and Allows the application to read and update No No


write basic the metadata of print jobs that the signed-
information of in user created. Does not allow access to
user's print print job document content.
jobs

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.Read.All Read Allows the application to read connectors Yes No


connectors on behalf of the signed-in user.

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

Permission Display Description Admin


String Consent
Required

Printer.Read.All Read Allows the application to read printers without a Yes


printers signed-in user.

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.Manage.All Perform Allows the application to perform advanced operations Yes


advanced like redirecting a print job to another printer without a
operations signed-in user. Also allows the application to read and
on print update the metadata of print jobs.
jobs

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

Printer.Read.All: Get a list of all printers in the tenant ( GET /print/printers )


PrintJob.Read.All: Get a list of all print jobs queued to a Printer ( GET /print/printers/{id}/jobs )
Printer.FullControl.All: Delete (unregister) a printer ( DELETE /print/printers/{id} )
PrintJob.ReadWriteBasic.All: Update metadata (such as current status) of print jobs ( PATCH
/print/printers/{id}/jobs/{id} )

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

Permission Display Description Admin Microsoft


String Consent Account
Required supported

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.Export.All Export Allows the app to export an organizational Yes No


users' data user's data, when performed by a Company
Administrator.

User.ManageIdentities.All Manage Allows an application to read, update and Yes No


user delete identities that are associated with a
identities user's account, that the signed-in user has
access to. This controls which identities your
users can sign-in with.
Permission Display Description Admin Microsoft
String Consent Account
Required supported

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

Permission Display Description Admin


String Consent
Required

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.

With the User.ManageIdentities.All delegated or application permission, it is possible to update the


identities ( identities ) of a user. This includes federated (or social identities) or local identities with email
or name-based sign-in names.

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.

User activity permissions

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}).

User authentication method permissions

Delegated permissions

Permission Display Description Admin Microsoft


String Consent Account
Required supported
Permission Display Description Admin Microsoft
String Consent Account
Required supported

UserAuthenticationMethod.Read Read own Allows the app to read the Yes No


authentication signed-in user's authentication
methods 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.

UserAuthenticationMethod.Read.All Read users' Allows the app to read Yes No


authentication authentication methods of all
methods users in your organization that
the signed-in user has access to.
Authentication methods include
things like a user's phone
numbers and Authenticator app
settings. This does not allow the
app to see secret information
like passwords, or to sign-in or
otherwise use the
authentication methods.

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.

UserAuthenticationMethod.ReadWrite.All Manage Allows the app to read and write Yes No


users' authentication methods of all
authentication users in your organization that
methods the signed-in user has access to.
Authentication methods include
things like a user's phone
numbers and Authenticator app
settings. This does not allow the
app to see secret information
like passwords, or to sign-in or
otherwise use the
authentication methods.

Application permissions
Permission Display Description Admin
String Consent
Required

UserAuthenticationMethod.Read.All Read users' Allows the app to read authentication Yes


authentication methods of all users in your organization,
methods without a signed-in user. Authentication
methods include things like a user's phone
numbers and Authenticator app settings. This
does not allow the app to see secret
information like passwords, or to sign-in or
otherwise use the authentication methods.

UserAuthenticationMethod.ReadWrite.All Manage Allows the application to read and write Yes


users' authentication methods of all users in your
authentication organization, without a signed-in user.
methods Authentication methods include things like a
user's phone numbers and Authenticator app
settings. This does not allow the app to see
secret information like passwords, or to sign-
in or otherwise use the authentication
methods.

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:

Primary authentication (password, FIDO2, Microsoft Authenticator, and so on)


Second factor of multi-factor authentication/MFA (phone numbers, Microsoft Authenticator, and so
on)
Self-Service Password Reset/SSPR (email address, and so on)

Windows updates permissions

Delegated permissions

Permission Display String Description Admin Microsoft


Consent Account
Required Supported

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

Permission Display String Description Admin


Consent
Required

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

WindowsUpdates.ReadWrite.All: Create a deployment ( POST


/beta/admin/windows/updates/deployments ).

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.

Access scenarios on the User resource

App tasks involving User Required Permission strings


permissions
App tasks involving User Required Permission strings
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

Access scenarios on the Group resource

App tasks involving Group Required Permission


permissions strings

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

All permissions and IDs


Permission name Type ID

AccessReview.Read.All Application d07a8cc0-3d51-4b77-b3b0-


32704d1f69fa

AccessReview.Read.All Delegated ebfcd32b-babb-40f4-a14b-


42706e83bd28

AccessReview.ReadWrite.All Application ef5f7d5c-338f-44b0-86c3-


351f46c8bb5f

AccessReview.ReadWrite.All Delegated e4aa47b9-9a69-4109-82ed-


36ec70d85ff1

AccessReview.ReadWrite.Membership Application 18228521-a591-40f1-b215-


5fad4488c117

AccessReview.ReadWrite.Membership Delegated 5af8c3f5-baca-439a-97b0-


ea58a435e269

Acronym.Read.All Application 8c0aed2c-0c61-433d-b63c-


6370ddc73248

Acronym.Read.All Delegated 9084c10f-a2d6-4713-8732-


348def50fe02

AdministrativeUnit.Read.All Application 134fd756-38ce-4afd-ba33-


e9623dbe66c2

AdministrativeUnit.Read.All Delegated 3361d15d-be43-4de6-b441-


3c746d05163d

AdministrativeUnit.ReadWrite.All Application 5eb59dd3-1da2-4329-8733-


9dabdc435916

AdministrativeUnit.ReadWrite.All Delegated 7b8a2d34-6b3f-4542-a343-


54651608ad81

Agreement.Read.All Application 2f3e6f8c-093b-4c57-a58b-


ba5ce494a169

Agreement.Read.All Delegated af2819c9-df71-4dd3-ade7-


4d7c9dc653b7

Agreement.ReadWrite.All Application c9090d00-6101-42f0-a729-


c41074260d47

Agreement.ReadWrite.All Delegated ef4b5d93-3104-4664-9053-


a5c49ab44218
Permission name Type ID

AgreementAcceptance.Read Delegated 0b7643bb-5336-476f-80b5-


18fbfbc91806

AgreementAcceptance.Read.All Application d8e4ec18-f6c0-4620-8122-


c8b1f2bf400e

AgreementAcceptance.Read.All Delegated a66a5341-e66e-4897-9d52-


c2df58c2bfb9

Analytics.Read Delegated e03cf23f-8056-446a-8994-


7d93dfc8b50e

APIConnectors.Read.All Application b86848a7-d5b1-41eb-a9b4-


54a4e6306e97

APIConnectors.Read.All Delegated 1b6ff35f-31df-4332-8571-


d31ea5a4893f

APIConnectors.ReadWrite.All Application 1dfe531a-24a6-4f1b-80f4-


7a0dc5a0a171

APIConnectors.ReadWrite.All Delegated c67b52c5-7c69-48b6-9d48-


7b3af3ded914

AppCatalog.Read.All Application e12dae10-5a57-4817-b79d-


dfbec5348930

AppCatalog.Read.All Delegated 88e58d74-d3df-44f3-ad47-


e89edf4472e4

AppCatalog.ReadWrite.All Application dc149144-f292-421e-b185-


5953f2e98d7f

AppCatalog.ReadWrite.All Delegated 1ca167d5-1655-44a1-8adf-


1414072e1ef9

AppCatalog.Submit Delegated 3db89e36-7fa6-4012-b281-


85f3d9d9fd2e

Application.Read.All Application 9a5d68dd-52b0-4cc2-bd40-


abcf44ac3a30

Application.Read.All Delegated c79f8feb-a9db-4090-85f9-


90d820caa0eb

Application.ReadWrite.All Application 1bfefb4e-e0b5-418b-a88f-


73c46d2cc8e9

Application.ReadWrite.All Delegated bdfbf15f-ee85-4955-8675-


146e8e5296b5

Application.ReadWrite.OwnedBy Application 18a4783c-866b-4cc7-a460-


3d5e5662c884

Application-RemoteDesktopConfig.ReadWrite.All Application 3be0012a-cc4e-426b-895b-


f9c836bf6381

Application-RemoteDesktopConfig.ReadWrite.All Delegated ffa91d43-2ad8-45cc-b592-


09caddeb24bb
Permission name Type ID

AppRoleAssignment.ReadWrite.All Application 06b708a9-e830-4db3-a914-


8e69da51d44f

AppRoleAssignment.ReadWrite.All Delegated 84bccea3-f856-4a8a-967b-


dbe0a3d53a64

AttackSimulation.Read.All Application 93283d0a-6322-4fa8-966b-


8c121624760d

AttackSimulation.Read.All Delegated 104a7a4b-ca76-4677-b7e7-


2f4bc482f381

AttackSimulation.ReadWrite.All Application e125258e-8c8a-42a8-8f55-


ab502afa52f3

AttackSimulation.ReadWrite.All Delegated 27608d7c-2c66-4cad-a657-


951d575f5a60

AuditLog.Read.All Application b0afded3-3588-46d8-8b3d-


9842eff778da

AuditLog.Read.All Delegated e4c9e354-4dc5-45b8-9e7c-


e1393b0b1a20

AuthenticationContext.Read.All Application 381f742f-e1f8-4309-b4ab-


e3d91ae4c5c1

AuthenticationContext.Read.All Delegated 57b030f1-8c35-469c-b0d9-


e4a077debe70

AuthenticationContext.ReadWrite.All Application a88eef72-fed0-4bf7-a2a9-f19df33f8b83

AuthenticationContext.ReadWrite.All Delegated ba6d575a-1344-4516-b777-


1404f5593057

BillingConfiguration.ReadWrite.All Application 9e8be751-7eee-4c09-bcfd-


d64f6b087fd8

BillingConfiguration.ReadWrite.All Delegated 2bf6d319-dfca-4c22-9879-


f88dcfaee6be

BitlockerKey.Read.All Delegated b27a61ec-b99c-4d6a-b126-


c4375d08ae30

BitlockerKey.ReadBasic.All Delegated 5a107bfc-4f00-4e1a-b67e-


66451267bc68

Bookings.Manage.All Delegated 7f36b48e-542f-4d3b-9bcb-


8406f0ab9fdb

Bookings.Read.All Application 6e98f277-b046-4193-a4f2-


6bf6a78cd491

Bookings.Read.All Delegated 33b1df99-4b29-4548-9339-


7a7b83eaeebc

Bookings.ReadWrite.All Delegated 948eb538-f19d-4ec5-9ccc-


f059e1ea4c72
Permission name Type ID

BookingsAppointment.ReadWrite.All Application 9769393e-5a9f-4302-9e3d-


7e018ecb64a7

BookingsAppointment.ReadWrite.All Delegated 02a5a114-36a6-46ff-a102-


954d89d9ab02

Bookmark.Read.All Application be95e614-8ef3-49eb-8464-


1c9503433b86

Bookmark.Read.All Delegated 98b17b35-f3b1-4849-a85f-


9f13733002f0

BrowserSiteLists.Read.All Application c5ee1f21-fc7f-4937-9af0-c91648ff9597

BrowserSiteLists.Read.All Delegated fb9be2b7-a7fc-4182-aec1-


eda4597c43d5

BrowserSiteLists.ReadWrite.All Application 8349ca94-3061-44d5-9bfb-


33774ea5e4f9

BrowserSiteLists.ReadWrite.All Delegated 83b34c85-95bf-497b-a04e-


b58eca9d49d0

BusinessScenarioConfig.Read.All Delegated d16480b2-e469-4118-846b-


d3d177327bee

BusinessScenarioConfig.Read.OwnedBy Application acc0fc4d-2cd6-4194-8700-


1768d8423d86

BusinessScenarioConfig.Read.OwnedBy Delegated c47e7b6e-d6f1-4be9-9ffd-


1e00f3e32892

BusinessScenarioConfig.ReadWrite.All Delegated 755e785b-b658-446f-bb22-


5a46abd029ea

BusinessScenarioConfig.ReadWrite.OwnedBy Application bbea195a-4c47-4a4f-bff2-


cba399e11698

BusinessScenarioConfig.ReadWrite.OwnedBy Delegated b3b7fcff-b4d4-4230-bf6f-


90bd91285395

BusinessScenarioData.Read.OwnedBy Application 6c0257fd-cffe-415b-8239-


2d0d70fdaa9c

BusinessScenarioData.Read.OwnedBy Delegated 25b265c4-5d34-4e44-952d-


b567f6d3b96d

BusinessScenarioData.ReadWrite.OwnedBy Application f2d21f22-5d80-499e-91cc-


0a8a4ce16f54

BusinessScenarioData.ReadWrite.OwnedBy Delegated 19932d57-2952-4c60-8634-


3655c79fc527

Calendars.Read Application 798ee544-9d2d-430c-a058-


570e29e34338

Calendars.Read Delegated 465a38f9-76ea-45b9-9f34-


9e8b0d4b0b42
Permission name Type ID

Calendars.Read.Shared Delegated 2b9c4092-424d-4249-948d-


b43879977640

Calendars.ReadBasic Delegated 662d75ba-a364-42ad-adee-


f5f880ea4878

Calendars.ReadBasic.All Application 8ba4a692-bc31-4128-9094-


475872af8a53

Calendars.ReadWrite Application ef54d2bf-783f-4e0f-bca1-


3210c0444d99

Calendars.ReadWrite Delegated 1ec239c2-d7c9-4623-a91a-


a9775856bb36

Calendars.ReadWrite.Shared Delegated 12466101-c9b8-439a-8589-


dd09ee67e8e9

CallRecord-PstnCalls.Read.All Application a2611786-80b3-417e-adaa-


707d4261a5f0

CallRecords.Read.All Application 45bbb07e-7321-4fd7-a8f6-


3ff27e6a81c8

Calls.AccessMedia.All Application a7a681dc-756e-4909-b988-


f160edc6655f

Calls.Initiate.All Application 284383ee-7f6e-4e40-a2a8-


e85dcb029101

Calls.InitiateGroupCall.All Application 4c277553-8a09-487b-8023-


29ee378d8324

Calls.JoinGroupCall.All Application f6b49018-60ab-4f81-83bd-


22caeabfed2d

Calls.JoinGroupCallAsGuest.All Application fd7ccf6b-3d28-418b-9701-


cd10f5cd2fd4

Channel.Create Application f3a65bd4-b703-46df-8f7e-


0174fea562aa

Channel.Create Delegated 101147cf-4178-4455-9d58-


02b5c164e759

Channel.Delete.All Application 6a118a39-1227-45d4-af0c-


ea7b40d210bc

Channel.Delete.All Delegated cc83893a-e232-4723-b5af-


bd0b01bcfe65

Channel.ReadBasic.All Application 59a6b24b-4225-4393-8165-


ebaec5f55d7a

Channel.ReadBasic.All Delegated 9d8982ae-4365-4f57-95e9-


d6032a4c0b87

ChannelMember.Read.All Application 3b55498e-47ec-484f-8136-


9013221c06a9
Permission name Type ID

ChannelMember.Read.All Delegated 2eadaff8-0bce-4198-a6b9-


2cfc35a30075

ChannelMember.ReadWrite.All Application 35930dcf-aceb-4bd1-b99a-


8ffed403c974

ChannelMember.ReadWrite.All Delegated 0c3e411a-ce45-4cd1-8f30-


f99a3efa7b11

ChannelMessage.Edit Delegated 2b61aa8a-6d36-4b2f-ac7b-


f29867937c53

ChannelMessage.Read.All Application 7b2449af-6ccd-4f4d-9f78-


e550c193f0d1

ChannelMessage.Read.All Delegated 767156cb-16ae-4d10-8f8b-


41b657c8c8c8

ChannelMessage.ReadWrite Delegated 5922d31f-46c8-4404-9eaf-


2117e390a8a4

ChannelMessage.Send Delegated ebf0f66e-9fb1-49e4-a278-


222f76911cf4

ChannelMessage.UpdatePolicyViolation.All Application 4d02b0cc-d90b-441f-8d82-


4fb55c34d6bb

ChannelSettings.Read.All Application c97b873f-f59f-49aa-8a0e-


52b32d762124

ChannelSettings.Read.All Delegated 233e0cf1-dd62-48bc-b65b-


b38fe87fcf8e

ChannelSettings.ReadWrite.All Application 243cded2-bd16-4fd6-a953-


ff8177894c3d

ChannelSettings.ReadWrite.All Delegated d649fb7c-72b4-4eec-b2b4-


b15acf79e378

Chat.Create Application d9c48af6-9ad9-47ad-82c3-


63757137b9af

Chat.Create Delegated 38826093-1258-4dea-98f0-


00003be2b8d0

Chat.ManageDeletion.All Application 9c7abde0-eacd-4319-bf9e-


35994b1a1717

Chat.ManageDeletion.All Delegated bb64e6fc-6b6d-4752-aea0-


dd922dbba588

Chat.Read Delegated f501c180-9344-439a-bca0-


6cbf209fd270

Chat.Read.All Application 6b7d71aa-70aa-4810-a8d9-


5d9fb2830017

Chat.Read.WhereInstalled Application 1c1b4c8e-3cc7-4c58-8470-


9b92c9d5848b
Permission name Type ID

Chat.ReadBasic Delegated 9547fcb5-d03f-419d-9948-


5928bbf71b0f

Chat.ReadBasic.All Application b2e060da-3baf-4687-9611-


f4ebc0f0cbde

Chat.ReadBasic.WhereInstalled Application 818ba5bd-5b3e-4fe0-bbe6-


aa4686669073

Chat.ReadWrite Delegated 9ff7295e-131b-4d94-90e1-


69fde507ac11

Chat.ReadWrite.All Application 294ce7c9-31ba-490a-ad7d-


97a7d075e4ed

Chat.ReadWrite.WhereInstalled Application ad73ce80-f3cd-40ce-b325-


df12c33df713

Chat.UpdatePolicyViolation.All Application 7e847308-e030-4183-9899-


5235d7270f58

ChatMember.Read Delegated c5a9e2b1-faf6-41d4-8875-


d381aa549b24

ChatMember.Read.All Application a3410be2-8e48-4f32-8454-


c29a7465209d

ChatMember.Read.WhereInstalled Application 93e7c9e4-54c5-4a41-b796-


f2a5adaacda7

ChatMember.ReadWrite Delegated dea13482-7ea6-488f-8b98-


eb5bbecf033d

ChatMember.ReadWrite.All Application 57257249-34ce-4810-a8a2-


a03adf0c5693

ChatMember.ReadWrite.WhereInstalled Application e32c2cd9-0124-4e44-88fc-


772cd98afbdb

ChatMessage.Read Delegated cdcdac3a-fd45-410d-83ef-


554db620e5c7

ChatMessage.Read.All Application b9bb2381-47a4-46cd-aafb-


00cb12f68504

ChatMessage.Send Delegated 116b7235-7cc6-461e-b163-


8e55691d839e

CloudPC.Read.All Application a9e09520-8ed4-4cde-838e-


4fdea192c227

CloudPC.Read.All Delegated 5252ec4e-fd40-4d92-8c68-


89dd1d3c6110

CloudPC.ReadWrite.All Application 3b4349e1-8cf5-45a3-95b7-


69d1751d3e6a

CloudPC.ReadWrite.All Delegated 9d77138f-f0e2-47ba-ab33-


cd246c8b79d1
Permission name Type ID

ConsentRequest.Read.All Application 1260ad83-98fb-4785-abbb-


d6cc1806fd41

ConsentRequest.Read.All Delegated f3bfad56-966e-4590-a536-


82ecf548ac1e

ConsentRequest.ReadWrite.All Application 9f1b81a7-0223-4428-bfa4-


0bcb5535f27d

ConsentRequest.ReadWrite.All Delegated 497d9dfa-3bd1-481a-baab-


90895e54568c

Contacts.Read Application 089fe4d0-434a-44c5-8827-


41ba8a0b17f5

Contacts.Read Delegated ff74d97f-43af-4b68-9f2a-


b77ee6968c5d

Contacts.Read.Shared Delegated 242b9d9e-ed24-4d09-9a52-


f43769beb9d4

Contacts.ReadWrite Application 6918b873-d17a-4dc1-b314-


35f528134491

Contacts.ReadWrite Delegated d56682ec-c09e-4743-aaf4-


1a3aac4caa21

Contacts.ReadWrite.Shared Delegated afb6c84b-06be-49af-80bb-


8f3f77004eab

CrossTenantInformation.ReadBasic.All Application cac88765-0581-4025-9725-


5ebc13f729ee

CrossTenantInformation.ReadBasic.All Delegated 81594d25-e88e-49cf-ac8c-fecbff49f994

CrossTenantUserProfileSharing.Read Delegated cb1ba48f-d22b-4325-a07f-


74135a62ee41

CrossTenantUserProfileSharing.Read.All Application 8b919d44-6192-4f3d-8a3b-


f86f8069ae3c

CrossTenantUserProfileSharing.Read.All Delegated 759dcd16-3c90-463c-937e-


abf89f991c18

CrossTenantUserProfileSharing.ReadWrite Delegated eed0129d-dc60-4f30-8641-


daf337a39ffd

CrossTenantUserProfileSharing.ReadWrite.All Application 306785c5-c09b-4ba0-a4ee-


023f3da165cb

CrossTenantUserProfileSharing.ReadWrite.All Delegated 64dfa325-cbf8-48e3-938d-


51224a0cac01

CustomAuthenticationExtension.Read.All Application 88bb2658-5d9e-454f-aacd-


a3933e079526

CustomAuthenticationExtension.Read.All Delegated b2052569-c98c-4f36-a5fb-


43e5c111e6d0
Permission name Type ID

CustomAuthenticationExtension.ReadWrite.All Application c2667967-7050-4e7e-b059-


4cbbb3811d03

CustomAuthenticationExtension.ReadWrite.All Delegated 8dfcf82f-15d0-43b3-bc78-


a958a13a5792

CustomAuthenticationExtension.Receive.Payload Application 214e810f-fda8-4fd7-a475-


29461495eb00

CustomSecAttributeAssignment.Read.All Application 3b37c5a4-1226-493d-bec3-


5d6c6b866f3f

CustomSecAttributeAssignment.Read.All Delegated b46ffa80-fe3d-4822-9a1a-


c200932d54d0

CustomSecAttributeAssignment.ReadWrite.All Application de89b5e4-5b8f-48eb-8925-


29c2b33bd8bd

CustomSecAttributeAssignment.ReadWrite.All Delegated ca46335e-8453-47cd-a001-


8459884efeae

CustomSecAttributeDefinition.Read.All Application b185aa14-d8d2-42c1-a685-


0f5596613624

CustomSecAttributeDefinition.Read.All Delegated ce026878-a0ff-4745-a728-


d4fedd086c07

CustomSecAttributeDefinition.ReadWrite.All Application 12338004-21f4-4896-bf5e-


b75dfaf1016d

CustomSecAttributeDefinition.ReadWrite.All Delegated 8b0160d4-5743-482b-bb27-


efc0a485ca4a

DelegatedAdminRelationship.Read.All Application f6e9e124-4586-492f-adc0-


c6f96e4823fd

DelegatedAdminRelationship.Read.All Delegated 0c0064ea-477b-4130-82a5-


4c2cc4ff68aa

DelegatedAdminRelationship.ReadWrite.All Application cc13eba4-8cd8-44c6-b4d4-


f93237adce58

DelegatedAdminRelationship.ReadWrite.All Delegated 885f682f-a990-4bad-a642-


36736a74b0c7

DelegatedPermissionGrant.ReadWrite.All Application 8e8e4742-1d95-4f68-9d56-


6ee75648c72a

DelegatedPermissionGrant.ReadWrite.All Delegated 41ce6ca6-6826-4807-84f1-


1c82854f7ee5

Device.Command Delegated bac3b9c2-b516-4ef4-bd3b-


c2ef73d8d804

Device.Read Delegated 11d4cd79-5ba5-460f-803f-


e22c8ab85ccd

Device.Read.All Application 7438b122-aefc-4978-80ed-


43db9fcc7715
Permission name Type ID

Device.Read.All Delegated 951183d1-1a61-466f-a6d1-


1fde911bfd95

Device.ReadWrite.All Application 1138cb37-bd11-4084-a2b7-


9f71582aeddb

DeviceLocalCredential.Read.All Application 884b599e-4d48-43a5-ba94-


15c414d00588

DeviceLocalCredential.Read.All Delegated 280b3b69-0437-44b1-bc20-


3b2fca1ee3e9

DeviceLocalCredential.ReadBasic.All Application db51be59-e728-414b-b800-


e0f010df1a79

DeviceLocalCredential.ReadBasic.All Delegated 9917900e-410b-4d15-846e-


42a357488545

DeviceManagementApps.Read.All Application 7a6ee1e7-141e-4cec-ae74-


d9db155731ff

DeviceManagementApps.Read.All Delegated 4edf5f54-4666-44af-9de9-


0144fb4b6e8c

DeviceManagementApps.ReadWrite.All Application 78145de6-330d-4800-a6ce-


494ff2d33d07

DeviceManagementApps.ReadWrite.All Delegated 7b3f05d5-f68c-4b8d-8c59-


a2ecd12f24af

DeviceManagementConfiguration.Read.All Application dc377aa6-52d8-4e23-b271-


2a7ae04cedf3

DeviceManagementConfiguration.Read.All Delegated f1493658-876a-4c87-8fa7-


edb559b3476a

DeviceManagementConfiguration.ReadWrite.All Application 9241abd9-d0e6-425a-bd4f-


47ba86e767a4

DeviceManagementConfiguration.ReadWrite.All Delegated 0883f392-0a7a-443d-8c76-


16a6d39c7b63

DeviceManagementManagedDevices.PrivilegedOperations.All Application 5b07b0dd-2377-4e44-a38d-


703f09a0dc3c

DeviceManagementManagedDevices.PrivilegedOperations.All Delegated 3404d2bf-2b13-457e-a330-


c24615765193

DeviceManagementManagedDevices.Read.All Application 2f51be20-0bb4-4fed-bf7b-


db946066c75e

DeviceManagementManagedDevices.Read.All Delegated 314874da-47d6-4978-88dc-


cf0d37f0bb82

DeviceManagementManagedDevices.ReadWrite.All Application 243333ab-4d21-40cb-a475-


36241daa0842

DeviceManagementManagedDevices.ReadWrite.All Delegated 44642bfe-8385-4adc-8fc6-


fe3cb2c375c3
Permission name Type ID

DeviceManagementRBAC.Read.All Application 58ca0d9a-1575-47e1-a3cb-


007ef2e4583b

DeviceManagementRBAC.Read.All Delegated 49f0cc30-024c-4dfd-ab3e-


82e137ee5431

DeviceManagementRBAC.ReadWrite.All Application e330c4f0-4170-414e-a55a-


2f022ec2b57b

DeviceManagementRBAC.ReadWrite.All Delegated 0c5e8a55-87a6-4556-93ab-


adc52c4d862d

DeviceManagementServiceConfig.Read.All Application 06a5fe6d-c49d-46a7-b082-


56b1b14103c7

DeviceManagementServiceConfig.Read.All Delegated 8696daa5-bce5-4b2e-83f9-


51b6defc4e1e

DeviceManagementServiceConfig.ReadWrite.All Application 5ac13192-7ace-4fcf-b828-


1a26f28068ee

DeviceManagementServiceConfig.ReadWrite.All Delegated 662ed50a-ac44-4eef-ad86-


62eed9be2a29

Directory.AccessAsUser.All Delegated 0e263e50-5827-48a4-b97c-


d940288653c7

Directory.Read.All Application 7ab1d382-f21e-4acd-a863-


ba3e13f7da61

Directory.Read.All Delegated 06da0dbc-49e2-44d2-8312-


53f166ab848a

Directory.ReadWrite.All Application 19dbc75e-c2e2-444c-a770-


ec69d8559fc7

Directory.ReadWrite.All Delegated c5366453-9fb0-48a5-a156-


24f0c49a4b84

Directory.Write.Restricted Application f20584af-9290-4153-9280-


ff8bb2c0ea7f

Directory.Write.Restricted Delegated cba5390f-ed6a-4b7f-b657-


0efc2210ed20

DirectoryRecommendations.Read.All Application ae73097b-cb2a-4447-b064-


5d80f6093921

DirectoryRecommendations.Read.All Delegated 34d3bd24-f6a6-468c-b67c-


0c365c1d6410

DirectoryRecommendations.ReadWrite.All Application 0e9eea12-4f01-45f6-9b8d-


3ea4c8144158

DirectoryRecommendations.ReadWrite.All Delegated f37235e8-90a0-4189-93e2-


e55b53867ccd

Domain.Read.All Application dbb9058a-0e50-45d7-ae91-


66909b5d4664
Permission name Type ID

Domain.Read.All Delegated 2f9ee017-59c1-4f1d-9472-


bd5529a7b311

Domain.ReadWrite.All Application 7e05723c-0bb0-42da-be95-


ae9f08a6e53c

Domain.ReadWrite.All Delegated 0b5d694c-a244-4bde-86e6-


eb5cd07730fe

EAS.AccessAsUser.All Delegated ff91d191-45a0-43fd-b837-


bd682c4a0b0f

eDiscovery.Read.All Application 50180013-6191-4d1e-a373-


e590ff4e66af

eDiscovery.Read.All Delegated 99201db3-7652-4d5a-809a-


bdb94f85fe3c

eDiscovery.ReadWrite.All Application b2620db1-3bf7-4c5b-9cb9-


576d29eac736

eDiscovery.ReadWrite.All Delegated acb8f680-0834-4146-b69e-


4ab1b39745ad

EduAdministration.Read Delegated 8523895c-6081-45bf-8a5d-


f062a2f12c9f

EduAdministration.Read.All Application 7c9db06a-ec2d-4e7b-a592-


5a1e30992566

EduAdministration.ReadWrite Delegated 63589852-04e3-46b4-bae9-


15d5b1050748

EduAdministration.ReadWrite.All Application 9bc431c3-b8bc-4a8d-a219-


40f10f92eff6

EduAssignments.Read Delegated 091460c9-9c4a-49b2-81ef-


1f3d852acce2

EduAssignments.Read.All Application 4c37e1b6-35a1-43bf-926a-


6f30f2cdf585

EduAssignments.ReadBasic Delegated c0b0103b-c053-4b2e-9973-


9f3a544ec9b8

EduAssignments.ReadBasic.All Application 6e0a958b-b7fc-4348-b7c4-


a6ab9fd3dd0e

EduAssignments.ReadWrite Delegated 2f233e90-164b-4501-8bce-


31af2559a2d3

EduAssignments.ReadWrite.All Application 0d22204b-6cad-4dd0-8362-


3e3f2ae699d9

EduAssignments.ReadWriteBasic Delegated 2ef770a1-622a-47c4-93ee-


28d6adbed3a0

EduAssignments.ReadWriteBasic.All Application f431cc63-a2de-48c4-8054-


a34bc093af84
Permission name Type ID

EduRoster.Read Delegated a4389601-22d9-4096-ac18-


36a927199112

EduRoster.Read.All Application e0ac9e1b-cb65-4fc5-87c5-


1a8bc181f648

EduRoster.ReadBasic Delegated 5d186531-d1bf-4f07-8cea-


7c42119e1bd9

EduRoster.ReadBasic.All Application 0d412a8c-a06c-439f-b3ec-


8abcf54d2f96

EduRoster.ReadWrite Delegated 359e19a6-e3fa-4d7f-bcab-


d28ec592b51e

EduRoster.ReadWrite.All Application d1808e82-ce13-47af-ae0d-


f9b254e6d58a

email Delegated 64a6cdd6-aab1-4aaf-94b8-


3cc8405e90d0

EntitlementManagement.Read.All Application c74fd47d-ed3c-45c3-9a9e-


b8676de685d2

EntitlementManagement.Read.All Delegated 5449aa12-1393-4ea2-a7c7-


d0e06c1a56b2

EntitlementManagement.ReadWrite.All Application 9acd699f-1e81-4958-b001-


93b1d2506e19

EntitlementManagement.ReadWrite.All Delegated ae7a573d-81d7-432b-ad44-


4ed5c9d89038

EntitlementMgmt-SubjectAccess.ReadWrite Delegated e9fdcbbb-8807-410f-b9ec-


8d5468c7c2ac

EventListener.Read.All Application b7f6385c-6ce6-4639-a480-


e23c42ed9784

EventListener.Read.All Delegated f7dd3bed-5eec-48da-bc73-


1c0ef50bc9a1

EventListener.ReadWrite.All Application 0edf5e9e-4ce8-468a-8432-


d08631d18c43

EventListener.ReadWrite.All Delegated d11625a6-fe21-4fc6-8d3d-


063eba5525ad

EWS.AccessAsUser.All Delegated 9769c687-087d-48ac-9cb3-


c37dde652038

ExternalConnection.Read.All Application 1914711b-a1cb-4793-b019-


c2ce0ed21b8c

ExternalConnection.Read.All Delegated a38267a5-26b6-4d76-9493-


935b7599116b

ExternalConnection.ReadWrite.All Application 34c37bc0-2b40-4d5e-85e1-


2365cd256d79
Permission name Type ID

ExternalConnection.ReadWrite.All Delegated bbbbd9b3-3566-4931-ac37-


2b2180d9e334

ExternalConnection.ReadWrite.OwnedBy Application f431331c-49a6-499f-be1c-


62af19c34a9d

ExternalConnection.ReadWrite.OwnedBy Delegated 4082ad95-c812-4f02-be92-


780c4c4f1830

ExternalItem.Read.All Application 7a7cffad-37d2-4f48-afa4-


c6ab129adcc2

ExternalItem.Read.All Delegated 922f9392-b1b7-483c-a4be-


0089be7704fb

ExternalItem.ReadWrite.All Application 38c3d6ee-69ee-422f-b954-


e17819665354

ExternalItem.ReadWrite.All Delegated b02c54f8-eb48-4c50-a9f0-


a149e5a2012f

ExternalItem.ReadWrite.OwnedBy Application 8116ae0f-55c2-452d-9944-


d18420f5b2c8

ExternalItem.ReadWrite.OwnedBy Delegated 4367b9d7-cee7-4995-853c-


a0bdfe95c1f9

Family.Read Delegated 3a1e4806-a744-4c70-80fc-


223bf8582c46

Files.Read Delegated 10465720-29dd-4523-a11a-


6a75c743c9d9

Files.Read.All Application 01d4889c-1287-42c6-ac1f-


5d1e02578ef6

Files.Read.All Delegated df85f4d6-205c-4ac5-a5ea-


6bf408dba283

Files.Read.Selected Delegated 5447fe39-cb82-4c1a-b977-


520e67e724eb

Files.ReadWrite Delegated 5c28f0bf-8a70-41f1-8ab2-


9032436ddb65

Files.ReadWrite.All Application 75359482-378d-4052-8f01-


80520e7db3cd

Files.ReadWrite.All Delegated 863451e7-0667-486c-a5d6-


d135439485f0

Files.ReadWrite.AppFolder Delegated 8019c312-3263-48e6-825e-


2b833497195b

Files.ReadWrite.Selected Delegated 17dde5bd-8c17-420f-a486-


969730c1b827

Financials.ReadWrite.All Delegated f534bf13-55d4-45a9-8f3c-


c92fe64d6131
Permission name Type ID

Group.Create Application bf7b1a76-6e77-406b-b258-


bf5c7720e98f

Group.Read.All Application 5b567255-7703-4780-807c-


7be8301ae99b

Group.Read.All Delegated 5f8c59db-677d-491f-a6b8-


5f174b11ec1d

Group.ReadWrite.All Application 62a82d76-70ea-41e2-9197-


370581804d09

Group.ReadWrite.All Delegated 4e46008b-f24c-477d-8fff-


7bb4ec7aafe0

GroupMember.Read.All Application 98830695-27a2-44f7-8c18-


0c3ebc9698f6

GroupMember.Read.All Delegated bc024368-1153-4739-b217-


4326f2e966d0

GroupMember.ReadWrite.All Application dbaae8cf-10b5-4b86-a4a1-


f871c94c6695

GroupMember.ReadWrite.All Delegated f81125ac-d3b7-4573-a3b2-


7099cc39df9e

IdentityProvider.Read.All Application e321f0bb-e7f7-481e-bb28-


e3b0b32d4bd0

IdentityProvider.Read.All Delegated 43781733-b5a7-4d1b-98f4-


e8edff23e1a9

IdentityProvider.ReadWrite.All Application 90db2b9a-d928-4d33-a4dd-


8442ae3d41e4

IdentityProvider.ReadWrite.All Delegated f13ce604-1677-429f-90bd-


8a10b9f01325

IdentityRiskEvent.Read.All Application 6e472fd1-ad78-48da-a0f0-


97ab2c6b769e

IdentityRiskEvent.Read.All Delegated 8f6a01e7-0391-4ee5-aa22-


a3af122cef27

IdentityRiskEvent.ReadWrite.All Application db06fb33-1953-4b7b-a2ac-


f1e2c854f7ae

IdentityRiskEvent.ReadWrite.All Delegated 9e4862a5-b68f-479e-848a-


4e07e25c9916

IdentityRiskyServicePrincipal.Read.All Application 607c7344-0eed-41e5-823a-


9695ebe1b7b0

IdentityRiskyServicePrincipal.Read.All Delegated ea5c4ab0-5a73-4f35-8272-


5d5337884e5d

IdentityRiskyServicePrincipal.ReadWrite.All Application cb8d6980-6bcb-4507-afec-


ed6de3a2d798
Permission name Type ID

IdentityRiskyServicePrincipal.ReadWrite.All Delegated bb6f654c-d7fd-4ae3-85c3-


fc380934f515

IdentityRiskyUser.Read.All Application dc5007c0-2d7d-4c42-879c-


2dab87571379

IdentityRiskyUser.Read.All Delegated d04bb851-cb7c-4146-97c7-


ca3e71baf56c

IdentityRiskyUser.ReadWrite.All Application 656f6061-f9fe-4807-9708-


6a2e0934df76

IdentityRiskyUser.ReadWrite.All Delegated e0a7cdbb-08b0-4697-8264-


0069786e9674

IdentityUserFlow.Read.All Application 1b0c317f-dd31-4305-9932-


259a8b6e8099

IdentityUserFlow.Read.All Delegated 2903d63d-4611-4d43-99ce-


a33f3f52e343

IdentityUserFlow.ReadWrite.All Application 65319a09-a2be-469d-8782-


f6b07debf789

IdentityUserFlow.ReadWrite.All Delegated 281892cc-4dbf-4e3a-b6cc-


b21029bb4e82

IMAP.AccessAsUser.All Delegated 652390e4-393a-48de-9484-


05f9b1212954

IndustryData.ReadBasic.All Application 4f5ac95f-62fd-472c-b60f-


125d24ca0bc5

IndustryData.ReadBasic.All Delegated 60382b96-1f5e-46ea-a544-


0407e489e588

IndustryData-DataConnector.Read.All Application 7ab52c2f-a2ee-4d98-9ebc-


725e3934aae2

IndustryData-DataConnector.Read.All Delegated d19c0de5-7ecb-4aba-b090-


da35ebcd5425

IndustryData-DataConnector.ReadWrite.All Application eda0971c-482e-4345-b28f-


69c309cb8a34

IndustryData-DataConnector.ReadWrite.All Delegated 5ce933ac-3997-4280-aed0-


cc072e5c062a

IndustryData-DataConnector.Upload Application 9334c44b-a7c6-4350-8036-


6bf8e02b4c1f

IndustryData-DataConnector.Upload Delegated fc47391d-ab2c-410f-9059-


5600f7af660d

IndustryData-InboundFlow.Read.All Application 305f6ba2-049a-4b1b-88bb-


fe7e08758a00

IndustryData-InboundFlow.Read.All Delegated cb0774da-a605-42af-959c-


32f438fb38f4
Permission name Type ID

IndustryData-InboundFlow.ReadWrite.All Application e688c61f-d4c6-4d64-a197-


3bcf6ba1d6ad

IndustryData-InboundFlow.ReadWrite.All Delegated 97044676-2cec-40ee-bd70-


38df444c9e70

IndustryData-ReferenceDefinition.Read.All Application 6ee891c3-74a4-4148-8463-


0c834375dfaf

IndustryData-ReferenceDefinition.Read.All Delegated a3f96ffe-cb84-40a8-ac85-


582d7ef97c2a

IndustryData-Run.Read.All Application f6f5d10b-3024-4d1d-b674-


aae4df4a1a73

IndustryData-Run.Read.All Delegated 92685235-50c4-4702-b2c8-


36043db6fa79

IndustryData-SourceSystem.Read.All Application bc167a60-39fe-4865-8b44-


78400fc6ed03

IndustryData-SourceSystem.Read.All Delegated 49b7016c-89ae-41e7-bd6f-


b7170c5490bf

IndustryData-SourceSystem.ReadWrite.All Application 7d866958-e06e-4dd6-91c6-


a086b3f5cfeb

IndustryData-SourceSystem.ReadWrite.All Delegated 9599f005-05d6-4ea7-b1b1-


4929768af5d0

IndustryData-TimePeriod.Read.All Application 7c55c952-b095-4c23-a522-


022bce4cc1e3

IndustryData-TimePeriod.Read.All Delegated c9d51f28-8ccd-42b2-a836-


fd8fe9ebf2ae

IndustryData-TimePeriod.ReadWrite.All Application 7afa7744-a782-4a32-b8c2-


e3db637e8de7

IndustryData-TimePeriod.ReadWrite.All Delegated b6d56528-3032-4f9d-830f-


5a24a25e6661

InformationProtectionConfig.Read Delegated 12f4bffb-b598-413c-984b-


db99728f8b54

InformationProtectionConfig.Read.All Application 14f49b9f-4bf2-4d24-b80e-


b27ec58409bd

InformationProtectionContent.Sign.All Application cbe6c7e4-09aa-4b8d-b3c3-


2dbb59af4b54

InformationProtectionContent.Write.All Application 287bd98c-e865-4e8c-bade-


1a85523195b9

InformationProtectionPolicy.Read Delegated 4ad84827-5578-4e18-ad7a-


86530b12f884

InformationProtectionPolicy.Read.All Application 19da66cb-0fb0-4390-b071-


ebc76a349482
Permission name Type ID

LearningAssignedCourse.Read Delegated ac08cdae-e845-41db-adf9-


5899a0ec9ef6

LearningAssignedCourse.Read.All Application 535e6066-2894-49ef-ab33-


e2c6d064bb81

LearningAssignedCourse.ReadWrite.All Application 236c1cbd-1187-427f-b0f5-


b1852454973b

LearningContent.Read.All Application 8740813e-d8aa-4204-860e-


2a0f8f84dbc8

LearningContent.Read.All Delegated ea4c1fd9-6a9f-4432-8e5d-


86e06cc0da77

LearningContent.ReadWrite.All Application 444d6fcb-b738-41e5-b103-


ac4f2a2628a3

LearningContent.ReadWrite.All Delegated 53cec1c4-a65f-4981-9dc1-


ad75dbf1c077

LearningProvider.Read Delegated dd8ce36f-9245-45ea-a99e-


8ac398c22861

LearningProvider.ReadWrite Delegated 40c2eb57-abaf-49f5-9331-


e90fd01f7130

LearningSelfInitiatedCourse.Read Delegated f6403ef7-4a96-47be-a190-


69ba274c3f11

LearningSelfInitiatedCourse.Read.All Application 467524fc-ed22-4356-a910-


af61191e3503

LearningSelfInitiatedCourse.ReadWrite.All Application 7654ed61-8965-4025-846a-


0856ec02b5b0

LicenseAssignment.ReadWrite.All Application 5facf0c1-8979-4e95-abcf-ff3d079771c0

LicenseAssignment.ReadWrite.All Delegated f55016cc-149c-447e-8f21-


7cf3ec1d6350

LifecycleWorkflows.Read.All Application 7c67316a-232a-4b84-be22-


cea2c0906404

LifecycleWorkflows.Read.All Delegated 9bcb9916-765a-42af-bf77-


02282e26b01a

LifecycleWorkflows.ReadWrite.All Application 5c505cf4-8424-4b8e-aa14-


ee06e3bb23e3

LifecycleWorkflows.ReadWrite.All Delegated 84b9d731-7db8-4454-8c90-


fd9e95350179

Mail.Read Application 810c84a8-4a9e-49e6-bf7d-


12d183f40d01

Mail.Read Delegated 570282fd-fa5c-430d-a7fd-


fc8dc98a9dca
Permission name Type ID

Mail.Read.Shared Delegated 7b9103a5-4610-446b-9670-


80643382c1fa

Mail.ReadBasic Application 6be147d2-ea4f-4b5a-a3fa-


3eab6f3c140a

Mail.ReadBasic Delegated a4b8392a-d8d1-4954-a029-


8e668a39a170

Mail.ReadBasic.All Application 693c5e45-0940-467d-9b8a-


1022fb9d42ef

Mail.ReadBasic.Shared Delegated b11fa0e7-fdb7-4dc9-b1f1-


59facd463480

Mail.ReadWrite Application e2a3a72e-5f79-4c64-b1b1-


878b674786c9

Mail.ReadWrite Delegated 024d486e-b451-40bb-833d-


3e66d98c5c73

Mail.ReadWrite.Shared Delegated 5df07973-7d5d-46ed-9847-


1271055cbd51

Mail.Send Application b633e1c5-b582-4048-a93e-


9f11b44c7e96

Mail.Send Delegated e383f46e-2787-4529-855e-


0e479a3ffac0

Mail.Send.Shared Delegated a367ab51-6b49-43bf-a716-


a1fb06d2a174

MailboxSettings.Read Application 40f97065-369a-49f4-947c-


6a255697ae91

MailboxSettings.Read Delegated 87f447af-9fa4-4c32-9dfa-


4a57a73d18ce

MailboxSettings.ReadWrite Application 6931bccd-447a-43d1-b442-


00a195474933

MailboxSettings.ReadWrite Delegated 818c620a-27a9-40bd-a6a5-


d96f7d610b4b

ManagedTenants.Read.All Delegated dc34164e-6c4a-41a0-be89-


3ae2fbad7cd3

ManagedTenants.ReadWrite.All Delegated b31fa710-c9b3-4d9e-8f5e-


8036eecddab9

Member.Read.Hidden Application 658aa5d8-239f-45c4-aa12-


864f4fc7e490

Member.Read.Hidden Delegated f6a3db3e-f7e8-4ed2-a414-


557c8c9830be

NetworkAccessBranch.Read.All Application 39ae4a24-1ef0-49e8-9d63-


2a66f5c39edd
Permission name Type ID

NetworkAccessBranch.Read.All Delegated 4051c7fc-b429-4804-8d80-


8f1f8c24a6f7

NetworkAccessBranch.ReadWrite.All Application 8137102d-ec16-4191-aaf8-


7aeda8026183

NetworkAccessBranch.ReadWrite.All Delegated b8a36cc2-b810-461a-baa4-


a7281e50bd5c

NetworkAccessPolicy.Read.All Application 8a3d36bf-cb46-4bcc-bec9-


8d92829dab84

NetworkAccessPolicy.Read.All Delegated ba22922b-752c-446f-89d7-


a2d92398fceb

NetworkAccessPolicy.ReadWrite.All Application f0c341be-8348-4989-8e43-


660324294538

NetworkAccessPolicy.ReadWrite.All Delegated b1fbad0f-ef6e-42ed-8676-


bca7fa3e7291

Notes.Create Delegated 9d822255-d64d-4b7a-afdb-


833b9a97ed02

Notes.Read Delegated 371361e4-b9e2-4a3f-8315-


2a301a3b0a3d

Notes.Read.All Application 3aeca27b-ee3a-4c2b-8ded-


80376e2134a4

Notes.Read.All Delegated dfabfca6-ee36-4db2-8208-


7a28381419b3

Notes.ReadWrite Delegated 615e26af-c38a-4150-ae3e-


c3b0d4cb1d6a

Notes.ReadWrite.All Application 0c458cef-11f3-48c2-a568-


c66751c238c0

Notes.ReadWrite.All Delegated 64ac0503-b4fa-45d9-b544-


71a463f05da0

Notes.ReadWrite.CreatedByApp Delegated ed68249d-017c-4df5-9113-


e684c7f8760b

Notifications.ReadWrite.CreatedByApp Delegated 89497502-6e42-46a2-8cb2-


427fd3df970a

offline_access Delegated 7427e0e9-2fba-42fe-b0c0-


848c9e6a8182

OnlineMeetingArtifact.Read.All Application df01ed3b-eb61-4eca-9965-


6b3d789751b2

OnlineMeetingArtifact.Read.All Delegated 110e5abb-a10c-4b59-8b55-


9b4daa4ef743

OnlineMeetingRecording.Read.All Application a4a08342-c95d-476b-b943-


97e100569c8d
Permission name Type ID

OnlineMeetingRecording.Read.All Delegated 190c2bb6-1fdd-4fec-9aa2-


7d571b5e1fe3

OnlineMeetings.Read Delegated 9be106e1-f4e3-4df5-bdff-


e4bc531cbe43

OnlineMeetings.Read.All Application c1684f21-1984-47fa-9d61-


2dc8c296bb70

OnlineMeetings.ReadWrite Delegated a65f2972-a4f8-4f5e-afd7-


69ccb046d5dc

OnlineMeetings.ReadWrite.All Application b8bb2037-6e08-44ac-a4ea-


4674e010e2a4

OnlineMeetingTranscript.Read.All Application a4a80d8d-d283-4bd8-8504-


555ec3870630

OnlineMeetingTranscript.Read.All Delegated 30b87d18-ebb1-45db-97f8-


82ccb1f0190c

OnPremDirectorySynchronization.Read.All Delegated f6609722-4100-44eb-b747-


e6ca0536989d

OnPremDirectorySynchronization.ReadWrite.All Delegated c2d95988-7604-4ba1-aaed-


38a5f82a51c7

OnPremisesPublishingProfiles.ReadWrite.All Application 0b57845e-aa49-4e6f-8109-


ce654fffa618

OnPremisesPublishingProfiles.ReadWrite.All Delegated 8c4d5184-71c2-4bf8-bb9d-


bc3378c9ad42

openid Delegated 37f7f235-527c-4136-accd-


4a02d197296e

Organization.Read.All Application 498476ce-e0fe-48b0-b801-


37ba7e2685c6

Organization.Read.All Delegated 4908d5b9-3fb2-4b1e-9336-


1888b7937185

Organization.ReadWrite.All Application 292d869f-3427-49a8-9dab-


8c70152b74e9

Organization.ReadWrite.All Delegated 46ca0847-7e6b-426e-9775-


ea810a948356

OrgContact.Read.All Application e1a88a34-94c4-4418-be12-


c87b00e26bea

OrgContact.Read.All Delegated 08432d1b-5911-483c-86df-


7980af5cdee0

People.Read Delegated ba47897c-39ec-4d83-8086-


ee8256fa737d

People.Read.All Application b528084d-ad10-4598-8b93-


929746b4d7d6
Permission name Type ID

People.Read.All Delegated b89f9189-71a5-4e70-b041-


9887f0bc7e4a

PeopleSettings.Read.All Application ef02f2e7-e22d-4c77-8614-


8f765683b86e

PeopleSettings.Read.All Delegated ec762c5f-388b-4b16-8693-


ac1efbc611bc

PeopleSettings.ReadWrite.All Application b6890674-9dd5-4e42-bb15-


5af07f541ae1

PeopleSettings.ReadWrite.All Delegated e67e6727-c080-415e-b521-


e3f35d5248e9

Place.Read.All Application 913b9306-0ce1-42b8-9137-


6a7df690a760

Place.Read.All Delegated cb8f45a0-5c2e-4ea1-b803-


84b870a7d7ec

Place.ReadWrite.All Delegated 4c06a06a-098a-4063-868e-


5dfee3827264

Policy.Read.All Application 246dd0d5-5bd0-4def-940b-


0421030a5b68

Policy.Read.All Delegated 572fea84-0151-49b2-9301-


11cb16974376

Policy.Read.ConditionalAccess Application 37730810-e9ba-4e46-b07e-


8ca78d182097

Policy.Read.ConditionalAccess Delegated 633e0fce-8c58-4cfb-9495-


12bbd5a24f7c

Policy.Read.PermissionGrant Application 9e640839-a198-48fb-8b9a-


013fd6f6cbcd

Policy.Read.PermissionGrant Delegated 414de6ea-2d92-462f-b120-


6e2a809a6d01

Policy.ReadWrite.AccessReview Application 77c863fd-06c0-47ce-a7eb-


49773e89d319

Policy.ReadWrite.AccessReview Delegated 4f5bc9c8-ea54-4772-973a-


9ca119cb0409

Policy.ReadWrite.ApplicationConfiguration Application be74164b-cff1-491c-8741-


e671cb536e13

Policy.ReadWrite.ApplicationConfiguration Delegated b27add92-efb2-4f16-84f5-


8108ba77985c

Policy.ReadWrite.AuthenticationFlows Application 25f85f3c-f66c-4205-8cd5-


de92dd7f0cec

Policy.ReadWrite.AuthenticationFlows Delegated edb72de9-4252-4d03-a925-


451deef99db7
Permission name Type ID

Policy.ReadWrite.AuthenticationMethod Application 29c18626-4985-4dcd-85c0-


193eef327366

Policy.ReadWrite.AuthenticationMethod Delegated 7e823077-d88e-468f-a337-


e18f1f0e6c7c

Policy.ReadWrite.Authorization Application fb221be6-99f2-473f-bd32-


01c6a0e9ca3b

Policy.ReadWrite.Authorization Delegated edd3c878-b384-41fd-95ad-


e7407dd775be

Policy.ReadWrite.ConditionalAccess Application 01c0a623-fc9b-48e9-b794-


0756f8e8f067

Policy.ReadWrite.ConditionalAccess Delegated ad902697-1014-4ef5-81ef-


2b4301988e8c

Policy.ReadWrite.ConsentRequest Application 999f8c63-0a38-4f1b-91fd-


ed1947bdd1a9

Policy.ReadWrite.ConsentRequest Delegated 4d135e65-66b8-41a8-9f8b-


081452c91774

Policy.ReadWrite.CrossTenantAccess Application 338163d7-f101-4c92-94ba-


ca46fe52447c

Policy.ReadWrite.CrossTenantAccess Delegated 014b43d0-6ed4-4fc6-84dc-


4b6f7bae7d85

Policy.ReadWrite.DeviceConfiguration Delegated 40b534c3-9552-4550-901b-


23879c90bcf9

Policy.ReadWrite.ExternalIdentities Application 03cc4f92-788e-4ede-b93f-


199424d144a5

Policy.ReadWrite.ExternalIdentities Delegated b5219784-1215-45b5-b3f1-


88fe1081f9c0

Policy.ReadWrite.FeatureRollout Application 2044e4f1-e56c-435b-925c-


44cd8f6ba89a

Policy.ReadWrite.FeatureRollout Delegated 92a38652-f13b-4875-bc77-


6e1dbb63e1b2

Policy.ReadWrite.MobilityManagement Delegated a8ead177-1889-4546-9387-


f25e658e2a79

Policy.ReadWrite.PermissionGrant Application a402ca1c-2696-4531-972d-


6e5ee4aa11ea

Policy.ReadWrite.PermissionGrant Delegated 2672f8bb-fd5e-42e0-85e1-


ec764dd2614e

Policy.ReadWrite.SecurityDefaults Application 1c6e93a6-28e2-4cbb-9f64-


1a46a821124d

Policy.ReadWrite.SecurityDefaults Delegated 0b2a744c-2abf-4f1e-ad7e-


17a087e2be99
Permission name Type ID

Policy.ReadWrite.TrustFramework Application 79a677f7-b79d-40d0-a36a-


3e6f8688dd7a

Policy.ReadWrite.TrustFramework Delegated cefba324-1a70-4a6e-9c1d-


fd670b7ae392

POP.AccessAsUser.All Delegated d7b7f2d9-0f45-4ea1-9d42-


e50810c06991

Presence.Read Delegated 76bc735e-aecd-4a1d-8b4c-


2b915deabb79

Presence.Read.All Delegated 9c7a330d-35b3-4aa1-963d-


cb2b9f927841

Presence.ReadWrite Delegated 8d3c54a7-cf58-4773-bf81-


c0cd6ad522bb

Presence.ReadWrite.All Application 83cded22-8297-4ff6-a7fa-


e97e9545a259

PrintConnector.Read.All Delegated d69c2d6d-4f72-4f99-a6b9-


663e32f8cf68

PrintConnector.ReadWrite.All Delegated 79ef9967-7d59-4213-9c64-


4b10687637d8

Printer.Create Delegated 90c30bed-6fd1-4279-bf39-


714069619721

Printer.FullControl.All Delegated 93dae4bd-43a1-4a23-9a1a-


92957e1d9121

Printer.Read.All Application 9709bb33-4549-49d4-8ed9-


a8f65e45bb0f

Printer.Read.All Delegated 3a736c8a-018e-460a-b60c-


863b2683e8bf

Printer.ReadWrite.All Application f5b3f73d-6247-44df-a74c-


866173fddab0

Printer.ReadWrite.All Delegated 89f66824-725f-4b8f-928e-


e1c5258dc565

PrinterShare.Read.All Delegated ed11134d-2f3f-440d-a2e1-


411efada2502

PrinterShare.ReadBasic.All Delegated 5fa075e9-b951-4165-947b-


c63396ff0a37

PrinterShare.ReadWrite.All Delegated 06ceea37-85e2-40d7-bec3-


91337a46038f

PrintJob.Create Delegated 21f0d9c0-9f13-48b3-94e0-


b6b231c7d320

PrintJob.Manage.All Application 58a52f47-9e36-4b17-9ebe-


ce4ef7f3e6c8
Permission name Type ID

PrintJob.Read Delegated 248f5528-65c0-4c88-8326-


876c7236df5e

PrintJob.Read.All Application ac6f956c-edea-44e4-bd06-


64b1b4b9aec9

PrintJob.Read.All Delegated afdd6933-a0d8-40f7-bd1a-


b5d778e8624b

PrintJob.ReadBasic Delegated 6a71a747-280f-4670-9ca0-


a9cbf882b274

PrintJob.ReadBasic.All Application fbf67eee-e074-4ef7-b965-


ab5ce1c1f689

PrintJob.ReadBasic.All Delegated 04ce8d60-72ce-4867-85cf-


6d82f36922f3

PrintJob.ReadWrite Delegated b81dd597-8abb-4b3f-a07a-


820b0316ed04

PrintJob.ReadWrite.All Application 5114b07b-2898-4de7-a541-


53b0004e2e13

PrintJob.ReadWrite.All Delegated 036b9544-e8c5-46ef-900a-


0646cc42b271

PrintJob.ReadWriteBasic Delegated 6f2d22f2-1cb6-412c-a17c-


3336817eaa82

PrintJob.ReadWriteBasic.All Application 57878358-37f4-4d3a-8c20-


4816e0d457b1

PrintJob.ReadWriteBasic.All Delegated 3a0db2f6-0d2a-4c19-971b-


49109b19ad3d

PrintSettings.Read.All Application b5991872-94cf-4652-9765-


29535087c6d8

PrintSettings.Read.All Delegated 490f32fd-d90f-4dd7-a601-ff6cdc1a3f6c

PrintSettings.ReadWrite.All Delegated 9ccc526a-c51c-4e5c-a1fd-


74726ef50b8f

PrintTaskDefinition.ReadWrite.All Application 456b71a7-0ee0-4588-9842-


c123fcc8f664

PrivilegedAccess.Read.AzureAD Application 4cdc2547-9148-4295-8d11-


be0db1391d6b

PrivilegedAccess.Read.AzureAD Delegated b3a539c9-59cb-4ad5-825a-


041ddbdc2bdb

PrivilegedAccess.Read.AzureADGroup Application 01e37dc9-c035-40bd-b438-


b2879c4870a6

PrivilegedAccess.Read.AzureADGroup Delegated d329c81c-20ad-4772-abf9-


3f6fdb7e5988
Permission name Type ID

PrivilegedAccess.Read.AzureResources Application 5df6fe86-1be0-44eb-b916-


7bd443a71236

PrivilegedAccess.Read.AzureResources Delegated 1d89d70c-dcac-4248-b214-


903c457af83a

PrivilegedAccess.ReadWrite.AzureAD Application 854d9ab1-6657-4ec8-be45-


823027bcd009

PrivilegedAccess.ReadWrite.AzureAD Delegated 3c3c74f5-cdaa-4a97-b7e0-


4e788bfcfb37

PrivilegedAccess.ReadWrite.AzureADGroup Application 2f6817f8-7b12-4f0f-bc18-eeaf60705a9e

PrivilegedAccess.ReadWrite.AzureADGroup Delegated 32531c59-1f32-461f-b8df-


6f8a3b89f73b

PrivilegedAccess.ReadWrite.AzureResources Application 6f9d5abc-2db6-400b-a267-


7de22a40fb87

PrivilegedAccess.ReadWrite.AzureResources Delegated a84a9652-ffd3-496e-a991-


22ba5529156a

PrivilegedAssignmentSchedule.Read.AzureADGroup Application cd4161cb-f098-48f8-a884-


1eda9a42434c

PrivilegedAssignmentSchedule.Read.AzureADGroup Delegated 02a32cc4-7ab5-4b58-879a-


0586e0f7c495

PrivilegedAssignmentSchedule.ReadWrite.AzureADGroup Application 41202f2c-f7ab-45be-b001-


85c9728b9d69

PrivilegedAssignmentSchedule.ReadWrite.AzureADGroup Delegated 06dbc45d-6708-4ef0-a797-


f797ee68bf4b

PrivilegedEligibilitySchedule.Read.AzureADGroup Application edb419d6-7edc-42a3-9345-


509bfdf5d87c

PrivilegedEligibilitySchedule.Read.AzureADGroup Delegated 8f44f93d-ecef-46ae-a9bf-


338508d44d6b

PrivilegedEligibilitySchedule.ReadWrite.AzureADGroup Application 618b6020-bca8-4de6-99f6-


ef445fa4d857

PrivilegedEligibilitySchedule.ReadWrite.AzureADGroup Delegated ba974594-d163-484e-ba39-


c330d5897667

profile Delegated 14dad69e-099b-42c9-810b-


d002981feec1

ProgramControl.Read.All Application eedb7fdd-7539-4345-a38b-


4839e4a84cbd

ProgramControl.Read.All Delegated c492a2e1-2f8f-4caa-b076-


99bbf6e40fe4

ProgramControl.ReadWrite.All Application 60a901ed-09f7-4aa5-a16e-


7dd3d6f9de36
Permission name Type ID

ProgramControl.ReadWrite.All Delegated 50fd364f-9d93-4ae1-b170-


300e87cccf84

QnA.Read.All Application ee49e170-1dd1-4030-b44c-


61ad6e98f743

QnA.Read.All Delegated f73fa04f-b9a5-4df9-8843-


993ce928925e

RecordsManagement.Read.All Application ac3a2b8e-03a3-4da9-9ce0-


cbe28bf1accd

RecordsManagement.Read.All Delegated 07f995eb-fc67-4522-ad66-


2b8ca8ea3efd

RecordsManagement.ReadWrite.All Application eb158f57-df43-4751-8b21-


b8932adb3d34

RecordsManagement.ReadWrite.All Delegated f2833d75-a4e6-40ab-86d4-


6dfe73c97605

Reports.Read.All Application 230c1aed-a721-4c5d-9cb4-


a90514e508ef

Reports.Read.All Delegated 02e97553-ed7b-43d0-ab3c-


f8bace0d040c

ReportSettings.Read.All Application ee353f83-55ef-4b78-82da-


555bfa2b4b95

ReportSettings.Read.All Delegated 84fac5f4-33a9-4100-aa38-


a20c6d29e5e7

ReportSettings.ReadWrite.All Application 2a60023f-3219-47ad-baa4-


40e17cd02a1d

ReportSettings.ReadWrite.All Delegated b955410e-7715-4a88-a940-


dfd551018df3

RoleAssignmentSchedule.Read.Directory Application d5fe8ce8-684c-4c83-a52c-


46e882ce4be1

RoleAssignmentSchedule.Read.Directory Delegated 344a729c-0285-42c6-9014-


f12b9b8d6129

RoleAssignmentSchedule.ReadWrite.Directory Application dd199f4a-f148-40a4-a2ec-


f0069cc799ec

RoleAssignmentSchedule.ReadWrite.Directory Delegated 8c026be3-8e26-4774-9372-


8d5d6f21daff

RoleEligibilitySchedule.Read.Directory Application ff278e11-4a33-4d0c-83d2-


d01dc58929a5

RoleEligibilitySchedule.Read.Directory Delegated eb0788c2-6d4e-4658-8c9e-


c0fb8053f03d

RoleEligibilitySchedule.ReadWrite.Directory Application fee28b28-e1f3-4841-818e-


2704dc62245f
Permission name Type ID

RoleEligibilitySchedule.ReadWrite.Directory Delegated 62ade113-f8e0-4bf9-a6ba-


5acb31db32fd

RoleManagement.Read.All Application c7fbd983-d9aa-4fa7-84b8-


17382c103bc4

RoleManagement.Read.All Delegated 48fec646-b2ba-4019-8681-


8eb31435aded

RoleManagement.Read.CloudPC Application 031a549a-bb80-49b6-8032-


2068448c6a3c

RoleManagement.Read.CloudPC Delegated 9619b88a-8a25-48a7-9571-


d23be0337a79

RoleManagement.Read.Directory Application 483bed4a-2ad3-4361-a73b-


c83ccdbdc53c

RoleManagement.Read.Directory Delegated 741c54c3-0c1e-44a1-818b-


3f97ab4e8c83

RoleManagement.Read.Exchange Application c769435f-f061-4d0b-8ff1-


3d39870e5f85

RoleManagement.Read.Exchange Delegated 3bc15058-7858-4141-b24f-


ae43b4e80b52

RoleManagement.ReadWrite.CloudPC Application 274d0592-d1b6-44bd-af1d-


26d259bcb43a

RoleManagement.ReadWrite.CloudPC Delegated 501d06f8-07b8-4f18-b5c6-


c191a4af7a82

RoleManagement.ReadWrite.Directory Application 9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8

RoleManagement.ReadWrite.Directory Delegated d01b97e9-cbc0-49fe-810a-


750afd5527a3

RoleManagement.ReadWrite.Exchange Application 025d3225-3f02-4882-b4c0-


cd5b541a4e80

RoleManagement.ReadWrite.Exchange Delegated c1499fe0-52b1-4b22-bed2-


7a244e0e879f

RoleManagementAlert.Read.Directory Application ef31918f-2d50-4755-8943-


b8638c0a077e

RoleManagementAlert.Read.Directory Delegated cce71173-f76d-446e-97ff-


efb2d82e11b1

RoleManagementAlert.ReadWrite.Directory Application 11059518-d6a6-4851-98ed-


509268489c4a

RoleManagementAlert.ReadWrite.Directory Delegated 435644c6-a5b1-40bf-8f52-


fe8e5b53e19c

RoleManagementPolicy.Read.Directory Application fdc4c997-9942-4479-bfcb-


75a36d1138df
Permission name Type ID

RoleManagementPolicy.Read.Directory Delegated 3de2cdbe-0ff5-47d5-bdee-


7f45b4749ead

RoleManagementPolicy.ReadWrite.Directory Application 31e08e0a-d3f7-4ca2-ac39-


7343fb83e8ad

RoleManagementPolicy.ReadWrite.Directory Delegated 1ff1be21-34eb-448c-9ac9-


ce1f506b2a68

Schedule.Read.All Application 7b2ebf90-d836-437f-b90d-


7b62722c4456

Schedule.Read.All Delegated fccf6dd8-5706-49fa-811f-


69e2e1b585d0

Schedule.ReadWrite.All Application b7760610-0545-4e8a-9ec3-


cce9e63db01c

Schedule.ReadWrite.All Delegated 63f27281-c9d9-4f29-94dd-


6942f7f1feb0

SearchConfiguration.Read.All Application ada977a5-b8b1-493b-9a91-


66c206d76ecf

SearchConfiguration.Read.All Delegated 7d307522-aa38-4cd0-bd60-


90c6f0ac50bd

SearchConfiguration.ReadWrite.All Application 0e778b85-fefa-466d-9eec-


750569d92122

SearchConfiguration.ReadWrite.All Delegated b1a7d408-cab0-47d2-a2a5-


a74a3733600d

SecurityActions.Read.All Application 5e0edab9-c148-49d0-b423-


ac253e121825

SecurityActions.Read.All Delegated 1638cddf-07a4-4de2-8645-


69c96cacad73

SecurityActions.ReadWrite.All Application f2bf083f-0179-402a-bedb-


b2784de8a49b

SecurityActions.ReadWrite.All Delegated dc38509c-b87d-4da0-bd92-


6bec988bac4a

SecurityAlert.Read.All Application 472e4a4d-bb4a-4026-98d1-


0b0d74cb74a5

SecurityAlert.Read.All Delegated bc257fb8-46b4-4b15-8713-


01e91bfbe4ea

SecurityAlert.ReadWrite.All Application ed4fca05-be46-441f-9803-


1873825f8fdb

SecurityAlert.ReadWrite.All Delegated 471f2a7f-2a42-4d45-a2bf-


594d0838070d

SecurityAnalyzedMessage.Read.All Application b48f7ac2-044d-4281-b02f-


75db744d6f5f
Permission name Type ID

SecurityAnalyzedMessage.Read.All Delegated 53e6783e-b127-4a35-ab3a-


6a52d80a9077

SecurityAnalyzedMessage.ReadWrite.All Application 04c55753-2244-4c25-87fc-


704ab82a4f69

SecurityAnalyzedMessage.ReadWrite.All Delegated 48eb8c83-6e58-46e7-a6d3-


8805822f5940

SecurityEvents.Read.All Application bf394140-e372-4bf9-a898-


299cfc7564e5

SecurityEvents.Read.All Delegated 64733abd-851e-478a-bffb-


e47a14b18235

SecurityEvents.ReadWrite.All Application d903a879-88e0-4c09-b0c9-


82f6a1333f84

SecurityEvents.ReadWrite.All Delegated 6aedf524-7e1c-45a7-bd76-


ded8cab8d0fc

SecurityIncident.Read.All Application 45cc0394-e837-488b-a098-


1918f48d186c

SecurityIncident.Read.All Delegated b9abcc4f-94fc-4457-9141-


d20ce80ec952

SecurityIncident.ReadWrite.All Application 34bf0e97-1971-4929-b999-


9e2442d941d7

SecurityIncident.ReadWrite.All Delegated 128ca929-1a19-45e6-a3b8-


435ec44a36ba

ServiceHealth.Read.All Application 79c261e0-fe76-4144-aad5-


bdc68fbe4037

ServiceHealth.Read.All Delegated 55896846-df78-47a7-aa94-


8d3d4442ca7f

ServiceMessage.Read.All Application 1b620472-6534-4fe6-9df2-


4680e8aa28ec

ServiceMessage.Read.All Delegated eda39fa6-f8cf-4c3c-a909-


432c683e4c9b

ServiceMessageViewpoint.Write Delegated 636e1b0b-1cc2-4b1c-9aa9-


4eeed9b9761b

ServicePrincipalEndpoint.Read.All Application 5256681e-b7f6-40c0-8447-


2d9db68797a0

ServicePrincipalEndpoint.Read.All Delegated 9f9ce928-e038-4e3b-8faf-


7b59049a8ddc

ServicePrincipalEndpoint.ReadWrite.All Application 89c8469c-83ad-45f7-8ff2-


6e3d4285709e

ServicePrincipalEndpoint.ReadWrite.All Delegated 7297d82c-9546-4aed-91df-


3d4f0a9b3ff0
Permission name Type ID

SharePointTenantSettings.Read.All Application 83d4163d-a2d8-4d3b-9695-


4ae3ca98f888

SharePointTenantSettings.Read.All Delegated 2ef70e10-5bfd-4ede-a5f6-


67720500b258

SharePointTenantSettings.ReadWrite.All Application 19b94e34-907c-4f43-bde9-


38b1909ed408

SharePointTenantSettings.ReadWrite.All Delegated aa07f155-3612-49b8-a147-


6c590df35536

ShortNotes.Read Delegated 50f66e47-eb56-45b7-aaa2-


75057d9afe08

ShortNotes.Read.All Application 0c7d31ec-31ca-4f58-b6ec-


9950b6b0de69

ShortNotes.ReadWrite Delegated 328438b7-4c01-4c07-a840-


e625a749bb89

ShortNotes.ReadWrite.All Application 842c284c-763d-4a97-838d-


79787d129bab

Sites.FullControl.All Application a82116e5-55eb-4c41-a434-


62fe8a61c773

Sites.FullControl.All Delegated 5a54b8b3-347c-476d-8f8e-


42d5c7424d29

Sites.Manage.All Application 0c0bf378-bf22-4481-8f81-


9e89a9b4960a

Sites.Manage.All Delegated 65e50fdc-43b7-4915-933e-


e8138f11f40a

Sites.Read.All Application 332a536c-c7ef-4017-ab91-


336970924f0d

Sites.Read.All Delegated 205e70e5-aba6-4c52-a976-


6d2d46c48043

Sites.ReadWrite.All Application 9492366f-7969-46a4-8d15-


ed1a20078fff

Sites.ReadWrite.All Delegated 89fe6a52-be36-487e-b7d8-


d061c450a026

Sites.Selected Application 883ea226-0bf2-4a8f-9f9d-


92c9162a727d

SMTP.Send Delegated 258f6531-6087-4cc4-bb90-


092c5fb3ed3f

SubjectRightsRequest.Read.All Application ee1460f0-368b-4153-870a-


4e1ca7e72c42

SubjectRightsRequest.Read.All Delegated 9c3af74c-fd0f-4db4-b17a-


71939e2a9d77
Permission name Type ID

SubjectRightsRequest.ReadWrite.All Application 8387eaa4-1a3c-41f5-b261-


f888138e6041

SubjectRightsRequest.ReadWrite.All Delegated 2b8fcc74-bce1-4ae3-a0e8-


60c53739299d

Subscription.Read.All Delegated 5f88184c-80bb-4d52-9ff2-


757288b2e9b7

Synchronization.Read.All Application 5ba43d2f-fa88-4db2-bd1c-


a67c5f0fb1ce

Synchronization.Read.All Delegated 7aa02aeb-824f-4fbe-a3f7-


611f751f5b55

Synchronization.ReadWrite.All Application 9b50c33d-700f-43b1-b2eb-


87e89b703581

Synchronization.ReadWrite.All Delegated 7bb27fa3-ea8f-4d67-a916-


87715b6188bd

Tasks.Read Delegated f45671fb-e0fe-4b4b-be20-


3d3ce43f1bcb

Tasks.Read.All Application f10e1f91-74ed-437f-a6fd-


d6ae88e26c1f

Tasks.Read.Shared Delegated 88d21fd4-8e5a-4c32-b5e2-


4a1c95f34f72

Tasks.ReadWrite Delegated 2219042f-cab5-40cc-b0d2-


16b1540b4c5f

Tasks.ReadWrite.All Application 44e666d1-d276-445b-a5fc-


8815eeb81d55

Tasks.ReadWrite.Shared Delegated c5ddf11b-c114-4886-8558-


8a4e557cd52b

Team.Create Application 23fc2474-f741-46ce-8465-


674744c5c361

Team.Create Delegated 7825d5d6-6049-4ce7-bdf6-


3b8d53f4bcd0

Team.ReadBasic.All Application 2280dda6-0bfd-44ee-a2f4-


cb867cfc4c1e

Team.ReadBasic.All Delegated 485be79e-c497-4b35-9400-


0e3fa7f2a5d4

TeamMember.Read.All Application 660b7406-55f1-41ca-a0ed-


0b035e182f3e

TeamMember.Read.All Delegated 2497278c-d82d-46a2-b1ce-


39d4cdde5570

TeamMember.ReadWrite.All Application 0121dc95-1b9f-4aed-8bac-


58c5ac466691
Permission name Type ID

TeamMember.ReadWrite.All Delegated 4a06efd2-f825-4e34-813e-


82a57b03d1ee

TeamMember.ReadWriteNonOwnerRole.All Application 4437522e-9a86-4a41-a7da-


e380edd4a97d

TeamMember.ReadWriteNonOwnerRole.All Delegated 2104a4db-3a2f-4ea0-9dba-


143d457dc666

TeamsActivity.Read Delegated 0e755559-83fb-4b44-91d0-


4cc721b9323e

TeamsActivity.Read.All Application 70dec828-f620-4914-aa83-


a29117306807

TeamsActivity.Send Application a267235f-af13-44dc-8385-


c1dc93023186

TeamsActivity.Send Delegated 7ab1d787-bae7-4d5d-8db6-


37ea32df9186

TeamsAppInstallation.ReadForChat Delegated bf3fbf03-f35f-4e93-963e-


47e4d874c37a

TeamsAppInstallation.ReadForChat.All Application cc7e7635-2586-41d6-adaa-


a8d3bcad5ee5

TeamsAppInstallation.ReadForTeam Delegated 5248dcb1-f83b-4ec3-9f4d-


a4428a961a72

TeamsAppInstallation.ReadForTeam.All Application 1f615aea-6bf9-4b05-84bd-


46388e138537

TeamsAppInstallation.ReadForUser Delegated c395395c-ff9a-4dba-bc1f-


8372ba9dca84

TeamsAppInstallation.ReadForUser.All Application 9ce09611-f4f7-4abd-a629-


a05450422a97

TeamsAppInstallation.ReadWriteAndConsentForChat Delegated e1408a66-8f82-451b-a2f3-


3c3e38f7413f

TeamsAppInstallation.ReadWriteAndConsentForChat.All Application 6e74eff9-4a21-45d6-bc03-


3a20f61f8281

TeamsAppInstallation.ReadWriteAndConsentForTeam Delegated 946349d5-2a9d-4535-abc0-


7beeacaedd1d

TeamsAppInstallation.ReadWriteAndConsentForTeam.All Application b0c13be0-8e20-4bc5-8c55-


963c23a39ce9

TeamsAppInstallation.ReadWriteAndConsentSelfForChat Delegated a0e0e18b-8fb2-458f-8130-


da2d7cab9c75

TeamsAppInstallation.ReadWriteAndConsentSelfForChat.All Application ba1ba90b-2d8f-487e-9f16-


80728d85bb5c

TeamsAppInstallation.ReadWriteAndConsentSelfForTeam Delegated 4a6bbf29-a0e1-4a4d-a7d1-


cef17f772975
Permission name Type ID

TeamsAppInstallation.ReadWriteAndConsentSelfForTeam.All Application 1e4be56c-312e-42b8-a2c9-


009600d732c0

TeamsAppInstallation.ReadWriteForChat Delegated aa85bf13-d771-4d5d-a9e6-


bca04ce44edf

TeamsAppInstallation.ReadWriteForChat.All Application 9e19bae1-2623-4c4f-ab6e-


2664615ff9a0

TeamsAppInstallation.ReadWriteForTeam Delegated 2e25a044-2580-450d-8859-


42eeb6e996c0

TeamsAppInstallation.ReadWriteForTeam.All Application 5dad17ba-f6cc-4954-a5a2-


a0dcc95154f0

TeamsAppInstallation.ReadWriteForUser Delegated 093f8818-d05f-49b8-95bc-


9d2a73e9a43c

TeamsAppInstallation.ReadWriteForUser.All Application 74ef0291-ca83-4d02-8c7e-


d2391e6a444f

TeamsAppInstallation.ReadWriteSelfForChat Delegated 0ce33576-30e8-43b7-99e5-


62f8569a4002

TeamsAppInstallation.ReadWriteSelfForChat.All Application 73a45059-f39c-4baf-9182-


4954ac0e55cf

TeamsAppInstallation.ReadWriteSelfForTeam Delegated 0f4595f7-64b1-4e13-81bc-


11a249df07a9

TeamsAppInstallation.ReadWriteSelfForTeam.All Application 9f67436c-5415-4e7f-8ac1-


3014a7132630

TeamsAppInstallation.ReadWriteSelfForUser Delegated 207e0cb1-3ce7-4922-b991-


5a760c346ebc

TeamsAppInstallation.ReadWriteSelfForUser.All Application 908de74d-f8b2-4d6b-a9ed-


2a17b3b78179

TeamSettings.Read.All Application 242607bd-1d2c-432c-82eb-


bdb27baa23ab

TeamSettings.Read.All Delegated 48638b3c-ad68-4383-8ac4-


e6880ee6ca57

TeamSettings.ReadWrite.All Application bdd80a03-d9bc-451d-b7c4-


ce7c63fe3c8f

TeamSettings.ReadWrite.All Delegated 39d65650-9d3e-4223-80db-


a335590d027e

TeamsTab.Create Application 49981c42-fd7b-4530-be03-


e77b21aed25e

TeamsTab.Create Delegated a9ff19c2-f369-4a95-9a25-


ba9d460efc8e

TeamsTab.Read.All Application 46890524-499a-4bb2-ad64-


1476b4f3e1cf
Permission name Type ID

TeamsTab.Read.All Delegated 59dacb05-e88d-4c13-a684-


59f1afc8cc98

TeamsTab.ReadWrite.All Application a96d855f-016b-47d7-b51c-


1218a98d791c

TeamsTab.ReadWrite.All Delegated b98bfd41-87c6-45cc-b104-


e2de4f0dafb9

TeamsTab.ReadWriteForChat Delegated ee928332-e9c2-4747-b4a0-


f8c164b68de6

TeamsTab.ReadWriteForChat.All Application fd9ce730-a250-40dc-bd44-


8dc8d20f39ea

TeamsTab.ReadWriteForTeam Delegated c975dd04-a06e-4fbb-9704-


62daad77bb49

TeamsTab.ReadWriteForTeam.All Application 6163d4f4-fbf8-43da-a7b4-


060fe85ed148

TeamsTab.ReadWriteForUser Delegated c37c9b61-7762-4bff-a156-


afc0005847a0

TeamsTab.ReadWriteForUser.All Application 425b4b59-d5af-45c8-832f-


bb0b7402348a

TeamsTab.ReadWriteSelfForChat Delegated 0c219d04-3abf-47f7-912d-


5cca239e90e6

TeamsTab.ReadWriteSelfForChat.All Application 9f62e4a2-a2d6-4350-b28b-


d244728c4f86

TeamsTab.ReadWriteSelfForTeam Delegated f266662f-120a-4314-b26a-


99b08617c7ef

TeamsTab.ReadWriteSelfForTeam.All Application 91c32b81-0ef0-453f-a5c7-


4ce2e562f449

TeamsTab.ReadWriteSelfForUser Delegated 395dfec1-a0b9-465f-a783-


8250a430cb8c

TeamsTab.ReadWriteSelfForUser.All Application 3c42dec6-49e8-4a0a-b469-


36cff0d9da93

TeamTemplates.Read Delegated cd87405c-5792-4f15-92f7-


debc0db6d1d6

TeamTemplates.Read.All Application 6323133e-1f6e-46d4-9372-


ac33a0870636

Teamwork.Migrate.All Application dfb0dd15-61de-45b2-be36-


d6a69fba3c79

TeamworkAppSettings.Read.All Application 475ebe88-f071-4bd7-af2b-


642952bd4986

TeamworkAppSettings.Read.All Delegated 44e060c4-bbdc-4256-a0b9-


dcc0396db368
Permission name Type ID

TeamworkAppSettings.ReadWrite.All Application ab5b445e-8f10-45f4-9c79-


dd3f8062cc4e

TeamworkAppSettings.ReadWrite.All Delegated 87c556f0-2bd9-4eed-bd74-


5dd8af6eaf7e

TeamworkDevice.Read.All Application 0591bafd-7c1c-4c30-a2a5-


2b9aacb1dfe8

TeamworkDevice.Read.All Delegated b659488b-9d28-4208-b2be-


1c6652b3c970

TeamworkDevice.ReadWrite.All Application 79c02f5b-bd4f-4713-bc2c-


a8a4a66e127b

TeamworkDevice.ReadWrite.All Delegated ddd97ecb-5c31-43db-a235-


0ee20e635c40

TeamworkTag.Read Delegated 57587d0b-8399-45be-b207-


8050cec54575

TeamworkTag.Read.All Application b74fd6c4-4bde-488e-9695-


eeb100e4907f

TeamworkTag.ReadWrite Delegated 539dabd7-b5b6-4117-b164-


d60cd15a8671

TeamworkTag.ReadWrite.All Application a3371ca5-911d-46d6-901c-


42c8c7a937d8

TermStore.Read.All Application ea047cc2-df29-4f3e-83a3-


205de61501ca

TermStore.Read.All Delegated 297f747b-0005-475b-8fef-


c890f5152b38

TermStore.ReadWrite.All Application f12eb8d6-28e3-46e6-b2c0-


b7e4dc69fc95

TermStore.ReadWrite.All Delegated 6c37c71d-f50f-4bff-8fd3-


8a41da390140

ThreatAssessment.Read.All Application f8f035bb-2cce-47fb-8bf5-


7baf3ecbee48

ThreatAssessment.ReadWrite.All Delegated cac97e40-6730-457d-ad8d-


4852fddab7ad

ThreatHunting.Read.All Application dd98c7f5-2d42-42d3-a0e4-


633161547251

ThreatHunting.Read.All Delegated b152eca8-ea73-4a48-8c98-


1a6742673d99

ThreatIndicators.Read.All Application 197ee4e9-b993-4066-898f-


d6aecc55125b

ThreatIndicators.Read.All Delegated 9cc427b4-2004-41c5-aa22-


757b755e9796
Permission name Type ID

ThreatIndicators.ReadWrite.OwnedBy Application 21792b6c-c986-4ffc-85de-


df9da54b52fa

ThreatIndicators.ReadWrite.OwnedBy Delegated 91e7d36d-022a-490f-a748-


f8e011357b42

ThreatIntelligence.Read.All Application e0b77adb-e790-44a3-b0a0-


257d06303687

ThreatIntelligence.Read.All Delegated f266d9c0-ccb9-4fb8-a228-


01ac0d8d6627

ThreatSubmission.Read Delegated fd5353c6-26dd-449f-a565-


c4e16b9fce78

ThreatSubmission.Read.All Application 86632667-cd15-4845-ad89-


48a88e8412e1

ThreatSubmission.Read.All Delegated 7083913a-4966-44b6-9886-


c5822a5fd910

ThreatSubmission.ReadWrite Delegated 68a3156e-46c9-443c-b85c-


921397f082b5

ThreatSubmission.ReadWrite.All Application d72bdbf4-a59b-405c-8b04-


5995895819ac

ThreatSubmission.ReadWrite.All Delegated 8458e264-4eb9-4922-abe9-


768d58f13c7f

ThreatSubmissionPolicy.ReadWrite.All Application 926a6798-b100-4a20-a22f-


a4918f13951d

ThreatSubmissionPolicy.ReadWrite.All Delegated 059e5840-5353-4c68-b1da-


666a033fc5e8

TrustFrameworkKeySet.Read.All Application fff194f1-7dce-4428-8301-


1badb5518201

TrustFrameworkKeySet.Read.All Delegated 7ad34336-f5b1-44ce-8682-


31d7dfcd9ab9

TrustFrameworkKeySet.ReadWrite.All Application 4a771c9a-1cf2-4609-b88e-


3d3e02d539cd

TrustFrameworkKeySet.ReadWrite.All Delegated 39244520-1e7d-4b4a-aee0-


57c65826e427

UnifiedGroupMember.Read.AsGuest Delegated 73e75199-7c3e-41bb-9357-


167164dbb415

User.EnableDisableAccount.All Application 3011c876-62b7-4ada-afa2-


506cbbecc68c

User.EnableDisableAccount.All Delegated f92e74e7-2563-467f-9dd0-


902688cb5863

User.Export.All Application 405a51b5-8d8d-430b-9842-


8be4b0e9f324
Permission name Type ID

User.Export.All Delegated 405a51b5-8d8d-430b-9842-


8be4b0e9f324

User.Invite.All Application 09850681-111b-4a89-9bed-


3f2cae46d706

User.Invite.All Delegated 63dd7cd9-b489-4adf-a28c-


ac38b9a0f962

User.ManageIdentities.All Application c529cfca-c91b-489c-af2b-


d92990b66ce6

User.ManageIdentities.All Delegated 637d7bec-b31e-4deb-acc9-


24275642a2c9

User.Read Delegated e1fe6dd8-ba31-4d61-89e7-


88639da4683d

User.Read.All Application df021288-bdef-4463-88db-


98f22de89214

User.Read.All Delegated a154be20-db9c-4678-8ab7-


66f6cc099a59

User.ReadBasic.All Delegated b340eb25-3456-403f-be2f-


af7a0d370277

User.ReadWrite Delegated b4e74841-8e56-480b-be8b-


910348b18b4c

User.ReadWrite.All Application 741f803b-c850-494e-b5df-


cde7c675a1ca

User.ReadWrite.All Delegated 204e0828-b5ca-4ad8-b9f3-


f32a958e7cc4

UserActivity.ReadWrite.CreatedByApp Delegated 47607519-5fb1-47d9-99c7-


da4b48f369b1

UserAuthenticationMethod.Read Delegated 1f6b61c5-2f65-4135-9c9f-


31c0f8d32b52

UserAuthenticationMethod.Read.All Application 38d9df27-64da-44fd-b7c5-


a6fbac20248f

UserAuthenticationMethod.Read.All Delegated aec28ec7-4d02-4e8c-b864-


50163aea77eb

UserAuthenticationMethod.ReadWrite Delegated 48971fc1-70d7-4245-af77-


0beb29b53ee2

UserAuthenticationMethod.ReadWrite.All Application 50483e42-d915-4231-9639-


7fdb7fd190e5

UserAuthenticationMethod.ReadWrite.All Delegated b7887744-6746-4312-813d-


72daeaee7e2d

User-LifeCycleInfo.Read.All Application 8556a004-db57-4d7a-8b82-


97a13428e96f
Permission name Type ID

User-LifeCycleInfo.Read.All Delegated ed8d2a04-0374-41f1-aefe-


da8ac87ccc87

User-LifeCycleInfo.ReadWrite.All Application 925f1248-0f97-47b9-8ec8-


538c54e01325

User-LifeCycleInfo.ReadWrite.All Delegated 7ee7473e-bd4b-4c9f-987c-


bd58481f5fa2

UserNotification.ReadWrite.CreatedByApp Application 4e774092-a092-48d1-90bd-


baad67c7eb47

UserNotification.ReadWrite.CreatedByApp Delegated 26e2f3e8-b2a1-47fc-9620-


89bb5b042024

UserShiftPreferences.Read.All Application de023814-96df-4f53-9376-


1e2891ef5a18

UserShiftPreferences.ReadWrite.All Application d1eec298-80f3-49b0-9efb-


d90e224798ac

UserTimelineActivity.Write.CreatedByApp Delegated 367492fc-594d-4972-a9b5-


0d58c622c91c

VirtualAppointment.Read Delegated 27470298-d3b8-4b9c-aad4-


6334312a3eac

VirtualAppointment.Read.All Application d4f67ec2-59b5-4bdc-b4af-


d78f6f9c1954

VirtualAppointment.ReadWrite Delegated 2ccc2926-a528-4b17-b8bb-


860eed29d64c

VirtualAppointment.ReadWrite.All Application bf46a256-f47d-448f-ab78-f226fff08d40

VirtualEvent.Read Delegated 6b616635-ae58-433a-a918-


8c45e4f304dc

VirtualEvent.Read.All Application 1dccb351-c4e4-4e09-a8d1-


7a9ecbf027cc

WindowsUpdates.ReadWrite.All Application 7dd1be58-6e76-4401-bf8d-


31d1e8180d5b

WindowsUpdates.ReadWrite.All Delegated 11776c0c-6138-4db3-a668-


ee621bea2555

WorkforceIntegration.Read.All Delegated f1ccd5a7-6383-466a-8db8-


1a656f7d06fa

WorkforceIntegration.ReadWrite.All Application 202bf709-e8e6-478e-bcfd-


5d63c50b68e3

WorkforceIntegration.ReadWrite.All Delegated 08c4b377-0d23-4a8b-be2a-


23c1c1d88545
Azure AD built-in roles
Article • 04/28/2023

In Azure Active Directory (Azure AD), if another administrator or non-administrator


needs to manage Azure AD resources, you assign them an Azure AD role that provides
the permissions they need. For example, you can assign roles to allow adding or
changing users, resetting user passwords, managing user licenses, or managing domain
names.

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

Application Administrator Can create and manage all 9b895d92-2cd3-44c7-9d02-


aspects of app registrations a6ac2d5ea5c3
and enterprise apps.

Application Developer Can create application cf1c38e5-3621-4004-a7cb-


registrations independent of 879624dced7c
the 'Users can register
applications' setting.

Attack Payload Author Can create attack payloads 9c6df0f2-1e7c-4dc3-b195-


that an administrator can 66dfbd24aa8f
initiate later.

Attack Simulation Can create and manage all c430b396-e693-46cc-96f3-


Administrator aspects of attack simulation db01bf8bb62a
campaigns.

Attribute Assignment Assign custom security 58a13ea3-c632-46ae-9ee0-


Administrator attribute keys and values to 9c0d43cd7f3d
supported Azure AD objects.

Attribute Assignment Reader Read custom security attribute ffd52fa5-98dc-465c-991d-


keys and values for supported fc073eb59f8f
Azure AD objects.
Role Description Template ID

Attribute Definition Define and manage the 8424c6f0-a189-499e-bbd0-


Administrator definition of custom security 26c1753c96d4
attributes.

Attribute Definition Reader Read the definition of custom 1d336d2c-4ae8-42ef-9711-


security attributes. b3604ce3fc2c

Authentication Administrator Can access to view, set and c4e39bd9-1100-46d3-8c65-


reset authentication method fb160da0071f
information for any non-admin
user.

Authentication Policy Can create and manage the 0526716b-113d-4c15-b2c8-


Administrator authentication methods policy, 68e3c22b9f80
tenant-wide MFA settings,
password protection policy,
and verifiable credentials.

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.

Azure DevOps Administrator Can manage Azure DevOps e3973bdf-4987-49ae-837a-


policies and settings. ba8e231c7286

Azure Information Protection Can manage all aspects of the 7495fdc4-34c4-4d15-a289-


Administrator Azure Information Protection 98788ce399fd
product.

B2C IEF Keyset Administrator Can manage secrets for aaf43236-0c0d-4d5f-883a-


federation and encryption in 6955382ac081
the Identity Experience
Framework (IEF).

B2C IEF Policy Administrator Can create and manage trust 3edaf663-341e-4475-9f94-
framework policies in the 5c398ef6c070
Identity Experience Framework
(IEF).

Billing Administrator Can perform common billing b0f54661-2d74-4c50-afa3-


related tasks like updating 1ec803f12efe
payment information.

Cloud App Security Can manage all aspects of the 892c5842-a9a6-463a-8041-


Administrator Defender for Cloud Apps 72aa08ca3cf6
product.
Role Description Template ID

Cloud Application Can create and manage all 158c047a-c907-4556-b7ef-


Administrator aspects of app registrations 446551a6b5f7
and enterprise apps except
App Proxy.

Cloud Device Administrator Limited access to manage 7698a772-787b-4ac8-901f-


devices in Azure AD. 60d6b08affd2

Compliance Administrator Can read and manage 17315797-102d-40b4-93e0-


compliance configuration and 432062caca18
reports in Azure AD and
Microsoft 365.

Compliance Data Creates and manages e6d1a23a-da11-4be4-9570-


Administrator compliance content. befc86d067a7

Conditional Access Can manage Conditional b1be1c3e-b65d-4f19-8427-


Administrator Access capabilities. f6fa0d97feb9

Customer LockBox Access Can approve Microsoft 5c4f9dcd-47dc-4cf7-8c9a-


Approver support requests to access 9e4207cbfc91
customer organizational data.

Desktop Analytics Can access and manage 38a96431-2bdf-4b4c-8b6e-


Administrator Desktop management tools 5d3d8abac1a4
and services.

Directory Readers Can read basic directory 88d8e3e3-8f55-4a1e-953a-


information. Commonly used 9b9898b8876b
to grant directory read access
to applications and guests.

Directory Synchronization Only used by Azure AD d29b2b05-8046-44ba-8758-


Accounts Connect service. 1e26182fcf32

Directory Writers Can read and write basic 9360feb5-f418-4baa-8175-


directory information. For e2a00bac4301
granting access to
applications, not intended for
users.

Domain Name Administrator Can manage domain names in 8329153b-31d0-4727-b945-


cloud and on-premises. 745eb3bc5f31

Dynamics 365 Administrator Can manage all aspects of the 44367163-eba1-44c3-98af-


Dynamics 365 product. f5787879f96a

Edge Administrator Manage all aspects of 3f1acade-1e04-4fbc-9b69-


Microsoft Edge. f0302cd84aef
Role Description Template ID

Exchange Administrator Can manage all aspects of the 29232cdf-9323-42fd-ade2-


Exchange product. 1d097af3e4de

Exchange Recipient Can create or update 31392ffb-586c-42d1-9346-


Administrator Exchange Online recipients e59415a2cc4e
within the Exchange Online
organization.

External ID User Flow Can create and manage all 6e591065-9bad-43ed-90f3-


Administrator aspects of user flows. e9424366d2f0

External ID User Flow Attribute Can create and manage the 0f971eea-41eb-4569-a71e-
Administrator attribute schema available to 57bb8a3eff1e
all user flows.

External Identity Provider Can configure identity be2f45a1-457d-42af-a067-


Administrator providers for use in direct 6ec1fa63bc45
federation.

Global Administrator Can manage all aspects of 62e90394-69f5-4237-9190-


Azure AD and Microsoft 012177145e10
services that use Azure AD
identities.

Global Reader Can read everything that a f2ef992c-3afb-46b9-b7cf-


Global Administrator can, but a126ee74c451
not update anything.

Groups Administrator Members of this role can fdd7a751-b60b-444a-984c-


create/manage groups, 02652fe8fa1c
create/manage groups
settings like naming and
expiration policies, and view
groups activity and audit
reports.

Guest Inviter Can invite guest users 95e79109-95c0-4d8e-aee3-


independent of the 'members d01accf2d47b
can invite guests' setting.

Helpdesk Administrator Can reset passwords for non- 729827e3-9c14-49f7-bb1b-


administrators and Helpdesk 9608f156bbb8
Administrators.
Role Description Template ID

Hybrid Identity Administrator Can manage AD to Azure AD 8ac3fc64-6eca-42ea-9e69-


cloud provisioning, Azure AD 59f4c7b60eb2
Connect, Pass-through
Authentication (PTA), Password
hash synchronization (PHS),
Seamless Single sign-on
(Seamless SSO), and federation
settings.

Identity Governance Manage access using Azure 45d8d3c5-c802-45c6-b32a-


Administrator AD for identity governance 1d70b5e1e86e
scenarios.

Insights Administrator Has administrative access in eb1f4a8d-243a-41f0-9fbd-


the Microsoft 365 Insights app. c7cdf6c5ef7c

Insights Analyst Access the analytical 25df335f-86eb-4119-b717-


capabilities in Microsoft Viva 0ff02de207e9
Insights and run custom
queries.

Insights Business Leader Can view and share 31e939ad-9672-4796-9c2e-


dashboards and insights via 873181342d2d
the Microsoft 365 Insights app.

Intune Administrator Can manage all aspects of the 3a2c62db-5318-420d-8d74-


Intune product. 23affee5d9d5

Kaizala Administrator Can manage settings for 74ef975b-6605-40af-a5d2-


Microsoft Kaizala. b9539d836353

Knowledge Administrator Can configure knowledge, b5a8dcf3-09d5-43a9-a639-


learning, and other intelligent 8e29ef291470
features.

Knowledge Manager Can organize, create, manage, 744ec460-397e-42ad-a462-


and promote topics and 8b3f9747a02c
knowledge.

License Administrator Can manage product licenses 4d6ac14f-3453-41d0-bef9-


on users and groups. a3e0c569773a

Lifecycle Workflows Create and manage all aspects 59d46f88-662b-457b-bceb-


Administrator of workflows and tasks 5c3809e5908f
associated with Lifecycle
Workflows in Azure AD.
Role Description Template ID

Message Center Privacy Can read security messages ac16e43d-7b2d-40e0-ac05-


Reader and updates in Office 365 243ff356ab5b
Message Center only.

Message Center Reader Can read messages and 790c1fb9-7f7d-4f88-86a1-


updates for their organization ef1f95c05c1b
in Office 365 Message Center
only.

Microsoft Hardware Warranty Create and manage all aspects 1501b917-7653-4ff9-a4b5-


Administrator warranty claims and 203eaf33784f
entitlements for Microsoft
manufactured hardware, like
Surface and HoloLens.

Microsoft Hardware Warranty Create and read warranty 281fe777-fb20-4fbb-b7a3-


Specialist claims for Microsoft ccebce5b0d96
manufactured hardware, like
Surface and HoloLens.

Modern Commerce User Can manage commercial d24aef57-1500-4070-84db-


purchases for a company, 2666f29cf966
department or team.

Network Administrator Can manage network locations d37c8bed-0711-4417-ba38-


and review enterprise network b4abe66ce4c2
design insights for Microsoft
365 Software as a Service
applications.

Office Apps Administrator Can manage Office apps cloud 2b745bdf-0803-4d80-aa65-


services, including policy and 822c4493daac
settings management, and
manage the ability to select,
unselect and publish 'what's
new' feature content to end-
user's devices.

Organizational Messages Write, publish, manage, and 507f53e4-4e52-4077-abd3-


Writer review the organizational d2e1558b6ea2
messages for end-users
through Microsoft product
surfaces.

Partner Tier1 Support Do not use - not intended for 4ba39ca4-527c-499a-b93d-


general use. d9b492c50246

Partner Tier2 Support Do not use - not intended for e00e864a-17c5-4a4b-9c06-


general use. f5b95a8d5bd8
Role Description Template ID

Password Administrator Can reset passwords for non- 966707d0-3269-4727-9be2-


administrators and Password 8c3a10f19b9d
Administrators.

Permissions Management Manage all aspects of Entra af78dc32-cf4d-46f9-ba4e-


Administrator Permissions Management. 4428526346b5

Power BI Administrator Can manage all aspects of the a9ea8996-122f-4c74-9520-


Power BI product. 8edcd192826c

Power Platform Administrator Can create and manage all 11648597-926c-4cf3-9c36-


aspects of Microsoft Dynamics bcebb0ba8dcc
365, Power Apps and Power
Automate.

Printer Administrator Can manage all aspects of 644ef478-e28f-4e28-b9dc-


printers and printer 3fdde9aa0b1f
connectors.

Printer Technician Can register and unregister e8cef6f1-e4bd-4ea8-bc07-


printers and update printer 4b8d950f4477
status.

Privileged Authentication Can access to view, set and 7be44c8a-adaf-4e2a-84d6-


Administrator reset authentication method ab2649e08a13
information for any user
(admin or non-admin).

Privileged Role Administrator Can manage role assignments e8611ab8-c189-46e8-94e1-


in Azure AD, and all aspects of 60213ab1f814
Privileged Identity
Management.

Reports Reader Can read sign-in and audit 4a5d8f65-41da-4de4-8968-


reports. e035b65339cf

Search Administrator Can create and manage all 0964bb5e-9bdb-4d7b-ac29-


aspects of Microsoft Search 58e794862a40
settings.

Search Editor Can create and manage the 8835291a-918c-4fd7-a9ce-


editorial content such as faa49f0cf7d9
bookmarks, Q and As,
locations, floorplan.

Security Administrator Can read security information 194ae4cb-b126-40b2-bd5b-


and reports, and manage 6091b380977d
configuration in Azure AD and
Office 365.
Role Description Template ID

Security Operator Creates and manages security 5f2222b1-57c3-48ba-8ad5-


events. d4759f1fde6f

Security Reader Can read security information 5d6b6bb7-de71-4623-b4af-


and reports in Azure AD and 96380a352509
Office 365.

Service Support Administrator Can read service health f023fd81-a637-4b56-95fd-


information and manage 791ac0226033
support tickets.

SharePoint Administrator Can manage all aspects of the f28a1f50-f6e7-4571-818b-


SharePoint service. 6a12f2af6b6c

Skype for Business Can manage all aspects of the 75941009-915a-4869-abe7-


Administrator Skype for Business product. 691bff18279e

Teams Administrator Can manage the Microsoft 69091246-20e8-4a56-aa4d-


Teams service. 066075b2a7a8

Teams Communications Can manage calling and baf37b3a-610e-45da-9e62-


Administrator meetings features within the d9d1e5e8914b
Microsoft Teams service.

Teams Communications Can troubleshoot f70938a0-fc10-4177-9e90-


Support Engineer communications issues within 2178f8765737
Teams using advanced tools.

Teams Communications Can troubleshoot fcf91098-03e3-41a9-b5ba-


Support Specialist communications issues within 6f0ec8188a12
Teams using basic tools.

Teams Devices Administrator Can perform management 3d762c5a-1b6c-493f-843e-


related tasks on Teams 55a3b42923d4
certified devices.

Tenant Creator Create new Azure AD or Azure 112ca1a2-15ad-4102-995e-


AD B2C tenants. 45b0bc479a6a

Usage Summary Reports Can see only tenant level 75934031-6c7e-415a-99d7-


Reader aggregates in Microsoft 365 48dbd49e875e
Usage Analytics and
Productivity Score.

User Administrator Can manage all aspects of fe930be7-5e62-47db-91af-


users and groups, including 98c3a49a38b1
resetting passwords for limited
admins.
Role Description Template ID

Virtual Visits Administrator Manage and share Virtual e300d9e7-4a2b-4295-9eff-


Visits information and metrics f1c78b36cc98
from admin centers or the
Virtual Visits app.

Viva Goals Administrator Manage and configure all 92b086b3-e367-4ef2-b869-


aspects of Microsoft Viva 1de128fb986e
Goals.

Windows 365 Administrator Can provision and manage all 11451d60-acb2-45eb-a7d6-


aspects of Cloud PCs. 43d0f0125c13

Windows Update Deployment Can create and manage all 32696413-001a-46ae-978c-


Administrator aspects of Windows Update ce0f6b3620d2
deployments through the
Windows Update for Business
deployment service.

Yammer Administrator Manage all aspects of the 810a2642-a034-447f-a5e8-


Yammer service. 41beaa378541

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

microsoft.directory/adminConsentRequestPolic Manage admin consent request policies in


y/allProperties/allTasks Azure AD

microsoft.directory/appConsent/appConsentRe Read all properties of consent requests for


quests/allProperties/read applications registered with Azure AD

microsoft.directory/applications/create Create all types of applications

microsoft.directory/applications/delete Delete all types of applications

microsoft.directory/applications/applicationPro Read all application proxy properties


xy/read

microsoft.directory/applications/applicationPro Update all application proxy properties


xy/update

microsoft.directory/applications/applicationPro Update authentication on all types of


xyAuthentication/update applications

microsoft.directory/applications/applicationPro Update SSL certificate settings for application


xySslCertificate/update proxy

microsoft.directory/applications/applicationPro Update URL settings for application proxy


xyUrlSettings/update

microsoft.directory/applications/appRoles/upd Update the appRoles property on all types of


ate applications

microsoft.directory/applications/audience/upda Update the audience property for applications


te

microsoft.directory/applications/authentication Update authentication on all types of


/update applications

microsoft.directory/applications/basic/update Update basic properties for applications

microsoft.directory/applications/credentials/up Update application credentials


date

microsoft.directory/applications/extensionProp Update extension properties on applications


erties/update
Actions Description

microsoft.directory/applications/notes/update Update notes of applications

microsoft.directory/applications/owners/updat Update owners of applications


e

microsoft.directory/applications/permissions/u Update exposed permissions and required


pdate permissions on all types of applications

microsoft.directory/applications/policies/updat Update policies of applications


e

microsoft.directory/applications/tag/update Update tags of applications

microsoft.directory/applications/verification/up Update applicationsverification property


date

microsoft.directory/applications/synchronizatio Read provisioning settings associated with the


n/standard/read application object

microsoft.directory/applicationTemplates/insta Instantiate gallery applications from application


ntiate templates

microsoft.directory/auditLogs/allProperties/rea Read all properties on audit logs, including


d privileged properties

microsoft.directory/connectors/create Create application proxy connectors

microsoft.directory/connectors/allProperties/re Read all properties of application proxy


ad connectors

microsoft.directory/connectorGroups/create Create application proxy connector groups

microsoft.directory/connectorGroups/delete Delete application proxy connector groups

microsoft.directory/connectorGroups/allPropert Read all properties of application proxy


ies/read connector groups

microsoft.directory/connectorGroups/allPropert Update all properties of application proxy


ies/update connector groups

microsoft.directory/customAuthenticationExten Create and manage custom authentication


sions/allProperties/allTasks extensions

microsoft.directory/deletedItems.applications/d Permanently delete applications, which can no


elete longer be restored

microsoft.directory/deletedItems.applications/r Restore soft deleted applications to original


estore state
Actions Description

microsoft.directory/oAuth2PermissionGrants/all Create and delete OAuth 2.0 permission grants,


Properties/allTasks and read and update all properties

microsoft.directory/applicationPolicies/create Create application policies

microsoft.directory/applicationPolicies/delete Delete application policies

microsoft.directory/applicationPolicies/standar Read standard properties of application policies


d/read

microsoft.directory/applicationPolicies/owners/ Read owners on application policies


read

microsoft.directory/applicationPolicies/policyA Read application policies applied to objects list


ppliedTo/read

microsoft.directory/applicationPolicies/basic/up Update standard properties of application


date policies

microsoft.directory/applicationPolicies/owners/ Update the owner property of application


update policies

microsoft.directory/provisioningLogs/allPropert Read all properties of provisioning logs


ies/read

microsoft.directory/servicePrincipals/create Create service principals

microsoft.directory/servicePrincipals/delete Delete service principals

microsoft.directory/servicePrincipals/disable Disable service principals

microsoft.directory/servicePrincipals/enable Enable service principals

microsoft.directory/servicePrincipals/getPasswo Manage password single sign-on credentials on


rdSingleSignOnCredentials service principals

microsoft.directory/servicePrincipals/synchroniz Manage application provisioning secrets and


ationCredentials/manage credentials

microsoft.directory/servicePrincipals/synchroniz Start, restart, and pause application


ationJobs/manage provisioning synchronization jobs

microsoft.directory/servicePrincipals/synchroniz Create and manage application provisioning


ationSchema/manage synchronization jobs and schema

microsoft.directory/servicePrincipals/managePa Read password single sign-on credentials on


sswordSingleSignOnCredentials service principals
Actions Description

microsoft.directory/servicePrincipals/managePe Grant consent for application permissions and


rmissionGrantsForAll.microsoft-application- delegated permissions on behalf of any user or
admin all users, except for application permissions for
Microsoft Graph

microsoft.directory/servicePrincipals/appRoleAs Update service principal role assignments


signedTo/update

microsoft.directory/servicePrincipals/audience/ Update audience properties on service


update principals

microsoft.directory/servicePrincipals/authentica Update authentication properties on service


tion/update principals

microsoft.directory/servicePrincipals/basic/upd Update basic properties on service principals


ate

microsoft.directory/servicePrincipals/credential Update credentials of service principals


s/update

microsoft.directory/servicePrincipals/notes/upd Update notes of service principals


ate

microsoft.directory/servicePrincipals/owners/up Update owners of service principals


date

microsoft.directory/servicePrincipals/permissio Update permissions of service principals


ns/update

microsoft.directory/servicePrincipals/policies/u Update policies of service principals


pdate

microsoft.directory/servicePrincipals/tag/updat Update the tag property for service principals


e

microsoft.directory/servicePrincipals/synchroniz Read provisioning settings associated with your


ation/standard/read service principal

microsoft.directory/signInReports/allProperties/ Read all properties on sign-in reports, including


read privileged properties

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center
Actions Description

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.directory/applications/createAsOwne Create all types of applications, and creator is


r added as the first owner

microsoft.directory/oAuth2PermissionGrants/cr Create OAuth 2.0 permission grants, with


eateAsOwner creator as the first owner

microsoft.directory/servicePrincipals/createAsO Create service principals, with creator as the


wner first owner

Attack Payload Author


Users in this role can create attack payloads but not actually launch or schedule them.
Attack payloads are then available to all administrators in the tenant who can use them
to create a simulation.

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

microsoft.office365.protectionCenter/attackSim Create and manage attack payloads in Attack


ulator/payload/allProperties/allTasks Simulator

microsoft.office365.protectionCenter/attackSim Read reports of attack simulation, responses,


ulator/reports/allProperties/read and associated training
Attack Simulation Administrator
Users in this role can create and manage all aspects of attack simulation creation,
launch/scheduling of a simulation, and the review of simulation results. Members of this
role have this access for all simulations in the tenant.

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

microsoft.office365.protectionCenter/attackSim Create and manage attack payloads in Attack


ulator/payload/allProperties/allTasks Simulator

microsoft.office365.protectionCenter/attackSim Read reports of attack simulation, responses,


ulator/reports/allProperties/read and associated training

microsoft.office365.protectionCenter/attackSim Create and manage attack simulation templates


ulator/simulation/allProperties/allTasks in Attack Simulator

Attribute Assignment Administrator


Users with this role can assign and remove custom security attribute keys and values for
supported Azure AD objects such as users, service principals, and devices.

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

microsoft.directory/attributeSets/allProperties/r Read all properties of attribute sets


ead

microsoft.directory/customSecurityAttributeDef Read all properties of custom security attribute


initions/allProperties/read definitions

microsoft.directory/devices/customSecurityAttri Read custom security attribute values for


butes/read devices

microsoft.directory/devices/customSecurityAttri Update custom security attribute values for


butes/update devices
Actions Description

microsoft.directory/servicePrincipals/customSe Read custom security attribute values for


curityAttributes/read service principals

microsoft.directory/servicePrincipals/customSe Update custom security attribute values for


curityAttributes/update service principals

microsoft.directory/users/customSecurityAttrib Read custom security attribute values for users


utes/read

microsoft.directory/users/customSecurityAttrib Update custom security attribute values for


utes/update users

Attribute Assignment Reader


Users with this role can read custom security attribute keys and values for supported
Azure AD objects.

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

microsoft.directory/attributeSets/allProperties/r Read all properties of attribute sets


ead

microsoft.directory/customSecurityAttributeDef Read all properties of custom security attribute


initions/allProperties/read definitions

microsoft.directory/devices/customSecurityAttri Read custom security attribute values for


butes/read devices

microsoft.directory/servicePrincipals/customSe Read custom security attribute values for


curityAttributes/read service principals

microsoft.directory/users/customSecurityAttrib Read custom security attribute values for users


utes/read

Attribute Definition Administrator


Users with this role can define a valid set of custom security attributes that can be
assigned to supported Azure AD objects. This role can also activate and deactivate
custom security attributes.

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

microsoft.directory/attributeSets/allProperties/ Manage all aspects of attribute sets


allTasks

microsoft.directory/customSecurityAttributeDef Manage all aspects of custom security attribute


initions/allProperties/allTasks definitions

Attribute Definition Reader


Users with this role can read the definition of custom security attributes.

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

microsoft.directory/attributeSets/allProperties/r Read all properties of attribute sets


ead

microsoft.directory/customSecurityAttributeDef Read all properties of custom security attribute


initions/allProperties/read definitions

Authentication Administrator
Assign the Authentication Administrator role to users who need to do the following:

Set or reset any authentication method (including passwords) for non-


administrators and some roles. For a list of the roles that an Authentication
Administrator can read or update authentication methods, see Who can reset
passwords.
Require users who are non-administrators or assigned to some roles to re-register
against existing non-password credentials (for example, MFA or FIDO), and can
also revoke remember MFA on the device, which prompts for MFA on the next
sign-in.
Perform sensitive actions for some users. For more information, see Who can
perform sensitive actions.
Create and manage support tickets in Azure and the Microsoft 365 admin center.

Users with this role cannot 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.

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

Authentication Yes for Yes for No No No Yes for Yes for


Administrator some some some some
users users users users

Privileged Yes for Yes for No No No Yes for all Yes for
Authentication all users all users users all
Administrator users

Authentication No No Yes Yes Yes No No


Policy
Administrator

User No No No No No Yes for Yes for


Administrator some some
users 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:

Application Registration and Enterprise Application owners, who can manage


credentials of apps they own. Those apps may have privileged permissions in
Azure AD and elsewhere not granted to Authentication Administrators.
Through this path an Authentication Administrator can assume the identity of
an application owner and then further assume the identity of a privileged
application by updating the credentials for the application.
Azure subscription owners, who may have access to sensitive or private
information or critical configuration in Azure.
Security Group and Microsoft 365 group owners, who can manage group
membership. Those groups may grant access to sensitive or private
information or critical configuration in Azure AD and elsewhere.
Administrators in other services outside of Azure AD like Exchange Online,
Microsoft 365 Defender portal, Microsoft Purview compliance portal, and
human resources systems.
Non-administrators like executives, legal counsel, and human resources
employees who may have access to sensitive or private information.

Actions Description

microsoft.directory/users/authenticationMetho Create authentication methods for users


ds/create

microsoft.directory/users/authenticationMetho Delete authentication methods for users


ds/delete

microsoft.directory/users/authenticationMetho Read standard properties of authentication


ds/standard/restrictedRead methods that do not include personally
identifiable information for users

microsoft.directory/users/authenticationMetho Update basic properties of authentication


ds/basic/update methods for users

microsoft.directory/deletedItems.users/restore Restore soft deleted users to original state

microsoft.directory/users/delete Delete users

microsoft.directory/users/disable Disable users

microsoft.directory/users/enable Enable users

microsoft.directory/users/invalidateAllRefreshT Force sign-out by invalidating user refresh


okens tokens

microsoft.directory/users/restore Restore deleted users

microsoft.directory/users/basic/update Update basic properties on users


Actions Description

microsoft.directory/users/manager/update Update manager for users

microsoft.directory/users/password/update Reset passwords for all users

microsoft.directory/users/userPrincipalName/u Update User Principal Name of users


pdate

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Authentication Policy Administrator


Assign the Authentication Policy Administrator role to users who need to do the
following:

Configure the authentication methods policy, tenant-wide MFA settings, and


password protection policy that determine which methods each user can register
and use.
Manage Password Protection settings: smart lockout configurations and updating
the custom banned passwords list.
Create and manage verifiable credentials.
Create and manage Azure support tickets.

Users with this role cannot do the following:

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.

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

Authentication Yes for Yes for No No No Yes for Yes for


Administrator some some some some
users users users users

Privileged Yes for Yes for No No No Yes for all Yes for
Authentication all users all users users all
Administrator users

Authentication No No Yes Yes Yes No No


Policy
Administrator

User No No No No No Yes for Yes for


Administrator some some
users users

Actions Description

microsoft.directory/organization/strongAuthen Manage all aspects of strong authentication


tication/allTasks properties of an organization

microsoft.directory/userCredentialPolicies/creat Create credential policies for users


e

microsoft.directory/userCredentialPolicies/delet Delete credential policies for users


e

microsoft.directory/userCredentialPolicies/stan Read standard properties of credential policies


dard/read for users

microsoft.directory/userCredentialPolicies/own Read owners of credential policies for users


ers/read

microsoft.directory/userCredentialPolicies/polic Read policy.appliesTo navigation link


yAppliedTo/read

microsoft.directory/userCredentialPolicies/basic Update basic policies for users


/update

microsoft.directory/userCredentialPolicies/own Update owners of credential policies for users


ers/update

microsoft.directory/userCredentialPolicies/tena Update policy.isOrganizationDefault property


ntDefault/update
Actions Description

microsoft.directory/verifiableCredentials/config Read a verifiable credential card


uration/contracts/cards/allProperties/read

microsoft.directory/verifiableCredentials/config Revoke a verifiable credential card


uration/contracts/cards/revoke

microsoft.directory/verifiableCredentials/config Create a verifiable credential contract


uration/contracts/create

microsoft.directory/verifiableCredentials/config Read a verifiable credential contract


uration/contracts/allProperties/read

microsoft.directory/verifiableCredentials/config Update a verifiable credential contract


uration/contracts/allProperties/update

microsoft.directory/verifiableCredentials/config Create configuration required to create and


uration/create manage verifiable credentials

microsoft.directory/verifiableCredentials/config Delete configuration required to create and


uration/delete manage verifiable credentials and delete all of
its verifiable credentials

microsoft.directory/verifiableCredentials/config Read configuration required to create and


uration/allProperties/read manage verifiable credentials

microsoft.directory/verifiableCredentials/config Update configuration required to create and


uration/allProperties/update manage verifiable credentials

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

Azure AD Joined Device Local Administrator


This role is available for assignment only as an additional local administrator in Device
settings. Users with this role become local machine administrators on all Windows 10
devices that are joined to Azure Active Directory. They do not have the ability to
manage devices objects in Azure Active Directory.

Actions Description

microsoft.directory/groupSettings/standard/rea Read basic properties on group settings


d

microsoft.directory/groupSettingTemplates/sta Read basic properties on group setting


ndard/read templates
Azure DevOps Administrator
Users with this role can manage all enterprise Azure DevOps policies, applicable to all
Azure DevOps organizations backed by the Azure AD. Users in this role can manage
these policies by navigating to any Azure DevOps organization that is backed by the
company's Azure AD. Additionally, users in this role can claim ownership of orphaned
Azure DevOps organizations. This role grants no other Azure DevOps-specific
permissions (for example, Project Collection Administrators) inside any of the Azure
DevOps organizations backed by the company's Azure AD organization.

Actions Description

microsoft.azure.devOps/allEntities/allTasks Read and configure Azure DevOps

Azure Information Protection Administrator


Users with this role have all permissions in the Azure Information Protection service. This
role allows configuring labels for the Azure Information Protection policy, managing
protection templates, and activating protection. This role does not grant any
permissions in Identity Protection, Privileged Identity Management, Monitor Microsoft
365 Service Health, Microsoft 365 Defender portal, or Microsoft Purview compliance
portal.

Actions Description

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.azure.informationProtection/allEntitie Manage all aspects of Azure Information


s/allTasks Protection

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center
B2C IEF Keyset Administrator
User can create and manage policy keys and secrets for token encryption, token
signatures, and claim encryption/decryption. By adding new keys to existing key
containers, this limited administrator can roll over secrets as needed without impacting
existing applications. This user can see the full content of these secrets and their
expiration dates even after their creation.

) 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

microsoft.directory/b2cTrustFrameworkKeySet/ Read and configure key sets in Azure Active


allProperties/allTasks Directory B2C

B2C IEF Policy Administrator


Users in this role have the ability to create, read, update, and delete all custom policies
in Azure AD B2C and therefore have full control over the Identity Experience Framework
in the relevant Azure AD B2C organization. By editing policies, this user can establish
direct federation with external identity providers, change the directory schema, change
all user-facing content (HTML, CSS, JavaScript), change the requirements to complete an
authentication, create new users, send user data to external systems including full
migrations, and edit all user information including sensitive fields like passwords and
phone numbers. Conversely, this role cannot change the encryption keys or edit the
secrets used for federation in the organization.

) 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

microsoft.directory/b2cTrustFrameworkPolicy/al Read and configure custom policies in Azure


lProperties/allTasks Active Directory B2C
Billing Administrator
Makes purchases, manages subscriptions, manages support tickets, and monitors
service health.

Actions Description

microsoft.directory/organization/basic/update Update basic properties on organization

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.commerce.billing/allEntities/allProper Manage all aspects of Office 365 billing


ties/allTasks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Cloud App Security Administrator


Users with this role have full permissions in Defender for Cloud Apps. They can add
administrators, add Microsoft Defender for Cloud Apps policies and settings, upload
logs, and perform governance actions.

Actions Description

microsoft.directory/cloudAppSecurity/allProper Create and delete all resources, and read and


ties/allTasks update standard properties in Microsoft
Defender for Cloud Apps

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Cloud Application Administrator


Users in this role have the same permissions as the Application Administrator role,
excluding the ability to manage application proxy. This role grants the ability to create
and manage all aspects of enterprise applications and application registrations. 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

microsoft.directory/adminConsentRequestPolic Manage admin consent request policies in


y/allProperties/allTasks Azure AD

microsoft.directory/appConsent/appConsentRe Read all properties of consent requests for


quests/allProperties/read applications registered with Azure AD

microsoft.directory/applications/create Create all types of applications

microsoft.directory/applications/delete Delete all types of applications

microsoft.directory/applications/appRoles/upd Update the appRoles property on all types of


ate applications

microsoft.directory/applications/audience/upda Update the audience property for applications


te

microsoft.directory/applications/authentication Update authentication on all types of


/update applications
Actions Description

microsoft.directory/applications/basic/update Update basic properties for applications

microsoft.directory/applications/credentials/up Update application credentials


date

microsoft.directory/applications/extensionProp Update extension properties on applications


erties/update

microsoft.directory/applications/notes/update Update notes of applications

microsoft.directory/applications/owners/updat Update owners of applications


e

microsoft.directory/applications/permissions/u Update exposed permissions and required


pdate permissions on all types of applications

microsoft.directory/applications/policies/updat Update policies of applications


e

microsoft.directory/applications/tag/update Update tags of applications

microsoft.directory/applications/verification/up Update applicationsverification property


date

microsoft.directory/applications/synchronizatio Read provisioning settings associated with the


n/standard/read application object

microsoft.directory/applicationTemplates/insta Instantiate gallery applications from application


ntiate templates

microsoft.directory/auditLogs/allProperties/rea Read all properties on audit logs, including


d privileged properties

microsoft.directory/deletedItems.applications/d Permanently delete applications, which can no


elete longer be restored

microsoft.directory/deletedItems.applications/r Restore soft deleted applications to original


estore state

microsoft.directory/oAuth2PermissionGrants/all Create and delete OAuth 2.0 permission grants,


Properties/allTasks and read and update all properties

microsoft.directory/applicationPolicies/create Create application policies

microsoft.directory/applicationPolicies/delete Delete application policies

microsoft.directory/applicationPolicies/standar Read standard properties of application policies


d/read
Actions Description

microsoft.directory/applicationPolicies/owners/ Read owners on application policies


read

microsoft.directory/applicationPolicies/policyA Read application policies applied to objects list


ppliedTo/read

microsoft.directory/applicationPolicies/basic/up Update standard properties of application


date policies

microsoft.directory/applicationPolicies/owners/ Update the owner property of application


update policies

microsoft.directory/provisioningLogs/allPropert Read all properties of provisioning logs


ies/read

microsoft.directory/servicePrincipals/create Create service principals

microsoft.directory/servicePrincipals/delete Delete service principals

microsoft.directory/servicePrincipals/disable Disable service principals

microsoft.directory/servicePrincipals/enable Enable service principals

microsoft.directory/servicePrincipals/getPasswo Manage password single sign-on credentials on


rdSingleSignOnCredentials service principals

microsoft.directory/servicePrincipals/synchroniz Manage application provisioning secrets and


ationCredentials/manage credentials

microsoft.directory/servicePrincipals/synchroniz Start, restart, and pause application


ationJobs/manage provisioning synchronization jobs

microsoft.directory/servicePrincipals/synchroniz Create and manage application provisioning


ationSchema/manage synchronization jobs and schema

microsoft.directory/servicePrincipals/managePa Read password single sign-on credentials on


sswordSingleSignOnCredentials service principals

microsoft.directory/servicePrincipals/managePe Grant consent for application permissions and


rmissionGrantsForAll.microsoft-application- delegated permissions on behalf of any user or
admin all users, except for application permissions for
Microsoft Graph

microsoft.directory/servicePrincipals/appRoleAs Update service principal role assignments


signedTo/update

microsoft.directory/servicePrincipals/audience/ Update audience properties on service


update principals
Actions Description

microsoft.directory/servicePrincipals/authentica Update authentication properties on service


tion/update principals

microsoft.directory/servicePrincipals/basic/upd Update basic properties on service principals


ate

microsoft.directory/servicePrincipals/credential Update credentials of service principals


s/update

microsoft.directory/servicePrincipals/notes/upd Update notes of service principals


ate

microsoft.directory/servicePrincipals/owners/up Update owners of service principals


date

microsoft.directory/servicePrincipals/permissio Update permissions of service principals


ns/update

microsoft.directory/servicePrincipals/policies/u Update policies of service principals


pdate

microsoft.directory/servicePrincipals/tag/updat Update the tag property for service principals


e

microsoft.directory/servicePrincipals/synchroniz Read provisioning settings associated with your


ation/standard/read service principal

microsoft.directory/signInReports/allProperties/ Read all properties on sign-in reports, including


read privileged properties

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Cloud Device Administrator


Users in this role can enable, disable, and delete devices in Azure AD and read Windows
10 BitLocker keys (if present) in the Azure portal. The role does not grant permissions to
manage any other properties on the device.

Actions Description

microsoft.directory/auditLogs/allProperties/rea Read all properties on audit logs, including


d privileged properties

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.directory/bitlockerKeys/key/read Read bitlocker metadata and key on devices

microsoft.directory/deletedItems.devices/delet Permanently delete devices, which can no


e longer be restored

microsoft.directory/deletedItems.devices/restor Restore soft deleted devices to original state


e

microsoft.directory/devices/delete Delete devices from Azure AD

microsoft.directory/devices/disable Disable devices in Azure AD

microsoft.directory/devices/enable Enable devices in Azure AD

microsoft.directory/deviceLocalCredentials/pas Read all properties of the backed up local


sword/read administrator account credentials for Azure AD
joined devices, including the password

microsoft.directory/deviceManagementPolicies Read standard properties on device


/standard/read management application policies

microsoft.directory/deviceManagementPolicies Update basic properties on device


/basic/update management application policies

microsoft.directory/deviceRegistrationPolicy/sta Read standard properties on device registration


ndard/read policies

microsoft.directory/deviceRegistrationPolicy/ba Update basic properties on device registration


sic/update policies

microsoft.directory/signInReports/allProperties/ Read all properties on sign-in reports, including


read privileged properties

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center
Compliance Administrator
Users with this role have permissions to manage compliance-related features in the
Microsoft Purview compliance portal, Microsoft 365 admin center, Azure, and Microsoft
365 Defender portal. Assignees can also manage all features within the Exchange admin
center and create support tickets for Azure and Microsoft 365. For more information,
see Roles and role groups in Microsoft Defender for Office 365 and Microsoft Purview
compliance.

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

Microsoft 365 Manage data governance


Defender portal Perform legal and data investigation
Manage Data Subject Request

This role has the same permissions as the Compliance Administrator role
group in Microsoft 365 Defender portal role-based access control.

Intune View all Intune audit data

Microsoft Defender Has read-only permissions and can manage alerts


for Cloud Apps Can create and modify file policies and allow file governance actions
Can view all the built-in reports under Data Management

Actions Description

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.directory/entitlementManagement/al Read all properties in Azure AD entitlement


lProperties/read management

microsoft.office365.complianceManager/allEnti Manage all aspects of Office 365 Compliance


ties/allTasks Manager

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center
Actions Description

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Compliance Data Administrator


Users with this role have permissions to track data in the Microsoft Purview compliance
portal, Microsoft 365 admin center, and Azure. Users can also track compliance data
within the Exchange admin center, Compliance Manager, and Teams & Skype for
Business admin center and create support tickets for Azure and Microsoft 365. For more
information about the differences between Compliance Administrator and Compliance
Data Administrator, see Roles and role groups in Microsoft Defender for Office 365 and
Microsoft Purview compliance.

In Can do

Microsoft Purview Monitor compliance-related policies across Microsoft 365 services


compliance portal Manage compliance alerts

Microsoft Purview Track, assign, and verify your organization's regulatory compliance activities
Compliance
Manager

Microsoft 365 Manage data governance


Defender portal Perform legal and data investigation
Manage Data Subject Request

This role has the same permissions as the Compliance Data Administrator
role group in Microsoft 365 Defender portal role-based access control.

Intune View all Intune audit data

Microsoft Defender Has read-only permissions and can manage alerts


for Cloud Apps Can create and modify file policies and allow file governance actions
Can view all the built-in reports under Data Management

Actions Description

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy
Actions Description

microsoft.directory/cloudAppSecurity/allProper Create and delete all resources, and read and


ties/allTasks update standard properties in Microsoft
Defender for Cloud Apps

microsoft.azure.informationProtection/allEntitie Manage all aspects of Azure Information


s/allTasks Protection

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.complianceManager/allEnti Manage all aspects of Office 365 Compliance


ties/allTasks Manager

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Conditional Access Administrator


Users with this role have the ability to manage Azure Active Directory Conditional
Access settings.

Actions Description

microsoft.directory/namedLocations/create Create custom rules that define network


locations

microsoft.directory/namedLocations/delete Delete custom rules that define network


locations

microsoft.directory/namedLocations/standard/r Read basic properties of custom rules that


ead define network locations

microsoft.directory/namedLocations/basic/upd Update basic properties of custom rules that


ate define network locations

microsoft.directory/conditionalAccessPolicies/cr Create conditional access policies


eate
Actions Description

microsoft.directory/conditionalAccessPolicies/d Delete conditional access policies


elete

microsoft.directory/conditionalAccessPolicies/st Read conditional access for policies


andard/read

microsoft.directory/conditionalAccessPolicies/o Read the owners of conditional access policies


wners/read

microsoft.directory/conditionalAccessPolicies/p Read the "applied to" property for conditional


olicyAppliedTo/read access policies

microsoft.directory/conditionalAccessPolicies/b Update basic properties for conditional access


asic/update policies

microsoft.directory/conditionalAccessPolicies/o Update owners for conditional access policies


wners/update

microsoft.directory/conditionalAccessPolicies/t Update the default tenant for conditional


enantDefault/update access policies

microsoft.directory/resourceNamespaces/resou Update Conditional Access authentication


rceActions/authenticationContext/update context of Microsoft 365 role-based access
control (RBAC) resource actions

Customer LockBox Access Approver


Manages Microsoft Purview Customer Lockbox requests in your organization. They
receive email notifications for Customer Lockbox requests and can approve and deny
requests from the Microsoft 365 admin center. They can also turn the Customer Lockbox
feature on or off. Only Global Administrators can reset the passwords of people
assigned to this role.

Actions Description

microsoft.office365.lockbox/allEntities/allTasks Manage all aspects of Customer Lockbox

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Desktop Analytics Administrator


Users in this role can manage the Desktop Analytics service. This includes the ability to
view asset inventory, create deployment plans, and view deployment and health status.
Actions Description

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.desktopAnalytics/allEntities Manage all aspects of Desktop Analytics


/allTasks

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

microsoft.directory/administrativeUnits/standar Read basic properties on administrative units


d/read

microsoft.directory/administrativeUnits/membe Read members of administrative units


rs/read

microsoft.directory/applications/standard/read Read standard properties of applications

microsoft.directory/applications/owners/read Read owners of applications

microsoft.directory/applications/policies/read Read policies of applications

microsoft.directory/contacts/standard/read Read basic properties on contacts in Azure AD

microsoft.directory/contacts/memberOf/read Read the group membership for all contacts in


Azure AD

microsoft.directory/contracts/standard/read Read basic properties on partner contracts

microsoft.directory/devices/standard/read Read basic properties on devices


Actions Description

microsoft.directory/devices/memberOf/read Read device memberships

microsoft.directory/devices/registeredOwners/r Read registered owners of devices


ead

microsoft.directory/devices/registeredUsers/rea Read registered users of devices


d

microsoft.directory/directoryRoles/standard/rea Read basic properties in Azure AD roles


d

microsoft.directory/directoryRoles/eligibleMem Read the eligible members of Azure AD roles


bers/read

microsoft.directory/directoryRoles/members/re Read all members of Azure AD roles


ad

microsoft.directory/domains/standard/read Read basic properties on domains

microsoft.directory/groups/standard/read Read standard properties of Security groups


and Microsoft 365 groups, including role-
assignable groups

microsoft.directory/groups/appRoleAssignment Read application role assignments of groups


s/read

microsoft.directory/groups/memberOf/read Read the memberOf property on Security


groups and Microsoft 365 groups, including
role-assignable groups

microsoft.directory/groups/members/read Read members of Security groups and


Microsoft 365 groups, including role-assignable
groups

microsoft.directory/groups/owners/read Read owners of Security groups and Microsoft


365 groups, including role-assignable groups

microsoft.directory/groups/settings/read Read settings of groups

microsoft.directory/groupSettings/standard/rea Read basic properties on group settings


d

microsoft.directory/groupSettingTemplates/sta Read basic properties on group setting


ndard/read templates

microsoft.directory/oAuth2PermissionGrants/st Read basic properties on OAuth 2.0 permission


andard/read grants

microsoft.directory/organization/standard/read Read basic properties on an organization


Actions Description

microsoft.directory/organization/trustedCAsFor Read trusted certificate authorities for


PasswordlessAuth/read passwordless authentication

microsoft.directory/applicationPolicies/standar Read standard properties of application policies


d/read

microsoft.directory/roleAssignments/standard/r Read basic properties on role assignments


ead

microsoft.directory/roleDefinitions/standard/re Read basic properties on role definitions


ad

microsoft.directory/servicePrincipals/appRoleAs Read service principal role assignments


signedTo/read

microsoft.directory/servicePrincipals/appRoleAs Read role assignments assigned to service


signments/read principals

microsoft.directory/servicePrincipals/standard/r Read basic properties of service principals


ead

microsoft.directory/servicePrincipals/memberO Read the group memberships on service


f/read principals

microsoft.directory/servicePrincipals/oAuth2Per Read delegated permission grants on service


missionGrants/read principals

microsoft.directory/servicePrincipals/owners/re Read owners of service principals


ad

microsoft.directory/servicePrincipals/ownedObj Read owned objects of service principals


ects/read

microsoft.directory/servicePrincipals/policies/re Read policies of service principals


ad

microsoft.directory/subscribedSkus/standard/re Read basic properties on subscriptions


ad

microsoft.directory/users/standard/read Read basic properties on users

microsoft.directory/users/appRoleAssignments/ Read application role assignments for users


read

microsoft.directory/users/deviceForResourceAc Read deviceForResourceAccount of users


count/read

microsoft.directory/users/directReports/read Read the direct reports for users

microsoft.directory/users/licenseDetails/read Read license details of users


Actions Description

microsoft.directory/users/manager/read Read manager of users

microsoft.directory/users/memberOf/read Read the group memberships of users

microsoft.directory/users/oAuth2PermissionGra Read delegated permission grants on users


nts/read

microsoft.directory/users/ownedDevices/read Read owned devices of users

microsoft.directory/users/ownedObjects/read Read owned objects of users

microsoft.directory/users/photo/read Read photo of users

microsoft.directory/users/registeredDevices/rea Read registered devices of users


d

microsoft.directory/users/scopedRoleMemberO Read user's membership of an Azure AD role,


f/read that is scoped to an administrative unit

microsoft.directory/users/sponsors/read Read sponsors of users

Directory Synchronization Accounts


Do not use. This role is automatically assigned to the Azure AD Connect service, and is
not intended or supported for any other use.

Actions Description

microsoft.directory/applications/create Create all types of applications

microsoft.directory/applications/delete Delete all types of applications

microsoft.directory/applications/appRoles/upd Update the appRoles property on all types of


ate applications

microsoft.directory/applications/audience/upda Update the audience property for applications


te

microsoft.directory/applications/authentication Update authentication on all types of


/update applications

microsoft.directory/applications/basic/update Update basic properties for applications

microsoft.directory/applications/credentials/up Update application credentials


date

microsoft.directory/applications/notes/update Update notes of applications


Actions Description

microsoft.directory/applications/owners/updat Update owners of applications


e

microsoft.directory/applications/permissions/u Update exposed permissions and required


pdate permissions on all types of applications

microsoft.directory/applications/policies/updat Update policies of applications


e

microsoft.directory/applications/tag/update Update tags of applications

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.directory/hybridAuthenticationPolicy/ Manage hybrid authentication policy in Azure


allProperties/allTasks AD

microsoft.directory/organization/dirSync/updat Update the organization directory sync


e property

microsoft.directory/passwordHashSync/allProp Manage all aspects of Password Hash


erties/allTasks Synchronization (PHS) in Azure AD

microsoft.directory/policies/create Create policies in Azure AD

microsoft.directory/policies/delete Delete policies in Azure AD

microsoft.directory/policies/standard/read Read basic properties on policies

microsoft.directory/policies/owners/read Read owners of policies

microsoft.directory/policies/policyAppliedTo/re Read policies.policyAppliedTo property


ad

microsoft.directory/policies/basic/update Update basic properties on policies

microsoft.directory/policies/owners/update Update owners of policies

microsoft.directory/policies/tenantDefault/upd Update default organization policies


ate

microsoft.directory/servicePrincipals/create Create service principals

microsoft.directory/servicePrincipals/delete Delete service principals

microsoft.directory/servicePrincipals/enable Enable service principals

microsoft.directory/servicePrincipals/disable Disable service principals

microsoft.directory/servicePrincipals/getPasswo Manage password single sign-on credentials on


rdSingleSignOnCredentials service principals
Actions Description

microsoft.directory/servicePrincipals/managePa Read password single sign-on credentials on


sswordSingleSignOnCredentials service principals

microsoft.directory/servicePrincipals/appRoleAs Read service principal role assignments


signedTo/read

microsoft.directory/servicePrincipals/appRoleAs Read role assignments assigned to service


signments/read principals

microsoft.directory/servicePrincipals/standard/r Read basic properties of service principals


ead

microsoft.directory/servicePrincipals/memberO Read the group memberships on service


f/read principals

microsoft.directory/servicePrincipals/oAuth2Per Read delegated permission grants on service


missionGrants/read principals

microsoft.directory/servicePrincipals/owners/re Read owners of service principals


ad

microsoft.directory/servicePrincipals/ownedObj Read owned objects of service principals


ects/read

microsoft.directory/servicePrincipals/policies/re Read policies of service principals


ad

microsoft.directory/servicePrincipals/appRoleAs Update service principal role assignments


signedTo/update

microsoft.directory/servicePrincipals/audience/ Update audience properties on service


update principals

microsoft.directory/servicePrincipals/authentica Update authentication properties on service


tion/update principals

microsoft.directory/servicePrincipals/basic/upd Update basic properties on service principals


ate

microsoft.directory/servicePrincipals/credential Update credentials of service principals


s/update

microsoft.directory/servicePrincipals/notes/upd Update notes of service principals


ate

microsoft.directory/servicePrincipals/owners/up Update owners of service principals


date

microsoft.directory/servicePrincipals/permissio Update permissions of service principals


ns/update
Actions Description

microsoft.directory/servicePrincipals/policies/u Update policies of service principals


pdate

microsoft.directory/servicePrincipals/tag/updat Update the tag property for service principals


e

Directory Writers
Users in this role can read and update basic information of users, groups, and service
principals.

Actions Description

microsoft.directory/applications/extensionProp Update extension properties on applications


erties/update

microsoft.directory/contacts/create Create contacts

microsoft.directory/groups/assignLicense Assign product licenses to groups for group-


based licensing

microsoft.directory/groups/create Create Security groups and Microsoft 365


groups, excluding role-assignable groups

microsoft.directory/groups/reprocessLicenseAs Reprocess license assignments for group-based


signment licensing

microsoft.directory/groups/basic/update Update basic properties on Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/groups/classification/updat Update the classification property on Security


e groups and Microsoft 365 groups, excluding
role-assignable groups

microsoft.directory/groups/dynamicMembershi Update the dynamic membership rule on


pRule/update Security groups and Microsoft 365 groups,
excluding role-assignable groups

microsoft.directory/groups/groupType/update Update properties that would affect the group


type of Security groups and Microsoft 365
groups, excluding role-assignable groups

microsoft.directory/groups/members/update Update members of Security groups and


Microsoft 365 groups, excluding role-
assignable groups
Actions Description

microsoft.directory/groups/onPremWriteBack/ Update Azure Active Directory groups to be


update written back to on-premises with Azure AD
Connect

microsoft.directory/groups/owners/update Update owners of Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/groups/settings/update Update settings of groups

microsoft.directory/groups/visibility/update Update the visibility property of Security groups


and Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/groupSettings/create Create group settings

microsoft.directory/groupSettings/delete Delete group settings

microsoft.directory/groupSettings/basic/updat Update basic properties on group settings


e

microsoft.directory/oAuth2PermissionGrants/cr Create OAuth 2.0 permission grants


eate

microsoft.directory/oAuth2PermissionGrants/b Update OAuth 2.0 permission grants


asic/update

microsoft.directory/servicePrincipals/synchroniz Manage application provisioning secrets and


ationCredentials/manage credentials

microsoft.directory/servicePrincipals/synchroniz Start, restart, and pause application


ationJobs/manage provisioning synchronization jobs

microsoft.directory/servicePrincipals/synchroniz Create and manage application provisioning


ationSchema/manage synchronization jobs and schema

microsoft.directory/servicePrincipals/appRoleAs Update service principal role assignments


signedTo/update

microsoft.directory/users/assignLicense Manage user licenses

microsoft.directory/users/create Add users

microsoft.directory/users/disable Disable users

microsoft.directory/users/enable Enable users

microsoft.directory/users/invalidateAllRefreshT Force sign-out by invalidating user refresh


okens tokens
Actions Description

microsoft.directory/users/inviteGuest Invite guest users

microsoft.directory/users/reprocessLicenseAssi Reprocess license assignments for users


gnment

microsoft.directory/users/basic/update Update basic properties on users

microsoft.directory/users/manager/update Update manager for users

microsoft.directory/users/photo/update Update photo of users

microsoft.directory/users/sponsors/update Update sponsors of users

microsoft.directory/users/userPrincipalName/u Update User Principal Name of users


pdate

Domain Name Administrator


Users with this role can manage (read, add, verify, update, and delete) domain names.
They can also read directory information about users, groups, and applications, as these
objects possess domain dependencies. For on-premises environments, users with this
role can configure domain names for federation so that associated users are always
authenticated on-premises. These users can then sign into Azure AD-based services with
their on-premises passwords via single sign-on. Federation settings need to be synced
via Azure AD Connect, so users also have permissions to manage Azure AD Connect.

Actions Description

microsoft.directory/domains/allProperties/allTa Create and delete domains, and read and


sks update all properties

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Dynamics 365 Administrator


Users with this role have global permissions within Microsoft Dynamics 365 Online,
when the service is present, as well as the ability to manage support tickets and monitor
service health. For more information, see Use service admin roles to manage your
tenant.
7 Note

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

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.dynamics365/allEntities/allTasks Manage all aspects of Dynamics 365

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.edge/allEntities/allProperties/allTasks Manage all aspects of Microsoft Edge

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.directory/groups/hiddenMembers/re Read hidden members of Security groups and


ad Microsoft 365 groups, including role-assignable
groups

microsoft.directory/groups.unified/create Create Microsoft 365 groups, excluding role-


assignable groups

microsoft.directory/groups.unified/delete Delete Microsoft 365 groups, excluding role-


assignable groups

microsoft.directory/groups.unified/restore Restore Microsoft 365 groups from soft-deleted


container, excluding role-assignable groups

microsoft.directory/groups.unified/basic/updat Update basic properties on Microsoft 365


e groups, excluding role-assignable groups

microsoft.directory/groups.unified/members/u Update members of Microsoft 365 groups,


pdate excluding role-assignable groups

microsoft.directory/groups.unified/owners/upd Update owners of Microsoft 365 groups,


ate excluding role-assignable groups

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.exchange/allEntities/basic/a Manage all aspects of Exchange Online


llTasks

microsoft.office365.network/performance/allPr Read all network performance properties in the


operties/read Microsoft 365 admin center
Actions Description

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.usageReports/allEntities/all Read Office 365 usage reports


Properties/read

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Exchange Recipient Administrator


Users with this role have read access to recipients and write access to the attributes of
those recipients in Exchange Online. For more information, see Recipients in Exchange
Server.

Actions Description

microsoft.office365.exchange/recipients/allProp Create and delete all recipients, and read and


erties/allTasks update all properties of recipients in Exchange
Online

microsoft.office365.exchange/migration/allProp Manage all tasks related to migration of


erties/allTasks recipients in Exchange Online

External ID User Flow Administrator


Users with this role can create and manage user flows (also called "built-in" policies) in
the Azure portal. These users can customize HTML/CSS/JavaScript content, change MFA
requirements, select claims in the token, manage API connectors and their credentials,
and configure session settings for all user flows in the Azure AD organization. On the
other hand, this role does not include the ability to review user data or make changes to
the attributes that are included in the organization schema. Changes to Identity
Experience Framework policies (also known as custom policies) are also outside the
scope of this role.

Actions Description

microsoft.directory/b2cUserFlow/allProperties/ Read and configure user flow in Azure Active


allTasks Directory B2C
External ID User Flow Attribute Administrator
Users with this role add or delete custom attributes available to all user flows in the
Azure AD organization. As such, users with this role can change or add new elements to
the end-user schema and impact the behavior of all user flows and indirectly result in
changes to what data may be asked of end users and ultimately sent as claims to
applications. This role cannot edit user flows.

Actions Description

microsoft.directory/b2cUserAttribute/allPropert Read and configure user attribute in Azure


ies/allTasks Active Directory B2C

External Identity Provider Administrator


This administrator manages federation between Azure AD organizations and external
identity providers. With this role, users can add new identity providers and configure all
available settings (e.g. authentication path, service ID, assigned key containers). This user
can enable the Azure AD organization to trust authentications from external identity
providers. The resulting impact on end-user experiences depends on the type of
organization:

Azure AD organizations for employees and partners: The addition of a federation


(e.g. with Gmail) will immediately impact all guest invitations not yet redeemed.
See Adding Google as an identity provider for B2B guest users.
Azure Active Directory B2C organizations: The addition of a federation (for
example, with Facebook, or with another Azure AD organization) does not
immediately impact end-user flows until the identity provider is added as an
option in a user flow (also called a built-in policy). See Configuring a Microsoft
account as an identity provider for an example. To change user flows, the limited
role of "B2C User Flow Administrator" is required.

Actions Description

microsoft.directory/domains/federation/update Update federation property of domains

microsoft.directory/identityProviders/allPropert Read and configure identity providers in Azure


ies/allTasks Active Directory B2C

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

microsoft.directory/accessReviews/allProperties (Deprecated) Create and delete access reviews,


/allTasks read and update all properties of access
reviews, and manage access reviews of groups
in Azure AD

microsoft.directory/accessReviews/definitions/a Manage access reviews of all reviewable


llProperties/allTasks resources in Azure AD

microsoft.directory/adminConsentRequestPolic Manage admin consent request policies in


y/allProperties/allTasks Azure AD

microsoft.directory/administrativeUnits/allProp Create and manage administrative units


erties/allTasks (including members)

microsoft.directory/appConsent/appConsentRe Read all properties of consent requests for


quests/allProperties/read applications registered with Azure AD

microsoft.directory/applications/allProperties/al Create and delete applications, and read and


lTasks update all properties

microsoft.directory/applications/synchronizatio Read provisioning settings associated with the


n/standard/read application object

microsoft.directory/applicationTemplates/insta Instantiate gallery applications from application


ntiate templates
Actions Description

microsoft.directory/auditLogs/allProperties/rea Read all properties on audit logs, including


d privileged properties

microsoft.directory/users/authenticationMetho Create authentication methods for users


ds/create

microsoft.directory/users/authenticationMetho Delete authentication methods for users


ds/delete

microsoft.directory/users/authenticationMetho Read standard properties of authentication


ds/standard/read methods for users

microsoft.directory/users/authenticationMetho Update basic properties of authentication


ds/basic/update methods for users

microsoft.directory/authorizationPolicy/allProp Manage all aspects of authorization policy


erties/allTasks

microsoft.directory/bitlockerKeys/key/read Read bitlocker metadata and key on devices

microsoft.directory/cloudAppSecurity/allProper Create and delete all resources, and read and


ties/allTasks update standard properties in Microsoft
Defender for Cloud Apps

microsoft.directory/connectors/create Create application proxy connectors

microsoft.directory/connectors/allProperties/re Read all properties of application proxy


ad connectors

microsoft.directory/connectorGroups/create Create application proxy connector groups

microsoft.directory/connectorGroups/delete Delete application proxy connector groups

microsoft.directory/connectorGroups/allPropert Read all properties of application proxy


ies/read connector groups

microsoft.directory/connectorGroups/allPropert Update all properties of application proxy


ies/update connector groups

microsoft.directory/contacts/allProperties/allTas Create and delete contacts, and read and


ks update all properties

microsoft.directory/contracts/allProperties/allTa Create and delete partner contracts, and read


sks and update all properties

microsoft.directory/customAuthenticationExten Create and manage custom authentication


sions/allProperties/allTasks extensions

microsoft.directory/deletedItems/delete Permanently delete objects, which can no


longer be restored
Actions Description

microsoft.directory/deletedItems/restore Restore soft deleted objects to original state

microsoft.directory/devices/allProperties/allTas Create and delete devices, and read and update


ks all properties

microsoft.directory/namedLocations/create Create custom rules that define network


locations

microsoft.directory/namedLocations/delete Delete custom rules that define network


locations

microsoft.directory/namedLocations/standard/r Read basic properties of custom rules that


ead define network locations

microsoft.directory/namedLocations/basic/upd Update basic properties of custom rules that


ate define network locations

microsoft.directory/deviceLocalCredentials/pas Read all properties of the backed up local


sword/read administrator account credentials for Azure AD
joined devices, including the password

microsoft.directory/deviceManagementPolicies Read standard properties on device


/standard/read management application policies

microsoft.directory/deviceManagementPolicies Update basic properties on device


/basic/update management application policies

microsoft.directory/deviceRegistrationPolicy/sta Read standard properties on device registration


ndard/read policies

microsoft.directory/deviceRegistrationPolicy/ba Update basic properties on device registration


sic/update policies

microsoft.directory/directoryRoles/allProperties Create and delete directory roles, and read and


/allTasks update all properties

microsoft.directory/directoryRoleTemplates/allP Create and delete Azure AD role templates, and


roperties/allTasks read and update all properties

microsoft.directory/domains/allProperties/allTa Create and delete domains, and read and


sks update all properties

microsoft.directory/domains/federationConfigu Read standard properties of federation


ration/standard/read configuration for domains

microsoft.directory/domains/federationConfigu Update basic federation configuration for


ration/basic/update domains

microsoft.directory/domains/federationConfigu Create federation configuration for domains


ration/create
Actions Description

microsoft.directory/domains/federationConfigu Delete federation configuration for domains


ration/delete

microsoft.directory/entitlementManagement/al Create and delete resources, and read and


lProperties/allTasks update all properties in Azure AD entitlement
management

microsoft.directory/groups/allProperties/allTask Create and delete groups, and read and update


s all properties

microsoft.directory/groupsAssignableToRoles/c Create role-assignable groups


reate

microsoft.directory/groupsAssignableToRoles/d Delete role-assignable groups


elete

microsoft.directory/groupsAssignableToRoles/r Restore role-assignable groups


estore

microsoft.directory/groupsAssignableToRoles/a Update role-assignable groups


llProperties/update

microsoft.directory/groupSettings/allProperties Create and delete group settings, and read and


/allTasks update all properties

microsoft.directory/groupSettingTemplates/allP Create and delete group setting templates, and


roperties/allTasks read and update all properties

microsoft.directory/hybridAuthenticationPolicy/ Manage hybrid authentication policy in Azure


allProperties/allTasks AD

microsoft.directory/identityProtection/allProper Create and delete all resources, and read and


ties/allTasks update standard properties in Azure AD
Identity Protection

microsoft.directory/loginOrganizationBranding/ Create and delete loginTenantBranding, and


allProperties/allTasks read and update all properties

microsoft.directory/oAuth2PermissionGrants/all Create and delete OAuth 2.0 permission grants,


Properties/allTasks and read and update all properties

microsoft.directory/organization/allProperties/a Read and update all properties for an


llTasks organization

microsoft.directory/passwordHashSync/allProp Manage all aspects of Password Hash


erties/allTasks Synchronization (PHS) in Azure AD

microsoft.directory/policies/allProperties/allTas Create and delete policies, and read and update


ks all properties
Actions Description

microsoft.directory/conditionalAccessPolicies/al Manage all properties of conditional access


lProperties/allTasks policies

microsoft.directory/crossTenantAccessPolicy/st Read basic properties of cross-tenant access


andard/read policy

microsoft.directory/crossTenantAccessPolicy/all Update allowed cloud endpoints of cross-


owedCloudEndpoints/update tenant access policy

microsoft.directory/crossTenantAccessPolicy/ba Update basic settings of cross-tenant access


sic/update policy

microsoft.directory/crossTenantAccessPolicy/de Read basic properties of the default cross-


fault/standard/read tenant access policy

microsoft.directory/crossTenantAccessPolicy/de Update Azure AD B2B collaboration settings of


fault/b2bCollaboration/update the default cross-tenant access policy

microsoft.directory/crossTenantAccessPolicy/de Update Azure AD B2B direct connect settings of


fault/b2bDirectConnect/update the default cross-tenant access policy

microsoft.directory/crossTenantAccessPolicy/de Update cross-cloud Teams meeting settings of


fault/crossCloudMeetings/update the default cross-tenant access policy

microsoft.directory/crossTenantAccessPolicy/de Update tenant restrictions of the default cross-


fault/tenantRestrictions/update tenant access policy

microsoft.directory/crossTenantAccessPolicy/pa Create cross-tenant access policy for partners


rtners/create

microsoft.directory/crossTenantAccessPolicy/pa Delete cross-tenant access policy for partners


rtners/delete

microsoft.directory/crossTenantAccessPolicy/pa Read basic properties of cross-tenant access


rtners/standard/read policy for partners

microsoft.directory/crossTenantAccessPolicy/pa Update Azure AD B2B collaboration settings of


rtners/b2bCollaboration/update cross-tenant access policy for partners

microsoft.directory/crossTenantAccessPolicy/pa Update Azure AD B2B direct connect settings of


rtners/b2bDirectConnect/update cross-tenant access policy for partners

microsoft.directory/crossTenantAccessPolicy/pa Update cross-cloud Teams meeting settings of


rtners/crossCloudMeetings/update cross-tenant access policy for partners

microsoft.directory/crossTenantAccessPolicy/pa Update tenant restrictions of cross-tenant


rtners/tenantRestrictions/update access policy for partners

microsoft.directory/privilegedIdentityManagem Read all resources in Privileged Identity


ent/allProperties/read Management
Actions Description

microsoft.directory/provisioningLogs/allPropert Read all properties of provisioning logs


ies/read

microsoft.directory/resourceNamespaces/resou Update Conditional Access authentication


rceActions/authenticationContext/update context of Microsoft 365 role-based access
control (RBAC) resource actions

microsoft.directory/roleAssignments/allProperti Create and delete role assignments, and read


es/allTasks and update all role assignment properties

microsoft.directory/roleDefinitions/allProperties Create and delete role definitions, and read and


/allTasks update all properties

microsoft.directory/scopedRoleMemberships/al Create and delete scopedRoleMemberships,


lProperties/allTasks and read and update all properties

microsoft.directory/serviceAction/activateServic Can perform the "activate service" action for a


e service

microsoft.directory/serviceAction/disableDirect Can perform the "disable directory feature"


oryFeature service action

microsoft.directory/serviceAction/enableDirect Can perform the "enable directory feature"


oryFeature service action

microsoft.directory/serviceAction/getAvailableE Can perform the


xtentionProperties getAvailableExtentionProperties service action

microsoft.directory/servicePrincipals/allProperti Create and delete service principals, and read


es/allTasks and update all properties

microsoft.directory/servicePrincipals/managePe Grant consent for any permission to any


rmissionGrantsForAll.microsoft-company- application
admin

microsoft.directory/servicePrincipals/synchroniz Read provisioning settings associated with your


ation/standard/read service principal

microsoft.directory/signInReports/allProperties/ Read all properties on sign-in reports, including


read privileged properties

microsoft.directory/subscribedSkus/allPropertie Buy and manage subscriptions and delete


s/allTasks subscriptions

microsoft.directory/users/allProperties/allTasks Create and delete users, and read and update


all properties

microsoft.directory/permissionGrantPolicies/cre Create permission grant policies


ate
Actions Description

microsoft.directory/permissionGrantPolicies/del Delete permission grant policies


ete

microsoft.directory/permissionGrantPolicies/sta Read standard properties of permission grant


ndard/read policies

microsoft.directory/permissionGrantPolicies/ba Update basic properties of permission grant


sic/update policies

microsoft.directory/servicePrincipalCreationPoli Create service principal creation policies


cies/create

microsoft.directory/servicePrincipalCreationPoli Delete service principal creation policies


cies/delete

microsoft.directory/servicePrincipalCreationPoli Read standard properties of service principal


cies/standard/read creation policies

microsoft.directory/servicePrincipalCreationPoli Update basic properties of service principal


cies/basic/update creation policies

microsoft.directory/tenantManagement/tenant Create new tenants in Azure Active Directory


s/create

microsoft.directory/verifiableCredentials/config Read a verifiable credential card


uration/contracts/cards/allProperties/read

microsoft.directory/verifiableCredentials/config Revoke a verifiable credential card


uration/contracts/cards/revoke

microsoft.directory/verifiableCredentials/config Create a verifiable credential contract


uration/contracts/create

microsoft.directory/verifiableCredentials/config Read a verifiable credential contract


uration/contracts/allProperties/read

microsoft.directory/verifiableCredentials/config Update a verifiable credential contract


uration/contracts/allProperties/update

microsoft.directory/verifiableCredentials/config Create configuration required to create and


uration/create manage verifiable credentials

microsoft.directory/verifiableCredentials/config Delete configuration required to create and


uration/delete manage verifiable credentials and delete all of
its verifiable credentials

microsoft.directory/verifiableCredentials/config Read configuration required to create and


uration/allProperties/read manage verifiable credentials
Actions Description

microsoft.directory/verifiableCredentials/config Update configuration required to create and


uration/allProperties/update manage verifiable credentials

microsoft.directory/lifecycleWorkflows/workflo Manage all aspects of lifecycle workflows and


ws/allProperties/allTasks tasks in Azure AD

microsoft.azure.advancedThreatProtection/allE Manage all aspects of Azure Advanced Threat


ntities/allTasks Protection

microsoft.azure.informationProtection/allEntitie Manage all aspects of Azure Information


s/allTasks Protection

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.cloudPC/allEntities/allProperties/allTa Manage all aspects of Windows 365


sks

microsoft.commerce.billing/allEntities/allProper Manage all aspects of Office 365 billing


ties/allTasks

microsoft.commerce.billing/purchases/standard Read purchase services in M365 Admin Center.


/read

microsoft.dynamics365/allEntities/allTasks Manage all aspects of Dynamics 365

microsoft.edge/allEntities/allProperties/allTasks Manage all aspects of Microsoft Edge

microsoft.flow/allEntities/allTasks Manage all aspects of Microsoft Power


Automate

microsoft.hardware.support/shippingAddress/a Create, read, update, and delete shipping


llProperties/allTasks addresses for Microsoft hardware warranty
claims, including shipping addresses created by
others

microsoft.hardware.support/shippingStatus/allP Read shipping status for open Microsoft


roperties/read hardware warranty claims

microsoft.hardware.support/warrantyClaims/all Create and manage all aspects of Microsoft


Properties/allTasks hardware warranty claims

microsoft.insights/allEntities/allProperties/allTas Manage all aspects of Insights app


ks

microsoft.intune/allEntities/allTasks Manage all aspects of Microsoft Intune


Actions Description

microsoft.office365.complianceManager/allEnti Manage all aspects of Office 365 Compliance


ties/allTasks Manager

microsoft.office365.desktopAnalytics/allEntities Manage all aspects of Desktop Analytics


/allTasks

microsoft.office365.exchange/allEntities/basic/a Manage all aspects of Exchange Online


llTasks

microsoft.office365.knowledge/contentUnderst Read and update all properties of content


anding/allProperties/allTasks understanding in Microsoft 365 admin center

microsoft.office365.knowledge/contentUnderst Read analytics reports of content


anding/analytics/allProperties/read understanding in Microsoft 365 admin center

microsoft.office365.knowledge/knowledgeNet Read and update all properties of knowledge


work/allProperties/allTasks network in Microsoft 365 admin center

microsoft.office365.knowledge/knowledgeNet Manage topic visibility of knowledge network in


work/topicVisibility/allProperties/allTasks Microsoft 365 admin center

microsoft.office365.knowledge/learningSources Manage learning sources and all their


/allProperties/allTasks properties in Learning App.

microsoft.office365.lockbox/allEntities/allTasks Manage all aspects of Customer Lockbox

microsoft.office365.messageCenter/messages/r Read messages in Message Center in the


ead Microsoft 365 admin center, excluding security
messages

microsoft.office365.messageCenter/securityMe Read security messages in Message Center in


ssages/read the Microsoft 365 admin center

microsoft.office365.network/performance/allPr Read all network performance properties in the


operties/read Microsoft 365 admin center

microsoft.office365.organizationalMessages/all Manage all authoring aspects of Microsoft 365


Entities/allProperties/allTasks Organizational Messages

microsoft.office365.protectionCenter/allEntities Manage all aspects of the Security and


/allProperties/allTasks Compliance centers

microsoft.office365.search/content/manage Create and delete content, and read and


update all properties in Microsoft Search

microsoft.office365.securityComplianceCenter/ Create and delete all resources, and read and


allEntities/allTasks update standard properties in the Office 365
Security & Compliance Center
Actions Description

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.sharePoint/allEntities/allTas Create and delete all resources, and read and


ks update standard properties in SharePoint

microsoft.office365.skypeForBusiness/allEntities Manage all aspects of Skype for Business


/allTasks Online

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.usageReports/allEntities/all Read Office 365 usage reports


Properties/read

microsoft.office365.userCommunication/allEntit Read and update what's new messages visibility


ies/allTasks

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

microsoft.office365.yammer/allEntities/allPrope Manage all aspects of Yammer


rties/allTasks

microsoft.permissionsManagement/allEntities/a Manage all aspects of Entra Permissions


llProperties/allTasks Management

microsoft.powerApps/allEntities/allTasks Manage all aspects of Power Apps

microsoft.powerApps.powerBI/allEntities/allTas Manage all aspects of Power BI


ks

microsoft.teams/allEntities/allProperties/allTask Manage all resources in Teams


s

microsoft.virtualVisits/allEntities/allProperties/al Manage and share Virtual Visits information


lTasks and metrics from admin centers or the Virtual
Visits app

microsoft.windows.defenderAdvancedThreatPr Manage all aspects of Microsoft Defender for


otection/allEntities/allTasks Endpoint

microsoft.windows.updatesDeployments/allEnti Read and configure all aspects of Windows


ties/allProperties/allTasks Update Service

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.

Users with this role cannot do the following:

Cannot access the Purchase Services area in the Microsoft 365 admin center.

7 Note

Global Reader role has the following limitations:

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

microsoft.directory/accessReviews/allProperties (Deprecated) Read all properties of access


/read reviews

microsoft.directory/accessReviews/definitions/a Read all properties of access reviews of all


llProperties/read reviewable resources in Azure AD

microsoft.directory/adminConsentRequestPolic Read all properties of admin consent request


y/allProperties/read policies in Azure AD

microsoft.directory/administrativeUnits/allProp Read all properties of administrative units,


erties/read including members

microsoft.directory/appConsent/appConsentRe Read all properties of consent requests for


quests/allProperties/read applications registered with Azure AD

microsoft.directory/applications/allProperties/r Read all properties (including privileged


ead properties) on all types of applications

microsoft.directory/applications/synchronizatio Read provisioning settings associated with the


n/standard/read application object

microsoft.directory/auditLogs/allProperties/rea Read all properties on audit logs, including


d privileged properties

microsoft.directory/users/authenticationMetho Read standard properties of authentication


ds/standard/restrictedRead methods that do not include personally
identifiable information for users

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.directory/bitlockerKeys/key/read Read bitlocker metadata and key on devices

microsoft.directory/cloudAppSecurity/allProper Read all properties for Defender for Cloud Apps


ties/read

microsoft.directory/connectors/allProperties/re Read all properties of application proxy


ad connectors

microsoft.directory/connectorGroups/allPropert Read all properties of application proxy


ies/read connector groups

microsoft.directory/contacts/allProperties/read Read all properties for contacts

microsoft.directory/customAuthenticationExten Read custom authentication extensions


sions/allProperties/read

microsoft.directory/deviceLocalCredentials/stan Read all properties of the backed up local


dard/read administrator account credentials for Azure AD
joined devices, except the password
Actions Description

microsoft.directory/devices/allProperties/read Read all properties of devices

microsoft.directory/directoryRoles/allProperties Read all properties of directory roles


/read

microsoft.directory/directoryRoleTemplates/allP Read all properties of directory role templates


roperties/read

microsoft.directory/domains/allProperties/read Read all properties of domains

microsoft.directory/domains/federationConfigu Read standard properties of federation


ration/standard/read configuration for domains

microsoft.directory/entitlementManagement/al Read all properties in Azure AD entitlement


lProperties/read management

microsoft.directory/groups/allProperties/read Read all properties (including privileged


properties) on Security groups and Microsoft
365 groups, including role-assignable groups

microsoft.directory/groupSettings/allProperties Read all properties of group settings


/read

microsoft.directory/groupSettingTemplates/allP Read all properties of group setting templates


roperties/read

microsoft.directory/identityProtection/allProper Read all resources in Azure AD Identity


ties/read Protection

microsoft.directory/loginOrganizationBranding/ Read all properties for your organization's


allProperties/read branded sign-in page

microsoft.directory/namedLocations/standard/r Read basic properties of custom rules that


ead define network locations

microsoft.directory/oAuth2PermissionGrants/all Read all properties of OAuth 2.0 permission


Properties/read grants

microsoft.directory/organization/allProperties/r Read all properties for an organization


ead

microsoft.directory/permissionGrantPolicies/sta Read standard properties of permission grant


ndard/read policies

microsoft.directory/policies/allProperties/read Read all properties of policies

microsoft.directory/conditionalAccessPolicies/al Read all properties of conditional access


lProperties/read policies
Actions Description

microsoft.directory/crossTenantAccessPolicy/st Read basic properties of cross-tenant access


andard/read policy

microsoft.directory/crossTenantAccessPolicy/de Read basic properties of the default cross-


fault/standard/read tenant access policy

microsoft.directory/crossTenantAccessPolicy/pa Read basic properties of cross-tenant access


rtners/standard/read policy for partners

microsoft.directory/deviceManagementPolicies Read standard properties on device


/standard/read management application policies

microsoft.directory/deviceRegistrationPolicy/sta Read standard properties on device registration


ndard/read policies

microsoft.directory/privilegedIdentityManagem Read all resources in Privileged Identity


ent/allProperties/read Management

microsoft.directory/provisioningLogs/allPropert Read all properties of provisioning logs


ies/read

microsoft.directory/roleAssignments/allProperti Read all properties of role assignments


es/read

microsoft.directory/roleDefinitions/allProperties Read all properties of role definitions


/read

microsoft.directory/scopedRoleMemberships/al View members in administrative units


lProperties/read

microsoft.directory/serviceAction/getAvailableE Can perform the


xtentionProperties getAvailableExtentionProperties service action

microsoft.directory/servicePrincipals/allProperti Read all properties (including privileged


es/read properties) on servicePrincipals

microsoft.directory/servicePrincipalCreationPoli Read standard properties of service principal


cies/standard/read creation policies

microsoft.directory/servicePrincipals/synchroniz Read provisioning settings associated with your


ation/standard/read service principal

microsoft.directory/signInReports/allProperties/ Read all properties on sign-in reports, including


read privileged properties

microsoft.directory/subscribedSkus/allPropertie Read all properties of product subscriptions


s/read

microsoft.directory/users/allProperties/read Read all properties of users


Actions Description

microsoft.directory/verifiableCredentials/config Read a verifiable credential card


uration/contracts/cards/allProperties/read

microsoft.directory/verifiableCredentials/config Read a verifiable credential contract


uration/contracts/allProperties/read

microsoft.directory/verifiableCredentials/config Read configuration required to create and


uration/allProperties/read manage verifiable credentials

microsoft.directory/lifecycleWorkflows/workflo Read all properties of lifecycle workflows and


ws/allProperties/read tasks in Azure AD

microsoft.cloudPC/allEntities/allProperties/read Read all aspects of Windows 365

microsoft.commerce.billing/allEntities/allProper Read all resources of Office 365 billing


ties/read

microsoft.commerce.billing/purchases/standard Read purchase services in M365 Admin Center.


/read

microsoft.edge/allEntities/allProperties/read Read all aspects of Microsoft Edge

microsoft.hardware.support/shippingAddress/a Read shipping addresses for Microsoft


llProperties/read hardware warranty claims, including existing
shipping addresses created by others

microsoft.hardware.support/shippingStatus/allP Read shipping status for open Microsoft


roperties/read hardware warranty claims

microsoft.hardware.support/warrantyClaims/all Read Microsoft hardware warranty claims


Properties/read

microsoft.insights/allEntities/allProperties/read Read all aspects of Viva Insights

microsoft.office365.messageCenter/messages/r Read messages in Message Center in the


ead Microsoft 365 admin center, excluding security
messages

microsoft.office365.messageCenter/securityMe Read security messages in Message Center in


ssages/read the Microsoft 365 admin center

microsoft.office365.network/performance/allPr Read all network performance properties in the


operties/read Microsoft 365 admin center

microsoft.office365.organizationalMessages/all Read all aspects of Microsoft 365


Entities/allProperties/read Organizational Messages

microsoft.office365.protectionCenter/allEntities Read all properties in the Security and


/allProperties/read Compliance centers
Actions Description

microsoft.office365.securityComplianceCenter/ Read standard properties in Microsoft 365


allEntities/read Security and Compliance Center

microsoft.office365.usageReports/allEntities/all Read Office 365 usage reports


Properties/read

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

microsoft.office365.yammer/allEntities/allPrope Read all aspects of Yammer


rties/read

microsoft.permissionsManagement/allEntities/a Read all aspects of Entra Permissions


llProperties/read Management

microsoft.teams/allEntities/allProperties/read Read all properties of Microsoft Teams

microsoft.virtualVisits/allEntities/allProperties/r Read all aspects of Virtual Visits


ead

microsoft.windows.updatesDeployments/allEnti Read all aspects of Windows Update Service


ties/allProperties/read

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

microsoft.directory/deletedItems.groups/delete Permanently delete groups, which can no


longer be restored

microsoft.directory/deletedItems.groups/restor Restore soft deleted groups to original state


e

microsoft.directory/groups/assignLicense Assign product licenses to groups for group-


based licensing

microsoft.directory/groups/create Create Security groups and Microsoft 365


groups, excluding role-assignable groups
Actions Description

microsoft.directory/groups/delete Delete Security groups and Microsoft 365


groups, excluding role-assignable groups

microsoft.directory/groups/hiddenMembers/re Read hidden members of Security groups and


ad Microsoft 365 groups, including role-assignable
groups

microsoft.directory/groups/reprocessLicenseAs Reprocess license assignments for group-based


signment licensing

microsoft.directory/groups/restore Restore groups from soft-deleted container

microsoft.directory/groups/basic/update Update basic properties on Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/groups/classification/updat Update the classification property on Security


e groups and Microsoft 365 groups, excluding
role-assignable groups

microsoft.directory/groups/dynamicMembershi Update the dynamic membership rule on


pRule/update Security groups and Microsoft 365 groups,
excluding role-assignable groups

microsoft.directory/groups/groupType/update Update properties that would affect the group


type of Security groups and Microsoft 365
groups, excluding role-assignable groups

microsoft.directory/groups/members/update Update members of Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/groups/onPremWriteBack/ Update Azure Active Directory groups to be


update written back to on-premises with Azure AD
Connect

microsoft.directory/groups/owners/update Update owners of Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/groups/settings/update Update settings of groups

microsoft.directory/groups/visibility/update Update the visibility property of Security groups


and Microsoft 365 groups, excluding role-
assignable groups

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s
Actions Description

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.directory/users/inviteGuest Invite guest users

microsoft.directory/users/standard/read Read basic properties on users

microsoft.directory/users/appRoleAssignments/ Read application role assignments for users


read

microsoft.directory/users/deviceForResourceAc Read deviceForResourceAccount of users


count/read

microsoft.directory/users/directReports/read Read the direct reports for users

microsoft.directory/users/licenseDetails/read Read license details of users

microsoft.directory/users/manager/read Read manager of users

microsoft.directory/users/memberOf/read Read the group memberships of users

microsoft.directory/users/oAuth2PermissionGra Read delegated permission grants on users


nts/read

microsoft.directory/users/ownedDevices/read Read owned devices of users

microsoft.directory/users/ownedObjects/read Read owned objects of users

microsoft.directory/users/photo/read Read photo of users


Actions Description

microsoft.directory/users/registeredDevices/rea Read registered devices of users


d

microsoft.directory/users/scopedRoleMemberO Read user's membership of an Azure AD role,


f/read that is scoped to an administrative unit

microsoft.directory/users/sponsors/read Read sponsors of users

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.

Users with this role cannot do the following:

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:

Application Registration and Enterprise Application owners, who can manage


credentials of apps they own. Those apps may have privileged permissions in
Azure AD and elsewhere not granted to Helpdesk Administrators. Through
this path a Helpdesk Administrator may be able to assume the identity of an
application owner and then further assume the identity of a privileged
application by updating the credentials for the application.
Azure subscription owners, who might have access to sensitive or private
information or critical configuration in Azure.
Security Group and Microsoft 365 group owners, who can manage group
membership. Those groups may grant access to sensitive or private
information or critical configuration in Azure AD and elsewhere.
Administrators in other services outside of Azure AD like Exchange Online,
Microsoft 365 Defender portal, Microsoft Purview compliance portal, and
human resources systems.
Non-administrators like executives, legal counsel, and human resources
employees who may have access to sensitive or private information.

Delegating administrative permissions over subsets of users and applying policies to a


subset of users is possible with Administrative Units.

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

microsoft.directory/bitlockerKeys/key/read Read bitlocker metadata and key on devices

microsoft.directory/deviceLocalCredentials/stan Read all properties of the backed up local


dard/read administrator account credentials for Azure AD
joined devices, except the password

microsoft.directory/users/invalidateAllRefreshT Force sign-out by invalidating user refresh


okens tokens

microsoft.directory/users/password/update Reset passwords for all users

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Hybrid Identity Administrator


Users in this role can create, manage and deploy provisioning configuration setup from
AD to Azure AD using Cloud Provisioning as well as manage Azure AD Connect, Pass-
through Authentication (PTA), Password hash synchronization (PHS), Seamless Single
Sign-On (Seamless SSO), and federation settings. Users can also troubleshoot and
monitor logs using this role.

Actions Description

microsoft.directory/applications/create Create all types of applications

microsoft.directory/applications/delete Delete all types of applications

microsoft.directory/applications/appRoles/upd Update the appRoles property on all types of


ate applications

microsoft.directory/applications/audience/upda Update the audience property for applications


te

microsoft.directory/applications/authentication Update authentication on all types of


/update applications

microsoft.directory/applications/basic/update Update basic properties for applications

microsoft.directory/applications/notes/update Update notes of applications

microsoft.directory/applications/owners/updat Update owners of applications


e

microsoft.directory/applications/permissions/u Update exposed permissions and required


pdate permissions on all types of applications

microsoft.directory/applications/policies/updat Update policies of applications


e

microsoft.directory/applications/tag/update Update tags of applications

microsoft.directory/applications/synchronizatio Read provisioning settings associated with the


n/standard/read application object

microsoft.directory/applicationTemplates/insta Instantiate gallery applications from application


ntiate templates

microsoft.directory/auditLogs/allProperties/rea Read all properties on audit logs, including


d privileged properties

microsoft.directory/cloudProvisioning/allProper Read and configure all properties of Azure AD


ties/allTasks Cloud Provisioning service.

microsoft.directory/deletedItems.applications/d Permanently delete applications, which can no


elete longer be restored
Actions Description

microsoft.directory/deletedItems.applications/r Restore soft deleted applications to original


estore state

microsoft.directory/domains/allProperties/read Read all properties of domains

microsoft.directory/domains/federation/update Update federation property of domains

microsoft.directory/domains/federationConfigu Read standard properties of federation


ration/standard/read configuration for domains

microsoft.directory/domains/federationConfigu Update basic federation configuration for


ration/basic/update domains

microsoft.directory/domains/federationConfigu Create federation configuration for domains


ration/create

microsoft.directory/domains/federationConfigu Delete federation configuration for domains


ration/delete

microsoft.directory/hybridAuthenticationPolicy/ Manage hybrid authentication policy in Azure


allProperties/allTasks AD

microsoft.directory/organization/dirSync/updat Update the organization directory sync


e property

microsoft.directory/passwordHashSync/allProp Manage all aspects of Password Hash


erties/allTasks Synchronization (PHS) in Azure AD

microsoft.directory/provisioningLogs/allPropert Read all properties of provisioning logs


ies/read

microsoft.directory/servicePrincipals/create Create service principals

microsoft.directory/servicePrincipals/delete Delete service principals

microsoft.directory/servicePrincipals/disable Disable service principals

microsoft.directory/servicePrincipals/enable Enable service principals

microsoft.directory/servicePrincipals/synchroniz Manage application provisioning secrets and


ationCredentials/manage credentials

microsoft.directory/servicePrincipals/synchroniz Start, restart, and pause application


ationJobs/manage provisioning synchronization jobs

microsoft.directory/servicePrincipals/synchroniz Create and manage application provisioning


ationSchema/manage synchronization jobs and schema

microsoft.directory/servicePrincipals/audience/ Update audience properties on service


update principals
Actions Description

microsoft.directory/servicePrincipals/authentica Update authentication properties on service


tion/update principals

microsoft.directory/servicePrincipals/basic/upd Update basic properties on service principals


ate

microsoft.directory/servicePrincipals/notes/upd Update notes of service principals


ate

microsoft.directory/servicePrincipals/owners/up Update owners of service principals


date

microsoft.directory/servicePrincipals/permissio Update permissions of service principals


ns/update

microsoft.directory/servicePrincipals/policies/u Update policies of service principals


pdate

microsoft.directory/servicePrincipals/tag/updat Update the tag property for service principals


e

microsoft.directory/servicePrincipals/synchroniz Read provisioning settings associated with your


ation/standard/read service principal

microsoft.directory/signInReports/allProperties/ Read all properties on sign-in reports, including


read privileged properties

microsoft.directory/users/authorizationInfo/up Update the multivalued Certificate user IDs


date property of users

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.messageCenter/messages/r Read messages in Message Center in the


ead Microsoft 365 admin center, excluding security
messages

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center
Identity Governance Administrator
Users with this role can manage Azure AD identity governance configuration, including
access packages, access reviews, catalogs and policies, ensuring access is approved and
reviewed and guest users who no longer need access are removed.

Actions Description

microsoft.directory/accessReviews/definitions.a Manage access reviews of application role


pplications/allProperties/allTasks assignments in Azure AD

microsoft.directory/accessReviews/definitions.e Manage access reviews for access package


ntitlementManagement/allProperties/allTasks assignments in entitlement management

microsoft.directory/accessReviews/definitions.g Read all properties of access reviews for


roups/allProperties/read membership in Security and Microsoft 365
groups, including role-assignable groups.

microsoft.directory/accessReviews/definitions.g Update all properties of access reviews for


roups/allProperties/update membership in Security and Microsoft 365
groups, excluding role-assignable groups.

microsoft.directory/accessReviews/definitions.g Create access reviews for membership in


roups/create Security and Microsoft 365 groups.

microsoft.directory/accessReviews/definitions.g Delete access reviews for membership in


roups/delete Security and Microsoft 365 groups.

microsoft.directory/accessReviews/allProperties (Deprecated) Create and delete access reviews,


/allTasks read and update all properties of access
reviews, and manage access reviews of groups
in Azure AD

microsoft.directory/entitlementManagement/al Create and delete resources, and read and


lProperties/allTasks update all properties in Azure AD entitlement
management

microsoft.directory/groups/members/update Update members of Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/servicePrincipals/appRoleAs Update service principal role assignments


signedTo/update

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

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.insights/allEntities/allProperties/allTas Manage all aspects of Insights app


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.insights/queries/allProperties/allTasks Run and manage queries in Viva Insights

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center
Insights Business Leader
Users in this role can access a set of dashboards and insights via the Microsoft Viva
Insights app. This includes full access to all dashboards and presented insights and data
exploration functionality. Users in this role do not have access to product configuration
settings, which is the responsibility of the Insights Administrator role.

Learn more

Actions Description

microsoft.insights/reports/allProperties/read View reports and dashboard in Insights app

microsoft.insights/programs/allProperties/upda Deploy and manage programs in Insights app


te

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

microsoft.directory/bitlockerKeys/key/read Read bitlocker metadata and key on devices

microsoft.directory/contacts/create Create contacts

microsoft.directory/contacts/delete Delete contacts


Actions Description

microsoft.directory/contacts/basic/update Update basic properties on contacts

microsoft.directory/deletedItems.devices/delet Permanently delete devices, which can no


e longer be restored

microsoft.directory/deletedItems.devices/restor Restore soft deleted devices to original state


e

microsoft.directory/devices/create Create devices (enroll in Azure AD)

microsoft.directory/devices/delete Delete devices from Azure AD

microsoft.directory/devices/disable Disable devices in Azure AD

microsoft.directory/devices/enable Enable devices in Azure AD

microsoft.directory/devices/basic/update Update basic properties on devices

microsoft.directory/devices/extensionAttribute Update the extensionAttribute1 to


Set1/update extensionAttribute5 properties on devices

microsoft.directory/devices/extensionAttribute Update the extensionAttribute6 to


Set2/update extensionAttribute10 properties on devices

microsoft.directory/devices/extensionAttribute Update the extensionAttribute11 to


Set3/update extensionAttribute15 properties on devices

microsoft.directory/devices/registeredOwners/ Update registered owners of devices


update

microsoft.directory/devices/registeredUsers/up Update registered users of devices


date

microsoft.directory/deviceLocalCredentials/pas Read all properties of the backed up local


sword/read administrator account credentials for Azure AD
joined devices, including the password

microsoft.directory/deviceManagementPolicies Read standard properties on device


/standard/read management application policies

microsoft.directory/deviceRegistrationPolicy/sta Read standard properties on device registration


ndard/read policies

microsoft.directory/groups/hiddenMembers/re Read hidden members of Security groups and


ad Microsoft 365 groups, including role-assignable
groups

microsoft.directory/groups.security/create Create Security groups, excluding role-


assignable groups
Actions Description

microsoft.directory/groups.security/delete Delete Security groups, excluding role-


assignable groups

microsoft.directory/groups.security/basic/updat Update basic properties on Security groups,


e excluding role-assignable groups

microsoft.directory/groups.security/classificatio Update the classification property on Security


n/update groups, excluding role-assignable groups

microsoft.directory/groups.security/dynamicMe Update the dynamic membership rule on


mbershipRule/update Security groups, excluding role-assignable
groups

microsoft.directory/groups.security/members/u Update members of Security groups, excluding


pdate role-assignable groups

microsoft.directory/groups.security/owners/up Update owners of Security groups, excluding


date role-assignable groups

microsoft.directory/groups.security/visibility/up Update the visibility property on Security


date groups, excluding role-assignable groups

microsoft.directory/users/basic/update Update basic properties on users

microsoft.directory/users/manager/update Update manager for users

microsoft.directory/users/photo/update Update photo of users

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.cloudPC/allEntities/allProperties/allTa Manage all aspects of Windows 365


sks

microsoft.intune/allEntities/allTasks Manage all aspects of Microsoft Intune

microsoft.office365.organizationalMessages/all Read all aspects of Microsoft 365


Entities/allProperties/read Organizational Messages

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.directory/groups.security/create Create Security groups, excluding role-


assignable groups

microsoft.directory/groups.security/createAsO Create Security groups, excluding role-


wner assignable groups. Creator is added as the first
owner.

microsoft.directory/groups.security/delete Delete Security groups, excluding role-


assignable groups

microsoft.directory/groups.security/basic/updat Update basic properties on Security groups,


e excluding role-assignable groups

microsoft.directory/groups.security/members/u Update members of Security groups, excluding


pdate role-assignable groups
Actions Description

microsoft.directory/groups.security/owners/up Update owners of Security groups, excluding


date role-assignable groups

microsoft.office365.knowledge/contentUnderst Read and update all properties of content


anding/allProperties/allTasks understanding in Microsoft 365 admin center

microsoft.office365.knowledge/knowledgeNet Read and update all properties of knowledge


work/allProperties/allTasks network in Microsoft 365 admin center

microsoft.office365.knowledge/learningSources Manage learning sources and all their


/allProperties/allTasks properties in Learning App.

microsoft.office365.protectionCenter/sensitivity Read all properties of sensitivity labels in the


Labels/allProperties/read Security and Compliance centers

microsoft.office365.sharePoint/allEntities/allTas Create and delete all resources, and read and


ks update standard properties in SharePoint

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.directory/groups.security/create Create Security groups, excluding role-


assignable groups

microsoft.directory/groups.security/createAsO Create Security groups, excluding role-


wner assignable groups. Creator is added as the first
owner.

microsoft.directory/groups.security/delete Delete Security groups, excluding role-


assignable groups

microsoft.directory/groups.security/basic/updat Update basic properties on Security groups,


e excluding role-assignable groups
Actions Description

microsoft.directory/groups.security/members/u Update members of Security groups, excluding


pdate role-assignable groups

microsoft.directory/groups.security/owners/up Update owners of Security groups, excluding


date role-assignable groups

microsoft.office365.knowledge/contentUnderst Read analytics reports of content


anding/analytics/allProperties/read understanding in Microsoft 365 admin center

microsoft.office365.knowledge/knowledgeNet Manage topic visibility of knowledge network in


work/topicVisibility/allProperties/allTasks Microsoft 365 admin center

microsoft.office365.sharePoint/allEntities/allTas Create and delete all resources, and read and


ks update standard properties in SharePoint

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.directory/groups/assignLicense Assign product licenses to groups for group-


based licensing

microsoft.directory/groups/reprocessLicenseAs Reprocess license assignments for group-based


signment licensing

microsoft.directory/users/assignLicense Manage user licenses

microsoft.directory/users/reprocessLicenseAssi Reprocess license assignments for users


gnment
Actions Description

microsoft.directory/users/usageLocation/updat Update usage location of users


e

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Lifecycle Workflows Administrator


Assign the Lifecycle Workflows Administrator role to users who need to do the following
tasks:

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

microsoft.directory/lifecycleWorkflows/workflo Manage all aspects of lifecycle workflows and


ws/allProperties/allTasks tasks in Azure AD

Message Center Privacy Reader


Users in this role can monitor all notifications in the Message Center, including data
privacy messages. Message Center Privacy Readers get email notifications including
those related to data privacy and they can unsubscribe using Message Center
Preferences. Only the Global Administrator and the Message Center Privacy Reader can
read data privacy messages. Additionally, this role contains the ability to view groups,
domains, and subscriptions. This role has no permission to view, create, or manage
service requests.

Actions Description
Actions Description

microsoft.office365.messageCenter/messages/r Read messages in Message Center in the


ead Microsoft 365 admin center, excluding security
messages

microsoft.office365.messageCenter/securityMe Read security messages in Message Center in


ssages/read the Microsoft 365 admin center

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Message Center Reader


Users in this role can monitor notifications and advisory health updates in Message
center for their organization on configured services such as Exchange, Intune, and
Microsoft Teams. Message Center Readers receive weekly email digests of posts,
updates, and can share message center posts in Microsoft 365. In Azure AD, users
assigned to this role will only have read-only access on Azure AD services such as users
and groups. This role has no access to view, create, or manage support tickets.

Actions Description

microsoft.office365.messageCenter/messages/r Read messages in Message Center in the


ead Microsoft 365 admin center, excluding security
messages

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Microsoft Hardware Warranty Administrator


Assign the Microsoft Hardware Warranty Administrator role to users who need to do the
following tasks:

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

microsoft.hardware.support/shippingAddress/a Create, read, update, and delete shipping


llProperties/allTasks addresses for Microsoft hardware warranty
claims, including shipping addresses created by
others

microsoft.hardware.support/shippingStatus/allP Read shipping status for open Microsoft


roperties/read hardware warranty claims

microsoft.hardware.support/warrantyClaims/all Create and manage all aspects of Microsoft


Properties/allTasks hardware warranty claims

microsoft.office365.messageCenter/messages/r Read messages in Message Center in the


ead Microsoft 365 admin center, excluding security
messages

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Microsoft Hardware Warranty Specialist


Assign the Microsoft Hardware Warranty Specialist role to users who need to do the
following tasks:

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

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
Actions Description

microsoft.hardware.support/shippingAddress/a Read shipping addresses for Microsoft


llProperties/read hardware warranty claims, including existing
shipping addresses created by others

microsoft.hardware.support/warrantyClaims/cre Create Microsoft hardware warranty claims


ateAsOwner where creator is the owner

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

microsoft.hardware.support/shippingStatus/allP Read shipping status for open Microsoft


roperties/read hardware warranty claims

microsoft.hardware.support/warrantyClaims/all Read Microsoft hardware warranty claims


Properties/read

Modern Commerce User


Do not use. This role is automatically assigned from Commerce, and is not intended or
supported for any other use. See details below.

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.

When is the Modern Commerce User role assigned?

Self-service purchase in Microsoft 365 admin center – Self-service purchase gives


users a chance to try out new products by buying or signing up for them on their
own. These products are managed in the admin center. Users who make a self-
service purchase are assigned a role in the commerce system, and the Modern
Commerce User role so they can manage their purchases in admin center. Admins
can block self-service purchases (for Power BI, Power Apps, Power automate)
through PowerShell. For more information, see Self-service purchase FAQ.
Purchases from Microsoft commercial marketplace – Similar to self-service
purchase, when a user buys a product or service from Microsoft AppSource or
Azure Marketplace, the Modern Commerce User role is assigned if they don’t have
the Global Administrator or Billing Administrator role. In some cases, users might
be blocked from making these purchases. For more information, see Microsoft
commercial marketplace.
Proposals from Microsoft – A proposal is a formal offer from Microsoft for your
organization to buy Microsoft products and services. When the person who is
accepting the proposal doesn’t have a Global Administrator or Billing
Administrator role in Azure AD, they are assigned both a commerce-specific role to
complete the proposal and the Modern Commerce User role to access admin
center. When they access the admin center they can only use features that are
authorized by their commerce-specific role.
Commerce-specific roles – Some users are assigned commerce-specific roles. If a
user isn't a Global Administrator or Billing Administrator, they get the Modern
Commerce User role so they can 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

microsoft.commerce.volumeLicenseServiceCent Manage all aspects of Volume Licensing Service


er/allEntities/allTasks Center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/basic/r Read basic properties on all resources in the


ead Microsoft 365 admin center

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

microsoft.office365.network/locations/allProper Manage all aspects of network locations


ties/allTasks

microsoft.office365.network/performance/allPr Read all network performance properties in the


operties/read Microsoft 365 admin center

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Office Apps Administrator


Users in this role can manage Microsoft 365 apps' cloud settings. This includes
managing cloud policies, self-service download management and the ability to view
Office apps related report. This role additionally grants the ability to manage support
tickets, and monitor service health within the main admin center. Users assigned to this
role can also manage communication of new features in Office apps.

Actions Description

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.messageCenter/messages/r Read messages in Message Center in the


ead Microsoft 365 admin center, excluding security
messages

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.userCommunication/allEntit Read and update what's new messages visibility


ies/allTasks

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center
Organizational Messages Writer
Assign the Organizational Messages Writer role to users who need to do the following
tasks:

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

microsoft.office365.organizationalMessages/all Manage all authoring aspects of Microsoft 365


Entities/allProperties/allTasks Organizational Messages

microsoft.office365.usageReports/allEntities/sta Read tenant-level aggregated Office 365 usage


ndard/read reports

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Partner Tier1 Support


Do not use. This role has been deprecated and will be removed from Azure AD in the
future. This role is intended for use by a small number of Microsoft resale partners, and
is not intended for general use.

) 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

microsoft.directory/applications/appRoles/upd Update the appRoles property on all types of


ate applications

microsoft.directory/applications/audience/upda Update the audience property for applications


te
Actions Description

microsoft.directory/applications/authentication Update authentication on all types of


/update applications

microsoft.directory/applications/basic/update Update basic properties for applications

microsoft.directory/applications/credentials/up Update application credentials


date

microsoft.directory/applications/notes/update Update notes of applications

microsoft.directory/applications/owners/updat Update owners of applications


e

microsoft.directory/applications/permissions/u Update exposed permissions and required


pdate permissions on all types of applications

microsoft.directory/applications/policies/updat Update policies of applications


e

microsoft.directory/applications/tag/update Update tags of applications

microsoft.directory/contacts/create Create contacts

microsoft.directory/contacts/delete Delete contacts

microsoft.directory/contacts/basic/update Update basic properties on contacts

microsoft.directory/deletedItems.groups/restor Restore soft deleted groups to original state


e

microsoft.directory/deletedItems.users/restore Restore soft deleted users to original state

microsoft.directory/groups/create Create Security groups and Microsoft 365


groups, excluding role-assignable groups

microsoft.directory/groups/delete Delete Security groups and Microsoft 365


groups, excluding role-assignable groups

microsoft.directory/groups/restore Restore groups from soft-deleted container

microsoft.directory/groups/members/update Update members of Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/groups/owners/update Update owners of Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/oAuth2PermissionGrants/all Create and delete OAuth 2.0 permission grants,


Properties/allTasks and read and update all properties
Actions Description

microsoft.directory/servicePrincipals/appRoleAs Update service principal role assignments


signedTo/update

microsoft.directory/users/assignLicense Manage user licenses

microsoft.directory/users/create Add users

microsoft.directory/users/delete Delete users

microsoft.directory/users/disable Disable users

microsoft.directory/users/enable Enable users

microsoft.directory/users/invalidateAllRefreshT Force sign-out by invalidating user refresh


okens tokens

microsoft.directory/users/restore Restore deleted users

microsoft.directory/users/basic/update Update basic properties on users

microsoft.directory/users/manager/update Update manager for users

microsoft.directory/users/password/update Reset passwords for all users

microsoft.directory/users/photo/update Update photo of users

microsoft.directory/users/userPrincipalName/u Update User Principal Name of users


pdate

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Partner Tier2 Support


Do not use. This role has been deprecated and will be removed from Azure AD in the
future. This role is intended for use by a small number of Microsoft resale partners, and
is not intended for general use.

) 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

microsoft.directory/applications/appRoles/upd Update the appRoles property on all types of


ate applications

microsoft.directory/applications/audience/upda Update the audience property for applications


te

microsoft.directory/applications/authentication Update authentication on all types of


/update applications

microsoft.directory/applications/basic/update Update basic properties for applications

microsoft.directory/applications/credentials/up Update application credentials


date

microsoft.directory/applications/notes/update Update notes of applications

microsoft.directory/applications/owners/updat Update owners of applications


e

microsoft.directory/applications/permissions/u Update exposed permissions and required


pdate permissions on all types of applications

microsoft.directory/applications/policies/updat Update policies of applications


e

microsoft.directory/applications/tag/update Update tags of applications

microsoft.directory/contacts/create Create contacts

microsoft.directory/contacts/delete Delete contacts

microsoft.directory/contacts/basic/update Update basic properties on contacts

microsoft.directory/deletedItems.groups/restor Restore soft deleted groups to original state


e

microsoft.directory/deletedItems.users/restore Restore soft deleted users to original state

microsoft.directory/domains/allProperties/allTa Create and delete domains, and read and


sks update all properties
Actions Description

microsoft.directory/groups/create Create Security groups and Microsoft 365


groups, excluding role-assignable groups

microsoft.directory/groups/delete Delete Security groups and Microsoft 365


groups, excluding role-assignable groups

microsoft.directory/groups/restore Restore groups from soft-deleted container

microsoft.directory/groups/members/update Update members of Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/groups/owners/update Update owners of Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/oAuth2PermissionGrants/all Create and delete OAuth 2.0 permission grants,


Properties/allTasks and read and update all properties

microsoft.directory/organization/basic/update Update basic properties on organization

microsoft.directory/roleAssignments/allProperti Create and delete role assignments, and read


es/allTasks and update all role assignment properties

microsoft.directory/roleDefinitions/allProperties Create and delete role definitions, and read and


/allTasks update all properties

microsoft.directory/scopedRoleMemberships/al Create and delete scopedRoleMemberships,


lProperties/allTasks and read and update all properties

microsoft.directory/servicePrincipals/appRoleAs Update service principal role assignments


signedTo/update

microsoft.directory/subscribedSkus/standard/re Read basic properties on subscriptions


ad

microsoft.directory/users/assignLicense Manage user licenses

microsoft.directory/users/create Add users

microsoft.directory/users/delete Delete users

microsoft.directory/users/disable Disable users

microsoft.directory/users/enable Enable users

microsoft.directory/users/invalidateAllRefreshT Force sign-out by invalidating user refresh


okens tokens

microsoft.directory/users/restore Restore deleted users


Actions Description

microsoft.directory/users/basic/update Update basic properties on users

microsoft.directory/users/manager/update Update manager for users

microsoft.directory/users/password/update Reset passwords for all users

microsoft.directory/users/photo/update Update photo of users

microsoft.directory/users/userPrincipalName/u Update User Principal Name of users


pdate

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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.

Users with this role cannot do the following:

Cannot change the credentials or reset MFA for members and owners of a role-
assignable group.

Actions Description

microsoft.directory/users/password/update Reset passwords for all users

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center
Permissions Management Administrator
Assign the Permissions Management Administrator role to users who need to do the
following tasks:

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

microsoft.permissionsManagement/allEntities/a Manage all aspects of Entra Permissions


llProperties/allTasks Management

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

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

microsoft.powerApps.powerBI/allEntities/allTas Manage all aspects of Power BI


ks
Power Platform Administrator
Users in this role can create and manage all aspects of environments, Power Apps,
Flows, Data Loss Prevention policies. Additionally, users with this role have the ability to
manage support tickets and monitor service health.

Actions Description

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.dynamics365/allEntities/allTasks Manage all aspects of Dynamics 365

microsoft.flow/allEntities/allTasks Manage all aspects of Microsoft Power


Automate

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

microsoft.powerApps/allEntities/allTasks Manage all aspects of Power Apps

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

microsoft.azure.print/allEntities/allProperties/all Create and delete printers and connectors, and


Tasks read and update all properties in Microsoft
Print

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

microsoft.azure.print/connectors/allProperties/r Read all properties of connectors in Microsoft


ead Print

microsoft.azure.print/printers/allProperties/rea Read all properties of printers in Microsoft Print


d

microsoft.azure.print/printers/register Register printers in Microsoft Print

microsoft.azure.print/printers/unregister Unregister printers in Microsoft Print

microsoft.azure.print/printers/basic/update Update basic properties of printers in Microsoft


Print

Privileged Authentication Administrator


Assign the Privileged Authentication Administrator role to users who need to do the
following:

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.

Users with this role cannot do the following:

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

Authentication Yes for Yes for No No No Yes for Yes for


Administrator some some some some
users users users users

Privileged Yes for Yes for No No No Yes for all Yes for
Authentication all users all users users all
Administrator users

Authentication No No Yes Yes Yes No No


Policy
Administrator

User No No No No No Yes for Yes for


Administrator some some
users 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:

Application Registration and Enterprise Application owners, who can manage


credentials of apps they own. Those apps may have privileged permissions in
Azure AD and elsewhere not granted to Authentication Administrators.
Through this path an Authentication Administrator can assume the identity of
an application owner and then further assume the identity of a privileged
application by updating the credentials for the application.
Azure subscription owners, who may have access to sensitive or private
information or critical configuration in Azure.
Security Group and Microsoft 365 group owners, who can manage group
membership. Those groups may grant access to sensitive or private
information or critical configuration in Azure AD and elsewhere.
Administrators in other services outside of Azure AD like Exchange Online,
Microsoft 365 Defender portal, and Microsoft Purview compliance portal, and
human resources systems.
Non-administrators like executives, legal counsel, and human resources
employees who may have access to sensitive or private information.

Actions Description

microsoft.directory/users/authenticationMetho Create authentication methods for users


ds/create

microsoft.directory/users/authenticationMetho Delete authentication methods for users


ds/delete

microsoft.directory/users/authenticationMetho Read standard properties of authentication


ds/standard/read methods for users

microsoft.directory/users/authenticationMetho Update basic properties of authentication


ds/basic/update methods for users

microsoft.directory/deletedItems.users/restore Restore soft deleted users to original state

microsoft.directory/users/delete Delete users

microsoft.directory/users/disable Disable users

microsoft.directory/users/enable Enable users

microsoft.directory/users/invalidateAllRefreshT Force sign-out by invalidating user refresh


okens tokens

microsoft.directory/users/restore Restore deleted users

microsoft.directory/users/basic/update Update basic properties on users

microsoft.directory/users/authorizationInfo/up Update the multivalued Certificate user IDs


date property of users

microsoft.directory/users/manager/update Update manager for users

microsoft.directory/users/password/update Reset passwords for all users

microsoft.directory/users/userPrincipalName/u Update User Principal Name of users


pdate

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center
Actions Description

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Privileged Role Administrator


Users with this role can manage role assignments in Azure Active Directory, as well as
within Azure AD Privileged Identity Management. They can create and manage groups
that can be assigned to Azure AD roles. In addition, this role allows management of all
aspects of Privileged Identity Management and administrative units.

) 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

microsoft.directory/accessReviews/definitions.a Read all properties of access reviews of


pplications/allProperties/read application role assignments in Azure AD

microsoft.directory/accessReviews/definitions.d Manage access reviews for Azure AD role


irectoryRoles/allProperties/allTasks assignments

microsoft.directory/accessReviews/definitions.g Update all properties of access reviews for


roupsAssignableToRoles/allProperties/update membership in groups that are assignable to
Azure AD roles

microsoft.directory/accessReviews/definitions.g Create access reviews for membership in


roupsAssignableToRoles/create groups that are assignable to Azure AD roles

microsoft.directory/accessReviews/definitions.g Delete access reviews for membership in


roupsAssignableToRoles/delete groups that are assignable to Azure AD roles

microsoft.directory/accessReviews/definitions.g Read all properties of access reviews for


roups/allProperties/read membership in Security and Microsoft 365
groups, including role-assignable groups.
Actions Description

microsoft.directory/administrativeUnits/allProp Create and manage administrative units


erties/allTasks (including members)

microsoft.directory/authorizationPolicy/allProp Manage all aspects of authorization policy


erties/allTasks

microsoft.directory/directoryRoles/allProperties Create and delete directory roles, and read and


/allTasks update all properties

microsoft.directory/groupsAssignableToRoles/c Create role-assignable groups


reate

microsoft.directory/groupsAssignableToRoles/d Delete role-assignable groups


elete

microsoft.directory/groupsAssignableToRoles/r Restore role-assignable groups


estore

microsoft.directory/groupsAssignableToRoles/a Update role-assignable groups


llProperties/update

microsoft.directory/oAuth2PermissionGrants/all Create and delete OAuth 2.0 permission grants,


Properties/allTasks and read and update all properties

microsoft.directory/privilegedIdentityManagem Create and delete all resources, and read and


ent/allProperties/allTasks update standard properties in Privileged
Identity Management

microsoft.directory/roleAssignments/allProperti Create and delete role assignments, and read


es/allTasks and update all role assignment properties

microsoft.directory/roleDefinitions/allProperties Create and delete role definitions, and read and


/allTasks update all properties

microsoft.directory/scopedRoleMemberships/al Create and delete scopedRoleMemberships,


lProperties/allTasks and read and update all properties

microsoft.directory/servicePrincipals/appRoleAs Update service principal role assignments


signedTo/update

microsoft.directory/servicePrincipals/permissio Update permissions of service principals


ns/update

microsoft.directory/servicePrincipals/managePe Grant consent for any permission to any


rmissionGrantsForAll.microsoft-company- application
admin

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center
Reports Reader
Users with this role can view usage reporting data and the reports dashboard in
Microsoft 365 admin center and the adoption context pack in Power BI. Additionally, the
role provides access to all sign-in logs, audit logs, and activity reports in Azure AD and
data returned by the Microsoft Graph reporting API. A user assigned to the Reports
Reader role can access only relevant usage and adoption metrics. They don't have any
admin permissions to configure settings or access the product-specific admin centers
like Exchange. This role has no access to view, create, or manage support tickets.

Actions Description

microsoft.directory/auditLogs/allProperties/rea Read all properties on audit logs, including


d privileged properties

microsoft.directory/provisioningLogs/allPropert Read all properties of provisioning logs


ies/read

microsoft.directory/signInReports/allProperties/ Read all properties on sign-in reports, including


read privileged properties

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.office365.network/performance/allPr Read all network performance properties in the


operties/read Microsoft 365 admin center

microsoft.office365.usageReports/allEntities/all Read Office 365 usage reports


Properties/read

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.office365.messageCenter/messages/r Read messages in Message Center in the


ead Microsoft 365 admin center, excluding security
messages
Actions Description

microsoft.office365.search/content/manage Create and delete content, and read and


update all properties in Microsoft Search

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.office365.messageCenter/messages/r Read messages in Message Center in the


ead Microsoft 365 admin center, excluding security
messages

microsoft.office365.search/content/manage Create and delete content, and read and


update all properties in Microsoft Search

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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 365 Monitor security-related policies across Microsoft 365 services


Defender portal Manage security threats and alerts
View reports
In Can do

Identity All permissions of the Security Reader role


Protection Perform all Identity Protection operations except for resetting passwords

Privileged All permissions of the Security Reader role


Identity Cannot manage Azure AD role assignments or settings
Management

Microsoft Manage security policies


Purview View, investigate, and respond to security threats
compliance View reports
portal

Azure Monitor and respond to suspicious security activity


Advanced
Threat
Protection

Microsoft Assign roles


Defender for Manage machine groups
Endpoint Configure endpoint threat detection and automated remediation
View, investigate, and respond to alerts
View machines/device inventory

Intune Views user, device, enrollment, configuration, and application information


Cannot make changes to Intune

Microsoft Add admins, add policies and settings, upload logs and perform governance
Defender for actions
Cloud Apps

Microsoft 365 View the health of Microsoft 365 services


service health

Smart lockout Define the threshold and duration for lockouts when failed sign-in events
happen.

Password Configure custom banned password list or on-premises password protection.


Protection

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

microsoft.directory/applications/policies/updat Update policies of applications


e
Actions Description

microsoft.directory/auditLogs/allProperties/rea Read all properties on audit logs, including


d privileged properties

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.directory/bitlockerKeys/key/read Read bitlocker metadata and key on devices

microsoft.directory/crossTenantAccessPolicy/st Read basic properties of cross-tenant access


andard/read policy

microsoft.directory/crossTenantAccessPolicy/all Update allowed cloud endpoints of cross-


owedCloudEndpoints/update tenant access policy

microsoft.directory/crossTenantAccessPolicy/ba Update basic settings of cross-tenant access


sic/update policy

microsoft.directory/crossTenantAccessPolicy/de Read basic properties of the default cross-


fault/standard/read tenant access policy

microsoft.directory/crossTenantAccessPolicy/de Update Azure AD B2B collaboration settings of


fault/b2bCollaboration/update the default cross-tenant access policy

microsoft.directory/crossTenantAccessPolicy/de Update Azure AD B2B direct connect settings of


fault/b2bDirectConnect/update the default cross-tenant access policy

microsoft.directory/crossTenantAccessPolicy/de Update cross-cloud Teams meeting settings of


fault/crossCloudMeetings/update the default cross-tenant access policy

microsoft.directory/crossTenantAccessPolicy/de Update tenant restrictions of the default cross-


fault/tenantRestrictions/update tenant access policy

microsoft.directory/crossTenantAccessPolicy/pa Create cross-tenant access policy for partners


rtners/create

microsoft.directory/crossTenantAccessPolicy/pa Delete cross-tenant access policy for partners


rtners/delete

microsoft.directory/crossTenantAccessPolicy/pa Read basic properties of cross-tenant access


rtners/standard/read policy for partners

microsoft.directory/crossTenantAccessPolicy/pa Update Azure AD B2B collaboration settings of


rtners/b2bCollaboration/update cross-tenant access policy for partners

microsoft.directory/crossTenantAccessPolicy/pa Update Azure AD B2B direct connect settings of


rtners/b2bDirectConnect/update cross-tenant access policy for partners

microsoft.directory/crossTenantAccessPolicy/pa Update cross-cloud Teams meeting settings of


rtners/crossCloudMeetings/update cross-tenant access policy for partners
Actions Description

microsoft.directory/crossTenantAccessPolicy/pa Update tenant restrictions of cross-tenant


rtners/tenantRestrictions/update access policy for partners

microsoft.directory/deviceLocalCredentials/stan Read all properties of the backed up local


dard/read administrator account credentials for Azure AD
joined devices, except the password

microsoft.directory/domains/federation/update Update federation property of domains

microsoft.directory/domains/federationConfigu Read standard properties of federation


ration/standard/read configuration for domains

microsoft.directory/domains/federationConfigu Update basic federation configuration for


ration/basic/update domains

microsoft.directory/domains/federationConfigu Create federation configuration for domains


ration/create

microsoft.directory/domains/federationConfigu Delete federation configuration for domains


ration/delete

microsoft.directory/entitlementManagement/al Read all properties in Azure AD entitlement


lProperties/read management

microsoft.directory/identityProtection/allProper Read all resources in Azure AD Identity


ties/read Protection

microsoft.directory/identityProtection/allProper Update all resources in Azure AD Identity


ties/update Protection

microsoft.directory/namedLocations/create Create custom rules that define network


locations

microsoft.directory/namedLocations/delete Delete custom rules that define network


locations

microsoft.directory/namedLocations/standard/r Read basic properties of custom rules that


ead define network locations

microsoft.directory/namedLocations/basic/upd Update basic properties of custom rules that


ate define network locations

microsoft.directory/policies/create Create policies in Azure AD

microsoft.directory/policies/delete Delete policies in Azure AD

microsoft.directory/policies/basic/update Update basic properties on policies

microsoft.directory/policies/owners/update Update owners of policies


Actions Description

microsoft.directory/policies/tenantDefault/upd Update default organization policies


ate

microsoft.directory/conditionalAccessPolicies/cr Create conditional access policies


eate

microsoft.directory/conditionalAccessPolicies/d Delete conditional access policies


elete

microsoft.directory/conditionalAccessPolicies/st Read conditional access for policies


andard/read

microsoft.directory/conditionalAccessPolicies/o Read the owners of conditional access policies


wners/read

microsoft.directory/conditionalAccessPolicies/p Read the "applied to" property for conditional


olicyAppliedTo/read access policies

microsoft.directory/conditionalAccessPolicies/b Update basic properties for conditional access


asic/update policies

microsoft.directory/conditionalAccessPolicies/o Update owners for conditional access policies


wners/update

microsoft.directory/conditionalAccessPolicies/t Update the default tenant for conditional


enantDefault/update access policies

microsoft.directory/privilegedIdentityManagem Read all resources in Privileged Identity


ent/allProperties/read Management

microsoft.directory/provisioningLogs/allPropert Read all properties of provisioning logs


ies/read

microsoft.directory/resourceNamespaces/resou Update Conditional Access authentication


rceActions/authenticationContext/update context of Microsoft 365 role-based access
control (RBAC) resource actions

microsoft.directory/servicePrincipals/policies/u Update policies of service principals


pdate

microsoft.directory/signInReports/allProperties/ Read all properties on sign-in reports, including


read privileged properties

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks
Actions Description

microsoft.office365.protectionCenter/allEntities Read standard properties of all resources in the


/standard/read Security and Compliance centers

microsoft.office365.protectionCenter/allEntities Update basic properties of all resources in the


/basic/update Security and Compliance centers

microsoft.office365.protectionCenter/attackSim Create and manage attack payloads in Attack


ulator/payload/allProperties/allTasks Simulator

microsoft.office365.protectionCenter/attackSim Read reports of attack simulation, responses,


ulator/reports/allProperties/read and associated training

microsoft.office365.protectionCenter/attackSim Create and manage attack simulation templates


ulator/simulation/allProperties/allTasks in Attack Simulator

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

Microsoft All permissions of the Security Reader role


365 View, investigate, and respond to security threats alerts
Defender Manage security settings in Microsoft 365 Defender portal
portal

Identity All permissions of the Security Reader role


Protection Perform all Identity Protection operations except for configuring or changing risk-
based policies, resetting passwords, and configuring alert e-mails.

Privileged All permissions of the Security Reader role


Identity
Management
In Can do

Microsoft All permissions of the Security Reader role


Purview View, investigate, and respond to security alerts
compliance
portal

Microsoft All permissions of the Security Reader role


Defender for View, investigate, and respond to security alerts
Endpoint When you turn on role-based access control in Microsoft Defender for Endpoint,
users with read-only permissions such as the Security Reader role lose access until
they are assigned a Microsoft Defender for Endpoint role.

Intune All permissions of the Security Reader role

Microsoft All permissions of the Security Reader role


Defender for View, investigate, and respond to security alerts
Cloud Apps

Microsoft View the health of Microsoft 365 services


365 service
health

Actions Description

microsoft.directory/auditLogs/allProperties/rea Read all properties on audit logs, including


d privileged properties

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.directory/cloudAppSecurity/allProper Create and delete all resources, and read and


ties/allTasks update standard properties in Microsoft
Defender for Cloud Apps

microsoft.directory/identityProtection/allProper Create and delete all resources, and read and


ties/allTasks update standard properties in Azure AD
Identity Protection

microsoft.directory/privilegedIdentityManagem Read all resources in Privileged Identity


ent/allProperties/read Management

microsoft.directory/provisioningLogs/allPropert Read all properties of provisioning logs


ies/read

microsoft.directory/signInReports/allProperties/ Read all properties on sign-in reports, including


read privileged properties

microsoft.azure.advancedThreatProtection/allE Manage all aspects of Azure Advanced Threat


ntities/allTasks Protection
Actions Description

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.intune/allEntities/read Read all resources in Microsoft Intune

microsoft.office365.securityComplianceCenter/ Create and delete all resources, and read and


allEntities/allTasks update standard properties in the Office 365
Security & Compliance Center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.windows.defenderAdvancedThreatPr Manage all aspects of Microsoft Defender for


otection/allEntities/allTasks Endpoint

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

Microsoft View security-related policies across Microsoft 365 services


365 View security threats and alerts
Defender View reports
portal

Identity View all Identity Protection reports and Overview


Protection

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

Microsoft View security policies


Purview View and investigate security threats
compliance View reports
portal

Microsoft View and investigate alerts


Defender for When you turn on role-based access control in Microsoft Defender for Endpoint,
Endpoint users with read-only permissions such as the Security Reader role lose access until
they are assigned a Microsoft Defender for Endpoint role.

Intune Views user, device, enrollment, configuration, and application information. Cannot
make changes to Intune.

Microsoft Has read permissions.


Defender for
Cloud Apps

Microsoft View the health of Microsoft 365 services


365 service
health

Actions Description

microsoft.directory/accessReviews/definitions/a Read all properties of access reviews of all


llProperties/read reviewable resources in Azure AD

microsoft.directory/auditLogs/allProperties/rea Read all properties on audit logs, including


d privileged properties

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.directory/bitlockerKeys/key/read Read bitlocker metadata and key on devices

microsoft.directory/deviceLocalCredentials/stan Read all properties of the backed up local


dard/read administrator account credentials for Azure AD
joined devices, except the password

microsoft.directory/domains/federationConfigu Read standard properties of federation


ration/standard/read configuration for domains

microsoft.directory/entitlementManagement/al Read all properties in Azure AD entitlement


lProperties/read management

microsoft.directory/identityProtection/allProper Read all resources in Azure AD Identity


ties/read Protection

microsoft.directory/namedLocations/standard/r Read basic properties of custom rules that


ead define network locations
Actions Description

microsoft.directory/policies/standard/read Read basic properties on policies

microsoft.directory/policies/owners/read Read owners of policies

microsoft.directory/policies/policyAppliedTo/re Read policies.policyAppliedTo property


ad

microsoft.directory/conditionalAccessPolicies/st Read conditional access for policies


andard/read

microsoft.directory/conditionalAccessPolicies/o Read the owners of conditional access policies


wners/read

microsoft.directory/conditionalAccessPolicies/p Read the "applied to" property for conditional


olicyAppliedTo/read access policies

microsoft.directory/privilegedIdentityManagem Read all resources in Privileged Identity


ent/allProperties/read Management

microsoft.directory/provisioningLogs/allPropert Read all properties of provisioning logs


ies/read

microsoft.directory/signInReports/allProperties/ Read all properties on sign-in reports, including


read privileged properties

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.office365.protectionCenter/allEntities Read standard properties of all resources in the


/standard/read Security and Compliance centers

microsoft.office365.protectionCenter/attackSim Read all properties of attack payloads in Attack


ulator/payload/allProperties/read Simulator

microsoft.office365.protectionCenter/attackSim Read reports of attack simulation, responses,


ulator/reports/allProperties/read and associated training

microsoft.office365.protectionCenter/attackSim Read all properties of attack simulation


ulator/simulation/allProperties/read templates in Attack Simulator

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Service Support Administrator


Users with this role can create and manage support requests with Microsoft for Azure
and Microsoft 365 services, and view the service dashboard and message center in the
Azure portal and Microsoft 365 admin center. For more information, see About admin
roles in the Microsoft 365 admin center.

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

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.network/performance/allPr Read all network performance properties in the


operties/read Microsoft 365 admin center

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.directory/groups/hiddenMembers/re Read hidden members of Security groups and


ad Microsoft 365 groups, including role-assignable
groups

microsoft.directory/groups.unified/create Create Microsoft 365 groups, excluding role-


assignable groups

microsoft.directory/groups.unified/delete Delete Microsoft 365 groups, excluding role-


assignable groups

microsoft.directory/groups.unified/restore Restore Microsoft 365 groups from soft-deleted


container, excluding role-assignable groups

microsoft.directory/groups.unified/basic/updat Update basic properties on Microsoft 365


e groups, excluding role-assignable groups

microsoft.directory/groups.unified/members/u Update members of Microsoft 365 groups,


pdate excluding role-assignable groups

microsoft.directory/groups.unified/owners/upd Update owners of Microsoft 365 groups,


ate excluding role-assignable groups

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.network/performance/allPr Read all network performance properties in the


operties/read Microsoft 365 admin center

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.sharePoint/allEntities/allTas Create and delete all resources, and read and


ks update standard properties in SharePoint

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests
Actions Description

microsoft.office365.usageReports/allEntities/all Read Office 365 usage reports


Properties/read

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Skype for Business Administrator


Users with this role have global permissions within Microsoft Skype for Business, when
the service is present, as well as manage Skype-specific user attributes in Azure Active
Directory. Additionally, this role grants the ability to manage support tickets and
monitor service health, and to access the Teams and Skype for Business admin center.
The account must also be licensed for Teams or it can't run Teams PowerShell cmdlets.
For more information, see Skype for Business Online Admin and Teams licensing
information at Skype for Business add-on licensing.

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

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.skypeForBusiness/allEntities Manage all aspects of Skype for Business


/allTasks Online

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.usageReports/allEntities/all Read Office 365 usage reports


Properties/read
Actions Description

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

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

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.directory/groups/hiddenMembers/re Read hidden members of Security groups and


ad Microsoft 365 groups, including role-assignable
groups

microsoft.directory/groups.unified/create Create Microsoft 365 groups, excluding role-


assignable groups

microsoft.directory/groups.unified/delete Delete Microsoft 365 groups, excluding role-


assignable groups

microsoft.directory/groups.unified/restore Restore Microsoft 365 groups from soft-deleted


container, excluding role-assignable groups

microsoft.directory/groups.unified/basic/updat Update basic properties on Microsoft 365


e groups, excluding role-assignable groups

microsoft.directory/groups.unified/members/u Update members of Microsoft 365 groups,


pdate excluding role-assignable groups

microsoft.directory/groups.unified/owners/upd Update owners of Microsoft 365 groups,


ate excluding role-assignable groups

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks
Actions Description

microsoft.office365.network/performance/allPr Read all network performance properties in the


operties/read Microsoft 365 admin center

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.skypeForBusiness/allEntities Manage all aspects of Skype for Business


/allTasks Online

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.usageReports/allEntities/all Read Office 365 usage reports


Properties/read

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

microsoft.teams/allEntities/allProperties/allTask Manage all resources in Teams


s

microsoft.directory/crossTenantAccessPolicy/st Read basic properties of cross-tenant access


andard/read policy

microsoft.directory/crossTenantAccessPolicy/all Update allowed cloud endpoints of cross-


owedCloudEndpoints/update tenant access policy

microsoft.directory/crossTenantAccessPolicy/de Read basic properties of the default cross-


fault/standard/read tenant access policy

microsoft.directory/crossTenantAccessPolicy/de Update cross-cloud Teams meeting settings of


fault/crossCloudMeetings/update the default cross-tenant access policy

microsoft.directory/crossTenantAccessPolicy/pa Create cross-tenant access policy for partners


rtners/create

microsoft.directory/crossTenantAccessPolicy/pa Read basic properties of cross-tenant access


rtners/standard/read policy for partners

microsoft.directory/crossTenantAccessPolicy/pa Update cross-cloud Teams meeting settings of


rtners/crossCloudMeetings/update cross-tenant access policy for partners

Teams Communications Administrator


Users in this role can manage aspects of the Microsoft Teams workload related to voice
& telephony. This includes the management tools for telephone number assignment,
voice and meeting policies, and full access to the call analytics toolset.
Actions Description

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.skypeForBusiness/allEntities Manage all aspects of Skype for Business


/allTasks Online

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.usageReports/allEntities/all Read Office 365 usage reports


Properties/read

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

microsoft.teams/callQuality/allProperties/read Read all data in the Call Quality Dashboard


(CQD)

microsoft.teams/meetings/allProperties/allTask Manage meetings including meeting policies,


s configurations, and conference bridges

microsoft.teams/voice/allProperties/allTasks Manage voice including calling policies and


phone number inventory and assignment

Teams Communications Support Engineer


Users in this role can troubleshoot communication issues within Microsoft Teams &
Skype for Business using the user call troubleshooting tools in the Microsoft Teams &
Skype for Business admin center. Users in this role can view full call record information
for all participants involved. This role has no access to view, create, or manage support
tickets.

Actions Description

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy
Actions Description

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.skypeForBusiness/allEntities Manage all aspects of Skype for Business


/allTasks Online

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

microsoft.teams/callQuality/allProperties/read Read all data in the Call Quality Dashboard


(CQD)

Teams Communications Support Specialist


Users in this role can troubleshoot communication issues within Microsoft Teams &
Skype for Business using the user call troubleshooting tools in the Microsoft Teams &
Skype for Business admin center. Users in this role can only view user details in the call
for the specific user they have looked up. This role has no access to view, create, or
manage support tickets.

Actions Description

microsoft.directory/authorizationPolicy/standar Read standard properties of authorization


d/read policy

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.skypeForBusiness/allEntities Manage all aspects of Skype for Business


/allTasks Online

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

microsoft.teams/callQuality/standard/read Read basic data in the Call Quality Dashboard


(CQD)

Teams Devices Administrator


Users with this role can manage Teams-certified devices from the Teams admin center.
This role allows viewing all devices at single glance, with ability to search and filter
devices. The user can check details of each device including logged-in account, make
and model of the device. The user can change the settings on the device and update the
software versions. This role does not grant permissions to check Teams activity and call
quality of the device.

Actions Description

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

microsoft.teams/devices/standard/read Manage all aspects of Teams-certified devices


including configuration policies

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

microsoft.directory/tenantManagement/tenant Create new tenants in Azure Active Directory


s/create

Usage Summary Reports Reader


Users with this role can access tenant level aggregated data and associated insights in
Microsoft 365 admin center for Usage and Productivity Score but cannot access any user
level details or insights. In Microsoft 365 admin center for the two reports, we
differentiate between tenant level aggregated data and user level details. This role gives
an extra layer of protection on individual user identifiable data, which was requested by
both customers and legal teams.
Actions Description

microsoft.office365.network/performance/allPr Read all network performance properties in the


operties/read Microsoft 365 admin center

microsoft.office365.usageReports/allEntities/sta Read tenant-level aggregated Office 365 usage


ndard/read reports

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

User Administrator
Assign the User Administrator role to users who need to do the following:

Permission More information

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

Disable or enable some users Who can perform sensitive


actions

Delete or restore some users Who can perform sensitive


actions

Create and manage user views

Create and manage all groups

Assign and read licenses for all users, including all administrators

Reset passwords Who can reset passwords

Invalidate refresh tokens Who can reset passwords

Update (FIDO) device keys

Update password expiration policies

Create and manage support tickets in Azure and the Microsoft 365
admin center

Monitor service health


Users with this role cannot do the following:

Cannot manage MFA.


Cannot change the credentials or reset MFA for members and owners of a role-
assignable group.
Cannot manage shared mailboxes.

) 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:

Application Registration and Enterprise Application owners, who can manage


credentials of apps they own. Those apps may have privileged permissions in
Azure AD and elsewhere not granted to User Administrators. Through this
path a User Administrator may be able to assume the identity of an
application owner and then further assume the identity of a privileged
application by updating the credentials for the application.
Azure subscription owners, who may have access to sensitive or private
information or critical configuration in Azure.
Security Group and Microsoft 365 group owners, who can manage group
membership. Those groups may grant access to sensitive or private
information or critical configuration in Azure AD and elsewhere.
Administrators in other services outside of Azure AD like Exchange Online,
Microsoft 365 Defender portal, Microsoft Purview compliance portal, and
human resources systems.
Non-administrators like executives, legal counsel, and human resources
employees who may have access to sensitive or private information.

Actions Description

microsoft.directory/accessReviews/definitions.a Manage access reviews of application role


pplications/allProperties/allTasks assignments in Azure AD

microsoft.directory/accessReviews/definitions.d Read all properties of access reviews for Azure


irectoryRoles/allProperties/read AD role assignments

microsoft.directory/accessReviews/definitions.e Manage access reviews for access package


ntitlementManagement/allProperties/allTasks assignments in entitlement management
Actions Description

microsoft.directory/accessReviews/definitions.g Update all properties of access reviews for


roups/allProperties/update membership in Security and Microsoft 365
groups, excluding role-assignable groups.

microsoft.directory/accessReviews/definitions.g Create access reviews for membership in


roups/create Security and Microsoft 365 groups.

microsoft.directory/accessReviews/definitions.g Delete access reviews for membership in


roups/delete Security and Microsoft 365 groups.

microsoft.directory/accessReviews/definitions.g Read all properties of access reviews for


roups/allProperties/read membership in Security and Microsoft 365
groups, including role-assignable groups.

microsoft.directory/contacts/create Create contacts

microsoft.directory/contacts/delete Delete contacts

microsoft.directory/contacts/basic/update Update basic properties on contacts

microsoft.directory/deletedItems.groups/restor Restore soft deleted groups to original state


e

microsoft.directory/deletedItems.users/restore Restore soft deleted users to original state

microsoft.directory/entitlementManagement/al Create and delete resources, and read and


lProperties/allTasks update all properties in Azure AD entitlement
management

microsoft.directory/groups/assignLicense Assign product licenses to groups for group-


based licensing

microsoft.directory/groups/create Create Security groups and Microsoft 365


groups, excluding role-assignable groups

microsoft.directory/groups/delete Delete Security groups and Microsoft 365


groups, excluding role-assignable groups

microsoft.directory/groups/hiddenMembers/re Read hidden members of Security groups and


ad Microsoft 365 groups, including role-assignable
groups

microsoft.directory/groups/reprocessLicenseAs Reprocess license assignments for group-based


signment licensing

microsoft.directory/groups/restore Restore groups from soft-deleted container

microsoft.directory/groups/basic/update Update basic properties on Security groups and


Microsoft 365 groups, excluding role-
assignable groups
Actions Description

microsoft.directory/groups/classification/updat Update the classification property on Security


e groups and Microsoft 365 groups, excluding
role-assignable groups

microsoft.directory/groups/dynamicMembershi Update the dynamic membership rule on


pRule/update Security groups and Microsoft 365 groups,
excluding role-assignable groups

microsoft.directory/groups/groupType/update Update properties that would affect the group


type of Security groups and Microsoft 365
groups, excluding role-assignable groups

microsoft.directory/groups/members/update Update members of Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/groups/onPremWriteBack/ Update Azure Active Directory groups to be


update written back to on-premises with Azure AD
Connect

microsoft.directory/groups/owners/update Update owners of Security groups and


Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/groups/settings/update Update settings of groups

microsoft.directory/groups/visibility/update Update the visibility property of Security groups


and Microsoft 365 groups, excluding role-
assignable groups

microsoft.directory/oAuth2PermissionGrants/all Create and delete OAuth 2.0 permission grants,


Properties/allTasks and read and update all properties

microsoft.directory/policies/standard/read Read basic properties on policies

microsoft.directory/servicePrincipals/appRoleAs Update service principal role assignments


signedTo/update

microsoft.directory/users/assignLicense Manage user licenses

microsoft.directory/users/create Add users

microsoft.directory/users/delete Delete users

microsoft.directory/users/disable Disable users

microsoft.directory/users/enable Enable users

microsoft.directory/users/inviteGuest Invite guest users


Actions Description

microsoft.directory/users/invalidateAllRefreshT Force sign-out by invalidating user refresh


okens tokens

microsoft.directory/users/reprocessLicenseAssi Reprocess license assignments for users


gnment

microsoft.directory/users/restore Restore deleted users

microsoft.directory/users/basic/update Update basic properties on users

microsoft.directory/users/manager/update Update manager for users

microsoft.directory/users/password/update Reset passwords for all users

microsoft.directory/users/photo/update Update photo of users

microsoft.directory/users/sponsors/update Update sponsors of users

microsoft.directory/users/usageLocation/updat Update usage location of users


e

microsoft.directory/users/userPrincipalName/u Update User Principal Name of users


pdate

microsoft.azure.serviceHealth/allEntities/allTask Read and configure Azure Service Health


s

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Virtual Visits Administrator


Users with this role can do the following tasks:

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

microsoft.virtualVisits/allEntities/allProperties/al Manage and share Virtual Visits information


lTasks and metrics from admin centers or the Virtual
Visits app

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Viva Goals Administrator


Assign the Viva Goals Administrator role to users who need to do the following tasks:

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

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Windows 365 Administrator


Users with this role have global permissions on Windows 365 resources, 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.
This role can create and manage security groups, but does not have administrator rights
over Microsoft 365 groups. That means administrators cannot update owners or
memberships of Microsoft 365 groups in the organization. However, they can manage
the Microsoft 365 group they create, which is a part of their end-user privileges. So, any
Microsoft 365 group (not security group) they create is counted against their quota of
250.

Assign the Windows 365 Administrator role to users who need to do the following tasks:

Manage Windows 365 Cloud PCs in Microsoft Intune


Enroll and manage devices in Azure AD, including assigning users and policies
Create and manage security groups, but not role-assignable groups
View basic properties in the Microsoft 365 admin center
Read usage reports in the Microsoft 365 admin center
Create and manage support tickets in Azure and the Microsoft 365 admin center

Actions Description

microsoft.directory/deletedItems.devices/delet Permanently delete devices, which can no


e longer be restored

microsoft.directory/deletedItems.devices/restor Restore soft deleted devices to original state


e

microsoft.directory/devices/create Create devices (enroll in Azure AD)

microsoft.directory/devices/delete Delete devices from Azure AD

microsoft.directory/devices/disable Disable devices in Azure AD

microsoft.directory/devices/enable Enable devices in Azure AD

microsoft.directory/devices/basic/update Update basic properties on devices

microsoft.directory/devices/extensionAttribute Update the extensionAttribute1 to


Set1/update extensionAttribute5 properties on devices

microsoft.directory/devices/extensionAttribute Update the extensionAttribute6 to


Set2/update extensionAttribute10 properties on devices

microsoft.directory/devices/extensionAttribute Update the extensionAttribute11 to


Set3/update extensionAttribute15 properties on devices

microsoft.directory/devices/registeredOwners/ Update registered owners of devices


update

microsoft.directory/devices/registeredUsers/up Update registered users of devices


date
Actions Description

microsoft.directory/groups.security/create Create Security groups, excluding role-


assignable groups

microsoft.directory/groups.security/delete Delete Security groups, excluding role-


assignable groups

microsoft.directory/groups.security/basic/updat Update basic properties on Security groups,


e excluding role-assignable groups

microsoft.directory/groups.security/classificatio Update the classification property on Security


n/update groups, excluding role-assignable groups

microsoft.directory/groups.security/dynamicMe Update the dynamic membership rule on


mbershipRule/update Security groups, excluding role-assignable
groups

microsoft.directory/groups.security/members/u Update members of Security groups, excluding


pdate role-assignable groups

microsoft.directory/groups.security/owners/up Update owners of Security groups, excluding


date role-assignable groups

microsoft.directory/groups.security/visibility/up Update the visibility property on Security


date groups, excluding role-assignable groups

microsoft.directory/deviceManagementPolicies Read standard properties on device


/standard/read management application policies

microsoft.directory/deviceRegistrationPolicy/sta Read standard properties on device registration


ndard/read policies

microsoft.azure.supportTickets/allEntities/allTas Create and manage Azure support tickets


ks

microsoft.cloudPC/allEntities/allProperties/allTa Manage all aspects of Windows 365


sks

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.usageReports/allEntities/all Read Office 365 usage reports


Properties/read

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

Windows Update Deployment Administrator


Users in this role can create and manage all aspects of Windows Update deployments
through the Windows Update for Business deployment service. The deployment service
enables users to define settings for when and how updates are deployed, and specify
which updates are offered to groups of devices in their tenant. It also allows users to
monitor the update progress.

Actions Description

microsoft.windows.updatesDeployments/allEnti Read and configure all aspects of Windows


ties/allProperties/allTasks Update Service

Yammer Administrator
Assign the Yammer Administrator role to users who need to do the following tasks:

Manage all aspects of Yammer


Create, manage, and restore Microsoft 365 Groups, but not role-assignable groups
View the hidden members of Security groups and Microsoft 365 groups, including
role assignable groups
Read usage reports in the Microsoft 365 admin center
Create and manage service requests in the Microsoft 365 admin center
View announcements in the Message center, but not security announcements
View service health

Learn more

Actions Description

microsoft.directory/groups/hiddenMembers/re Read hidden members of Security groups and


ad Microsoft 365 groups, including role-assignable
groups

microsoft.directory/groups.unified/create Create Microsoft 365 groups, excluding role-


assignable groups

microsoft.directory/groups.unified/delete Delete Microsoft 365 groups, excluding role-


assignable groups

microsoft.directory/groups.unified/restore Restore Microsoft 365 groups from soft-deleted


container, excluding role-assignable groups

microsoft.directory/groups.unified/basic/updat Update basic properties on Microsoft 365


e groups, excluding role-assignable groups

microsoft.directory/groups.unified/members/u Update members of Microsoft 365 groups,


pdate excluding role-assignable groups
Actions Description

microsoft.directory/groups.unified/owners/upd Update owners of Microsoft 365 groups,


ate excluding role-assignable groups

microsoft.office365.messageCenter/messages/r Read messages in Message Center in the


ead Microsoft 365 admin center, excluding security
messages

microsoft.office365.network/performance/allPr Read all network performance properties in the


operties/read Microsoft 365 admin center

microsoft.office365.serviceHealth/allEntities/allT Read and configure Service Health in the


asks Microsoft 365 admin center

microsoft.office365.supportTickets/allEntities/al Create and manage Microsoft 365 service


lTasks requests

microsoft.office365.usageReports/allEntities/all Read Office 365 usage reports


Properties/read

microsoft.office365.webPortal/allEntities/standa Read basic properties on all resources in the


rd/read Microsoft 365 admin center

microsoft.office365.yammer/allEntities/allPrope Manage all aspects of Yammer


rties/allTasks

How to understand role permissions


The schema for permissions loosely follows the REST format of Microsoft Graph:

<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.

allProperties designates all properties of the entity, including privileged


properties.
standard designates common properties, but excludes privileged ones
related to read action. For example, microsoft.directory/user/standard/read
includes the ability to read standard properties like public phone number and
email address, but not the private secondary phone number or email address
used for multifactor authentication.
basic designates common properties, but excludes privileged ones related
to the update action. The set of properties that you can read may be different
from what you can update. That’s why there are standard and basic
keywords to reflect that.

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.

AdHoc License Administrator


Device Join
Device Managers
Device Users
Email Verified User Creator
Mailbox Administrator
Workplace Device Join

Roles not shown in the portal


Not every role returned by PowerShell or MS Graph API is visible in Azure portal. The
following table organizes those differences.

API name Azure portal name Notes


API name Azure portal name Notes

Device Join Deprecated Deprecated roles documentation

Device Managers Deprecated Deprecated roles documentation

Device Users Deprecated Deprecated roles documentation

Directory Synchronization Not shown because it Directory Synchronization Accounts


Accounts shouldn't be used documentation

Guest User Not shown because it can't NA


be used

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

Restricted Guest User Not shown because it can't NA


be used

User Not shown because it can't NA


be used

Workplace Device Join Deprecated Deprecated roles documentation

Who can reset passwords


In the following table, the columns list the roles that can reset passwords and invalidate
refresh tokens. The rows list the roles for which their password can be reset.

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 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️

Global Admin ✔️ ✔️*

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 ✔️ ✔️ ✔️ ✔️

Message Center Reader ✔️ ✔️ ✔️ ✔️ ✔️

Password Admin ✔️ ✔️ ✔️ ✔️ ✔️ ✔️

Privileged Auth Admin ✔️ ✔️

Privileged Role Admin ✔️ ✔️

Reports Reader ✔️ ✔️ ✔️ ✔️ ✔️

User ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
(no admin role)

User ✔️ ✔️
(no admin role, but member
or owner of a role-assignable
group)

User Admin ✔️ ✔️ ✔️

Usage Summary Reports ✔️ ✔️ ✔️ ✔️ ✔️


Reader

All custom roles ✔️ ✔️ ✔️ ✔️ ✔️ ✔️

) 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.

Sensitive action Sensitive property name

Disable or enable users accountEnabled

Update business phone businessPhones

Update mobile phone mobilePhone

Update on-premises immutable ID onPremisesImmutableId

Update other emails otherMails

Update password profile passwordProfile

Update user principal name userPrincipalName

Delete or restore users Not applicable

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.

Role that sensitive action can be Auth User Privileged Global


performed upon Admin Admin Auth Admin Admin

Auth Admin ✔️ ✔️ ✔️

Directory Readers ✔️ ✔️ ✔️ ✔️

Global Admin ✔️ ✔️

Groups Admin ✔️ ✔️ ✔️

Guest Inviter ✔️ ✔️ ✔️ ✔️

Helpdesk Admin ✔️ ✔️ ✔️

Message Center Reader ✔️ ✔️ ✔️ ✔️

Password Admin ✔️ ✔️ ✔️ ✔️

Privileged Auth Admin ✔️ ✔️


Role that sensitive action can be Auth User Privileged Global
performed upon Admin Admin Auth Admin Admin

Privileged Role Admin ✔️ ✔️

Reports Reader ✔️ ✔️ ✔️ ✔️

User ✔️ ✔️ ✔️ ✔️
(no admin role)

User ✔️ ✔️
(no admin role, but member or owner of a
role-assignable group)

User Admin ✔️ ✔️ ✔️

Usage Summary Reports Reader ✔️ ✔️ ✔️ ✔️

All custom roles ✔️ ✔️ ✔️ ✔️

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.

This topic describes how to enable application access to partner-managed customer


data via Microsoft Graph using either the authorization code grant flow or the service to
service client credentials flow.

) Important

Calling Microsoft Graph from a CSP application is only supported for directory
resources (such as user, group,device, organization) and Intune resources.

What is a partner-managed application


The CSP program enables Microsoft’s partners to resell and manage Microsoft Online
Services (such as Microsoft 365, Microsoft Azure, and CRM Online) to customers.
Management of customer services is done through Delegated Admin Privileges, which
enables designated partner users (known as agents) to access and configure their
customers’ environments.

Additionally, as a partner developer, you can build a partner-managed app to manage


your customers' Microsoft services. Partner-managed apps are often called pre-
consented apps because all your customers are automatically pre-consented for your
partner-managed apps. This means when a user from one of your customer tenants
uses one of your partner-managed apps, the user can use it without being prompted to
give consent. Partner-managed apps also inherit Delegated Admin Privileges, so your
partner agents can also get privileged access to your customers through your partner-
managed application.

How to set-up a partner-managed application


An application is viewed as partner-managed when it is granted elevated permissions to
access your customers' data.
Note: Partner-managed apps can only be configured on Partner tenants, and in
order to manage customer tenant resources, partner-managed apps must be
configured as multi-tenant applications.

Register and configure a multi-tenant app


The initial steps required here follow most of the same steps used to register and
configure a multi-tenant application:

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.

Pre-consent your app for all your customers


Finally grant your partner-managed app those configured permissions for all your
customers. You can do this by adding the servicePrincipal that represents the app to the
Adminagents group in your Partner tenant, using Azure AD powershell V2 or Microsoft
Graph PowerShell. Follow these steps to find the Adminagents group, the
servicePrincipal and add it to the group.

Azure AD PowerShell

1. Open a PowerShell session and connect to your partner tenant by entering


your admin credentials into the sign-in window.

PowerShell

Connect-AzureAd

2. Find the group that represents the Adminagents.

PowerShell

$group = Get-AzureADGroup -Filter "displayName eq 'Adminagents'"

3. Find the service principal that has the same appId as your app.
PowerShell

$sp = Get-AzureADServicePrincipal -Filter "appId eq


'{yourAppsAppId}'"

4. Finally, add the service principal to the Adminagents group.

PowerShell

Add-AzureADGroupMember -ObjectId $group.ObjectId -RefObjectId


$sp.ObjectId

Token acquisition flows


Token acquisition flows for partner-managed apps - authorization code grant flow and
service-to-service client credentials flow - are the same as regular multi-tenant apps.

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:

1. Acquire an authorization code: Your app makes a request to the /authorize


endpoint and must use a customer tenant, in our example customer.com , for the
target tenant. Your agents would still sign-in with their [email protected]
account.

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>

Register your app in the regions you support


CSP customer engagement is currently limited to a single region. Partner-managed
applications carry the same limitation. This means you must have a separate tenant for
each region you sell in. For example, if your partner-managed app is registered in a
tenant in the US but your customer is in the EU – the partner-managed app will not
work. Each of your regional partner tenants must maintain their own set of partner-
managed apps to manage customers within the same region. This might require
additional logic in your app (prior to sign-in) to get your customers' sign-in username to
decide which region-specific partner-managed app identity to use, to serve the user.

Calling Microsoft Graph immediately after


customer creation
When you create a new customer using the Partner Center API , a new customer
tenant gets created. Additionally, a partner relationship also gets created, which makes
you the partner of record for this new customer tenant. This partner relationship can
take up to 3 minutes to propagate to the new customer tenant. If your app calls
Microsoft Graph straight after creation, your app will likely receive an access denied
error. A similar delay may be experienced when an existing customer accepts your
invitation. This is because pre-consent relies on the partner relationship being present in
the customer tenant.
To avoid this problem, we recommend that your partner app should wait three minutes
after customer creation before calling Azure AD to acquire a token (to call Microsoft
Graph). This should cover most cases. However, if after waiting three minutes you still
receive an authorization error, please wait an additional 60 seconds and try again.

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

Administrators can configure application access policy to limit app access to


specific mailboxes.

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:

1. Connect to Exchange Online PowerShell. For details, see Connect to Exchange


Online PowerShell.

2. Identify the app’s client ID and a mail-enabled security group to restrict the app’s
access to.

Identify the app’s application (client) ID in the Azure app registration


portal .
Create a new mail-enabled security group or use an existing one and identify
the email address for the group.

3. Create an application access policy.

Run the following command, replacing the arguments for AppId,


PolicyScopeGroupId, and Description.

PowerShell

New-ApplicationAccessPolicy -AppId e7e4dbfc-046f-4074-9b3b-2ae8f144f59b


-PolicyScopeGroupId [email protected] -AccessRight RestrictAccess -
Description "Restrict this app to members of distribution group
EvenUsers."

4. Test the newly created application access policy.

Run the following command, replacing the arguments for Identity and AppId.

PowerShell

Test-ApplicationAccessPolicy -Identity [email protected] -AppId


e7e4dbfc-046-4074-9b3b-2ae8f144f59b

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.

Supported permissions and additional


resources
Administrators can use ApplicationAccessPolicy cmdlets to control mailbox access of an
app that has been granted any of the following Microsoft Graph application permissions
or Exchange Web Services permissions.

Microsoft Graph application permissions:

Mail.Read
Mail.ReadBasic

Mail.ReadBasic.All

Mail.ReadWrite
Mail.Send

MailboxSettings.Read
MailboxSettings.ReadWrite

Calendars.Read
Calendars.ReadWrite

Contacts.Read

Contacts.ReadWrite

Exchange Web Services permission scope: full_access_as_app .

For more information about configuring application access policy, see the PowerShell
cmdlet reference for New-ApplicationAccessPolicy.

Handling API errors


You might encounter the following error when an API call is denied access due to a
configured application access policy.

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:

Incorrect access token acquisition flows


Poorly configured permission scopes
Lack of consent
Lack of permissions

Steps to resolve common errors


To resolve common authorization errors, try the steps described for the error that most
closely match the error you're getting. More than one error might apply. You can also
check the answers already available on Microsoft Q&A for 401 errors and 403 errors. If
you can't find a solution to your problem, ask a new question on Microsoft Q&A and tag
with microsoft-graph*.

401 Unauthorized error: Is your token valid?


Make sure that your application is presenting a valid access token to Microsoft Graph as
part of the request. This error often means that the access token may be missing in the
HTTP authenticate request header or that the token is invalid or has expired. We
strongly recommend that you use the Microsoft Authentication Library (MSAL) for
access token acquisition. Additionally this error may occur, if you try to use a delegated
access token granted to a personal Microsoft account, to access an API that only
supports work or school accounts (organizational accounts).

403 Forbidden error: Have you chosen the right set of


permissions?
Verify that you have requested the correct set of permissions based on the Microsoft
Graph APIs your app calls. The least privileged permissions that we recommend are
provided in all the Microsoft Graph API method reference topics. Additionally, those
permissions must be granted to the application by a user or an administrator. Granting
permissions normally happens through a consent page or by granting permissions using
the Azure Portal application registration blade. From the Settings blade for the
application, click Required Permissions, and then click Grant Permissions.

Microsoft Graph permissions


Understanding Azure AD permissions and consent

403 Forbidden error: Did your app acquire a token to


match chosen permissions?
Make sure that the type of permissions requested or granted matches the type of access
token that your app acquires. You might be requesting and granting application
permissions but using delegated interactive code flow tokens instead of client credential
flow tokens, or requesting and granting delegated permissions but using client
credential flow tokens instead of delegated code flow tokens.

Get access on behalf of users and delegated permissions


Azure AD v2.0 - OAuth 2.0 authorization code flow
Get access without a user (daemon service) and application permissions
Azure AD v2.0 - OAuth 2.0 client credentials flow

403 Forbidden error: Resetting password


Currently, there are no application permission daemon service-to-service permissions
that allow resetting user passwords. These APIs are only supported using the interactive
delegated code flows with a signed-in administrator.

Microsoft Graph permissions

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.

403 Forbidden: Did you select the correct resource API?


API services like Microsoft Graph check that the aud claim (audience) in the received
access token matches the value it expects for itself, and if not, it results in a 403
Forbidden error. A common mistake that causes in this error is trying to use a token

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.

400 Bad Request or 403 Forbidden: Does the user comply


with their organization's conditional access (CA) policies?
Based on an organization's CA policies, a user accessing Microsoft Graph resources via
your app might be challenged for additional information that is not present in the
access token your app originally acquired. In this case, your app receives a 400 with an
interaction_required error during access token acquisition or a 403 with
insufficient_claims error when calling Microsoft Graph. In both cases, the error response
contains additional information that can be presented to the authorize endpoint to
challenge the user for additional information (like multi-factor authentication or device
enrollment).

Handling conditional access challenges using MSAL


Developer guidance for Azure Active Directory conditional access

403 Forbidden: Access to OData is disabled


Many Microsoft Graph APIs access Exchange Online. These APIs are subject to the EWS
application policies of Exchange Online. Applications might receive 403 Forbidden errors
with the following response body.

JSON

{
"error": {
"code": "ErrorAccessDenied",
"message": "Access to OData is disabled."
}
}

This might be caused by your organization's EWS access policies. An Exchange


administrator can check this using the Exchange Online PowerShell module.

To determine whether an organization-wide policy has been applied:

PowerShell
Get-OrganizationConfig | fl EwsApplicationAccessPolicy,EWS*List

To determine whether a user-specific policy has been applied:

PowerShell

Get-CASMailbox <user-principal-name> | fl
EwsApplicationAccessPolicy,EWS*List

If EwsApplicationAccessPolicy is set, then a policy is applied.

If EwsApplicationAccessPolicy is set to EnforceAllowList , your application's User-


Agent value must be added to the EwsAllowList value.

If EwsApplicationAccessPolicy is set to EnforceBlockList , your application's User-


Agent value must be removed from the EwsBlockList value.

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

How conditional access policies apply to Microsoft Graph is changing. Applications


need to be updated to handle scenarios where conditional access policies are
configured. For more information and guidance, see Developer guidance for Azure
Active Directory Conditional Access.

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.

Call a REST API method


To read from or write to a resource such as a user or an email message, you construct a
request that looks like the following:

HTTP

{HTTP method} https://graph.microsoft.com/{version}/{resource}?{query-


parameters}

The components of a request include:

{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.

After you make a request, a response is returned that includes:

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

it by using the URL returned in @odata.nextLink . For details, see Paging.

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

GET Read data from a resource.

POST Create a new resource, or perform an action.

PATCH Update a resource with new values.

PUT Replace a resource with a new one.

DELETE Remove a resource.

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.

For details about permissions, see Permissions reference.

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

Tools for interacting with Microsoft Graph

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:

1. Select the HTTP method.


2. Select the version of API that you want to use.
3. Type the query in the request text box.
4. Select Run Query.
The following example shows a request that returns information about users in the
demo tenant:

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.

Microsoft Graph API metadata


The metadata document ($metadata) is published at the service root. You can view the
service document for the v1.0 and beta versions of the Microsoft Graph API via the
following URLs.

Microsoft Graph API v1.0 metadata

HTTP

https://graph.microsoft.com/v1.0/$metadata

Microsoft Graph API beta 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.

The metadata also supports defining types, methods, and enumerations in


corresponding OData namespaces. The majority of the Microsoft Graph API is defined in
the OData namespace, microsoft.graph . A few APIs are defined in subnamespaces, for
example, microsoft.graph.callRecords .

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.

View a collection of resources


Microsoft Graph lets you view resources in a tenant using HTTP GET queries. The query
response includes properties of each resource. Entity resources are each identified by its
ID. The format of a resource ID can be a GUID, and generally varies according to the
resource type.

For example, you can get the collection of user resources defined in a tenant:

GET https://graph.microsoft.com/v1.0/users HTTP/1.1


Authorization : Bearer {access_token}

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:

GET https://graph.microsoft.com/v1.0/me/mailfolders HTTP/1.1


Authorization : Bearer {access_token}

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
}
]
}

View a specific resource from a collection by ID


Continuing with using user as an example - to view the information about a user, use an
HTTPS GET request to get a specific user by the user's ID. For a user entity, you can use
either the id or userPrincipalName property as the identifier.

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]",

...
}

Read specific properties of a resource


To retrieve only the user's biographical data, such as the user's provided About me
description and their skill set, you can add the $select query parameter to the previous
request, as shown in the following example.

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"
}
]
}

Traverse from one resource to another via


relationship
A manager holds a directReports relationship with the other users reporting to him or
her. To query the list of the direct reports of a user, you can use the following HTTPS
GET request to navigate to the intended target via relationship traversal.

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.

GET https://graph.microsoft.com/v1.0/me/messages 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
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 .

Call actions and functions


Microsoft Graph also supports actions and functions to manipulate resources in ways
that are not simply create, read, update, and delete (CRUD) operations. They are often in
the shape of HTTPS POST requests in order to intake arguments for the action or
function. For example, the following action lets the signed-in user ( me ) send an email
message.

POST https://graph.microsoft.com/v1.0/me/sendMail HTTP/1.1


authorization: bearer {access_token}
content-type: application/json
content-length: 96
{
"message": {
"subject": "Meet for lunch?",
"body": {
"contentType": "Text",
"content": "The new cafeteria is open."
},
"toRecipients": [
{
"emailAddress": {
"address": "[email protected]"
}
}
],
"attachments": [
{
"@odata.type": "microsoft.graph.fileAttachment",
"name": "menu.txt",
"contentBytes": "bWFjIGFuZCBjaGVlc2UgdG9kYXk="
}
]
},
"saveToSentItems": "false"
}

You can see all the functions that are available in the metadata. They appear as
Functions or Actions.

Use the Microsoft Graph SDKs


Like the power and ease of SDKs? While you can always use REST APIs to call Microsoft
Graph, we also provide SDKs for many popular platforms. To explore the SDKs that are
available, see Code samples and SDKs.

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:

A page of results may contain zero or more results.


Different APIs might have different default and maximum page sizes.
Different APIs might behave differently if you specify a page size (via the $top
query parameter) that exceeds the maximum page size for that API. Depending on
the API, the requested page size might be ignored, it might default to the
maximum page size for that API, or Microsoft Graph might return an error.
Not all resources or relationships support paging. For example, queries against
directoryRoles do not support paging. This includes reading role objects
themselves as well as role members.
When paging against directory resources, any additional request headers such as
the ConsistencyLevel header are not included by default in subsequent page
requests. If those headers need to be sent on subsequent requests, you must set
them explicitly.
When using the $count=true query string when querying against directory
resources, the @odata.count property will be present only in the first page of the
paged data.

Learn more about paging


The following video introduces you to paging in Microsoft Graph.
https://www.youtube-nocookie.com/embed/DB_NoC9a1JI
Use query parameters to customize
responses
Article • 03/02/2023

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

OData system query options


A Microsoft Graph API operation might support one or more of the following OData
system query options. These query options are compatible with the OData V4 query
language and are supported in only GET operations.

Click the examples to try them in Graph Explorer.

Name Description Example

$count Retrieves the total count of matching resources. /me/messages?


$top=2&$count=true

$expand Retrieves related resources. /groups?$expand=members

$filter Filters results (rows). /users?


$filter=startswith(givenName,'J')

$format Returns the results in the specified media format. /users?$format=json

$orderby Orders results. /users?$orderby=displayName


desc

$search Returns results based on search criteria. /me/messages?$search=pizza


Name Description Example

$select Filters properties (columns). /users?


$select=givenName,surname

$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.

$top Sets the page size of results. /users?$top=2

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.

Other query parameters


Name Description Example

$skipToken Retrieves the next page of results from /users?


result sets that span multiple pages. $skiptoken=X%274453707402000100000017...
(Some APIs use $skip instead.)

Other OData URL capabilities


The following OData 4.0 capabilities are URL segments, not query parameters.

Name Description Example

$count Retrieves the integer total of the collection. GET /users/$count


GET
/groups/{id}/members/$count

$ref Updates entities membership to a collection. POST /groups/{id}/members/$ref

$value Retrieves or updates the binary value of an item. GET /me/photo/$value

$batch Combine multiple HTTP requests into a batch POST /$batch


request.

Encoding query parameters


The values of query parameters should be percent-encoded as per RFC 3986 . For
example, all reserved characters in query strings must be percent-encoded. Many HTTP
clients, browsers, and tools (such as the Graph Explorer) will help you with this. If a query
is failing, one possible cause is failure to encode the query parameter values
appropriately. In some cases, you may have to double-encode the values.

For example, an unencoded URL looks like this:

HTTP

HTTP

GET https://graph.microsoft.com/v1.0/users?$filter=startswith(givenName,
'J')

The properly percent-encoded URL looks like this:

HTTP

HTTP

GET https://graph.microsoft.com/v1.0/users?
$filter=startswith(givenName%2C+'J')

The double-encoded URL looks like this:

HTTP

HTTP

GET https://graph.microsoft.com/v1.0/users?
$filter=startswith%28givenName%2C%20%27J%27%29

Escaping single quotes


For requests that use single quotes, if any parameter values also contain single quotes,
those must be double escaped; otherwise, the request will fail due to invalid syntax. In
the example, the string value let''s meet for lunch? has the single quote escaped.

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

1. On resources that derive from directoryObject, $count is only supported in


an advanced query. See Advanced query capabilities in Azure AD directory
objects.
2. Use of $count is not supported in Azure AD B2C tenants.

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.

$expand is not currently supported with advanced queries.

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

Combining $orderby and $filter query parameters is supported for directory


objects. See Advanced query capabilities in Azure AD directory objects.

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.

The ConsistencyLevel header required for advanced queries against directory


objects is not included by default in subsequent page requests. It must be set
explicitly in subsequent pages.

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

The ConsistencyLevel header required for advanced queries against directory


objects is not included by default in subsequent page requests. It must be set
explicitly in subsequent pages.

Error handling for query parameters


Some requests will return an error message if a specified query parameter is not
supported. For example, you cannot use $expand on the user/photo relationship.

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".

Operators and functions supported in filter


expressions
Support for $filter operators varies across Microsoft Graph APIs. The following
operators and functions are supported:

Operator type Operator

Equality operators Equals ( eq )


Not equals ( ne )
Logical negation ( not )
In ( in )
Has ( has )

Relational operators Less than ( lt )


Greater than ( gt )
Less than or equal to ( le )
Greater than or equal to ( ge )

Lambda operators Any ( any )


All ( all )

Conditional operators And ( and )


Or ( or )
Operator type Operator

Functions Starts with ( startsWith )


Ends with ( endsWith )
Contains ( contains )

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.

Filter using lambda operators


OData defines the any and all operators to evaluate matches on multi-valued
properties, that is, either collection of primitive values such as String types or collection
of entities.

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

collection is the property that contains a collection of values or a collection of


complex properties.
property:property is the range variable that holds the current element of the
collection during iteration. This variable can be named almost anything, for
example, p:p.
subProperty is required when the query applies to a collection of entities. It
represents the property of the complex type whose value you're matching against.
value-to-match represents the member of the collection against which you're
matching.
If you are familiar with C# and LINQ , this would be the equivalent of the above syntax:

C#

collection.Any(property => property.subProperty == "value-to-match")

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]')

The assignedLicenses property of the user resource contains a collection of


assignedLicense objects, a complex type with two properties, skuId and disabledPlans.
The following query retrieves only users with an assigned license identified by the skuId
184efa21-98c3-4e5d-95ab-d07053a96e67 .

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.

Examples using the filter query operator


The following table shows some examples that use the $filter query parameter. For
more information, see the OData protocol .

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 users with the name Mary GET ~/users?$filter=startswith(displayName,'mary') or


across multiple properties. startswith(givenName,'mary') or
startswith(surname,'mary') or startswith(mail,'mary')
or startswith(userPrincipalName,'mary')

Get all users with mail domain equal GET ~/users?


to 'hotmail.com' $count=true&$filter=endsWith(mail,'@hotmail.com') *

Get all users without assigned licenses GET ~/users?$filter=assignedLicenses/$count eq


0&$count=true *

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 emails from a specific address GET ~/me/messages?$filter=from/emailAddress/address


received by the signed-in user. eq '[email protected]'
Description Example

Get all emails received by the signed- GET ~/me/mailFolders/inbox/messages?


in user in April 2017. $filter=ReceivedDateTime ge 2017-04-01 and
receivedDateTime lt 2017-05-01

Get all unread mail in the signed-in GET ~/me/mailFolders/inbox/messages?$filter=isRead eq


user's Inbox. false

Get all users in the Retail and Sales GET ~/users?$filter=department in ('Retail', 'Sales')
departments.

List users with a particular service plan GET ~/users?


that is in a suspended state. $filter=assignedPlans/any(a:a/servicePlanId eq
2e2ddb96-6af9-4b1d-a3f0-d6ecfd22edb2 and
a/capabilityStatus eq 'Suspended')&$count=true *

List all non-Microsoft 365 groups in GET ~/groups?$filter=NOT groupTypes/any(c:c eq


an organization. 'Unified')&$count=true *

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.

List all users whose company name is GET ~/users?$filter=companyName in (null,


either undefined or Microsoft. 'Microsoft')&$count=true *

Use OData cast to get transitive GET ~/me/transitiveMemberOf/microsoft.graph.group?


membership in groups with a display $count=true&$filter=startswith(displayName, 'a') *
name that starts with 'a' including a
count of returned objects.

Syntax for using the filter OData query


parameter
The following article demonstrates the syntax for using the $filter OData query
parameter and its associated operators. The examples are provided for guidance only
and don't reflect a comprehensive list for the application of $filter .

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.

GUID and DateTimeOffset values aren't enclosed in quotes in $filter


expressions.

For single primitive types like String, Int, and dates

Operator Syntax

eq ~/users?$filter=userType eq 'Member'

not ~/users?$filter=not(userType eq 'Member') *

ne ~/users?$filter=companyName ne null *

startsWith ~/users?$filter=startsWith(userPrincipalName, 'admin')

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 *

not and ~/users?$filter=not(endsWith(mail, 'OnMicrosoft.com')) *


endsWith

not and ~/users?$filter=not(startsWith(mail, 'A')) *


startsWith

not and eq ~/users?$filter=not(companyName eq 'Contoso E.A.') *

not and in ~/users?$filter=not(userType in ('Member')) *

contains ~/identityGovernance/accessReviews/definitions?
$filter=contains(scope/microsoft.graph.accessReviewQueryScope/query,
'./members')

has ~/identity/conditionalAccess/templates?$filter=scenarios has


'secureFoundation'

For a collection of primitive types

Operator (s) Syntax

eq ~/groups?$filter=groupTypes/any(c:c eq 'Unified')
Operator (s) Syntax

not ~/groups?$filter=not(groupTypes/any(c:c eq 'Unified')) *

ne ~/users?$filter=companyName ne null *

startsWith ~/users?$filter=businessPhones/any(p:startsWith(p,
'44')) *

endsWith ~/users?$filter=endsWith(mail,'@outlook.com') *

not and endsWith ~/groups?$filter=not(endsWith(mail,'OnMicrosoft.com')) *

not and startsWith ~/groups?$filter=not(startsWith(mail,'Pineview')) *

not and eq ~/groups?$filter=not(mail eq


'[email protected]') *

eq and $count for empty ~/users?$filter=assignedLicenses/$count eq 0 *


collections

ne and $count for empty ~/users?$filter=assignedLicenses/$count ne 0 *


collections

not and $count for empty ~/users?$filter=not(assignedLicenses/$count eq 0) *


collections

$count for collections with one ~/servicePrincipals?$filter=owners/$count eq 1 *


object

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.

For GUID types

Operator Syntax
(s)

eq ~/servicePrincipals?$filter=appOwnerOrganizationId eq 72f988bf-86f1-41af-91ab-
2d7cd011db47 *

not ~/servicePrincipals?$filter=not(appOwnerOrganizationId eq 72f988bf-86f1-41af-


91ab-2d7cd011db47) *

For a collection of GUID types

Operator (s) Syntax


Operator (s) Syntax

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) *

For a collection of complex types

Operator Syntax
(s)

eq ~/users?$filter=authorizationInfo/certificateUserIds/any(x:x eq
'9876543210@mil') *

not and eq ~/users?$filter=not(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.

Using $search on message collections


You can search messages based on a value in specific message properties. The results of the search
are sorted by the date and time that the message was sent. A $search request returns up to 1000
results.

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.

Searchable Description Example


email
property

attachment The names GET ../me/messages?$search="attachment:api-catalog.md"


of files
attached to
an email
message.
Searchable Description Example
email
property

bcc The bcc GET ../me/messages?


field of an $search="bcc:[email protected]"&$select=subject,bccRecipients
email
message,
specified as
an SMTP
address,
display
name, or
alias.

body The body of GET ../me/messages?$search="body:excitement"


an email
message.

cc The cc field GET ../me/messages?$search="cc:danas"&$select=subject,ccRecipients


of an email
message,
specified as
an SMTP
address,
display
name, or
alias.

from The sender GET ../me/messages?$search="from:randiw"&$select=subject,from


of an email
message,
specified as
an SMTP
address,
display
name, or
alias.

hasAttachment True if an GET ../me/messages?$search="hasAttachments:true"


email
message
contains an
attachment
that is not
an inline
attachment,
false
otherwise.
Searchable Description Example
email
property

importance The GET ../me/messages?$search="importance:high"&$select=subject,importance


importance
of an email
message,
which a
sender can
specify
when
sending a
message.
The
possible
values are
low ,
medium , or
high .

kind The type of GET ../me/messages?$search="kind:voicemail"


message.
The
possible
values are
contacts ,
docs ,
email ,
faxes , im ,
journals ,
meetings ,
notes ,
posts ,
rssfeeds ,
tasks , or
voicemail .

participants The from, GET ../me/messages?$search="participants:danas"


to, cc, and
bcc fields of
an email
message,
specified as
an SMTP
address,
display
name, or
alias.
Searchable Description Example
email
property

received The date GET ../me/messages?$search="received:07/23/2018"&$select=subject,receivedDateTime


that an
email
message
was
received by
a recipient.

recipients The to, cc, GET ../me/messages?


and bcc $search="recipients:randiq"&$select=subject,toRecipients,ccRecipients,bccRecipients
fields of an
email
meesage,
specified as
an SMTP
address,
display
name, or
alias.

sent The date GET ../me/messages?$search="sent:07/23/2018"&$select=subject,sentDateTime


that an
email
message
was sent by
the sender.

size The size of GET ../me/messages?$search="size:1..500000"


an item in
bytes.

subject The text in GET ../me/messages?$search="subject:has"&$select=subject


the subject
line of an
email
message. .

to The to field GET .../me/messages?$search="to:randiw"&$select=subject,toRecipients


of an email
message,
specified as
an SMTP
address,
display
name, or
alias.

For more information about searchable email properties, KQL syntax, supported operators, and tips
on searching, see the following articles:

Searchable properties in Exchange.


Keyword Query Language (KQL) syntax reference

Message properties and search operators for In-Place eDiscovery in Exchange 2016

Using $search on person collections


You can use the Microsoft Graph 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. The People API supports the $search query parameter. A $search request returns up to
250 results.

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

GET https://graph.microsoft.com/v1.0/me/people/?$search="Irene McGowen"

The following example shows the response.

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.

Using $search on directory object collections


Azure AD resources and their relationships that derive from directoryObject support the $search
query parameter only in advanced queries. The search implementation does not support "contains"
logic. Instead, it uses a tokenization approach that works by extracting words from the property value
and the search string using spaces, numbers, different casing, and symbols as shown in the following
examples:

Spaces: hello world => hello , world


Different casing⁽¹⁾: HelloWorld or helloWORLD => hello , world
Symbols⁽²⁾: hello.world => hello , . , world , helloworld
Numbers: hello123world => hello , 123 , world

⁽¹⁾ 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 .

$search can be used together with $filter :

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 .

The syntax of search follows these rules:

Generic format: $search="clause1" [AND | OR] "[clauseX]".


Any number of clauses is supported. Parentheses for precedence is also supported.
The syntax for each clause is: "<property>:<text to search>".
The property name must be specified in the clause. Any property that can be used in $filter
can also be used inside $search . Depending on the property, the search behavior is either
"search" or "startsWith" if search is not supported on the property.
The whole clause must be declared inside double quotes. If it contains double quotes or
backslash, it should be escaped with a backslash. All the other special characters must be URL
encoded.
Logical AND and OR operators must be put outside double quotes and they must be in upper
case.

The following table shows some examples.

Object Description Example


class

User Address book display name of the GET ../users?$search="displayName:Guthr"


user.

User Address book display name or mail GET ../users?$search="displayName:Guthr" OR "mail:Guthr"


of the user.
Object Description Example
class

Group Address book display name or GET ../groups?$search="description:One" AND


description of the group. ("displayName:Video" OR "displayName:Drive"

Group Address book display name on a GET ../groups?$filter=mailEnabled eq


mail-enabled group. true&$search="displayName:OneVideo"

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

Microsoft Graph objects that support advanced


query capabilities
These advanced query capabilities are supported only on directory objects and their
relationships, including the following frequently used objects:

Object Relationships

administrativeUnit members

application owners

appRoleAssignment -

device memberOf
transitiveMemberOf
registeredUsers
registeredOwners

group members
transitiveMembers
memberOf
transitiveMemberOf
owners
appRoleAssignments

oAuth2PermissionGrant (delegated permission grants) -

orgContact memberOf
transitiveMemberOf

servicePrincipal memberOf
transitiveMemberOf
appRoleAssignments
appRoleAssignmentsTo
oAuth2PermissionGrant
Object Relationships

user memberOf
transitiveMemberOf
ownedObjects
registeredDevices
ownedDevices
transitiveManagers
directReports
transitiveReports
appRoleAssignments
oAuth2PermissionGrant

Query scenarios that require advanced query


capabilities
The following table lists query scenarios on directory objects that are supported only in
advanced queries:

Description Example

Use of $count as a URL GET ~/groups/$count


segment

Use of $count as a query string GET ~/servicePrincipals?$count=true


parameter

Use of $count in a $filter GET ~/users?$filter=assignedLicenses/$count eq


expression 0&$count=true

Use of $search GET ~/applications?$search="displayName:Browser"

Use of $orderby on select GET ~/applications?$orderby=displayName&$count=true


properties

Use of $filter with the GET ~/users?


endsWith operator $count=true&$filter=endsWith(mail,'@outlook.com')

Use of $filter and $orderby in GET ../applications?


the same query $orderby=displayName&$filter=startsWith( displayName,
'Box')&$count=true

Use of $filter with the GET ~/users?$filter=startsWith(mobilePhone, '25478') OR


startsWith operators on startsWith(mobilePhone, '25473')&$count=true
specific properties.
Description Example

Use of $filter with ne and GET ~/users?$filter=companyName ne null and NOT(companyName


not operators eq 'Microsoft')&$count=true

Use of $filter with not and GET ~/users?$filter=NOT startsWith(displayName,


startsWith operators 'Conf')&$count=true

Use of $filter on a collection GET ~/users?$count=true&$filter=proxyAddresses/any


with endsWith operator (p:endsWith(p,
'OnMicrosoft.com'))&$select=id,displayName,proxyaddresses

Use of OData cast with GET ~/me/transitiveMemberOf/microsoft.graph.group?


transitive members list $count=true

7 Note

Using $filter and $orderby together is supported only with advanced


queries.
$expand is not currently supported with advanced queries.

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.

Support for filter by properties of Azure AD


(directory) objects
Properties of directory objects behave differently in their support for query parameters.
The following are common scenarios for directory objects:

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.

The following tables summarize support for $filter operators by properties of


directory objects and indicates where querying is supported through advanced query
capabilities.

Legend

The $filter operator works by default for that property.

The $filter operator requires advanced query parameters, which are:


ConsistencyLevel=eventual header

$count=true query string

The $filter operator is not supported on that property. Send us feedback


to request that this property support $filter for your scenarios.
Blank cells indicate that the query is not valid for that property.
The null value column indicates that the property is nullable and filterable using
null .
Properties that are not listed here do not support $filter at all.

Administrative unit properties


Property eq startsWith eq Null

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)

The following properties of the application entity support $count of a collection in a


filter expression.

Property eq Count 0 eq Count 1

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.

Property eq Count 0 eq Count 1

physicalIds/$count

systemLabels/$count

Directory role properties


Property eq startsWith eq Null

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

mail

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.

Property eq Count 0 eq Count 1

onPremisesProvisioningErrors/$count

proxyAddresses/$count

Organizational contacts properties


Property eq startsWith ge/le eq
Null

companyName

department

displayName

givenName

jobTitle
Property eq startsWith ge/le eq
Null

mail

mailNickname

manager/id

onPremisesLastSyncDateTime

onPremisesProvisioningErrors/any(o:o/category)

onPremisesProvisioningErrors/any(o:o/propertyCausingError)

onPremisesSyncEnabled

proxyAddresses/any(p:p)

surname

The following properties of the orgContact entity support $count of a collection in a


filter expression.

Property eq Count 0 eq Count 1

onPremisesProvisioningErrors/$count

proxyAddresses/$count

Service principal properties


Property eq startsWith ge/le eq Null

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.

Property eq Count 0 eq Count 1

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)

mail

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.

Property eq Count 0 eq Count 1

assignedLicenses/$count

onPremisesProvisioningErrors/$count

otherMails/$count

ownedObjects/$count

proxyAddresses/$count

Support for sorting by properties of Azure AD


(directory) objects
The following table summarizes support for $orderby by properties of directory objects
and indicates where sorting is supported through advanced query capabilities.

Legend

The $orderby operator works by default for that property.

The $orderby operator requires advanced query parameters, which are:


ConsistencyLevel=eventual header

$count=true query string


Use of $filter and $orderby in the same query for directory objects always
requires advanced query parameters. For more information, see Query scenarios
that require advanced query capabilities.

Directory object Property name Supports $orderby


Directory object Property name Supports $orderby

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:

An image stored in OneDrive


A list of Planner tasks
The calendar for a group

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

First JSON batch request


First you construct the JSON batch request for the previous example. In this scenario,
the individual requests are not interdependent in any way and therefore can be placed
into the batch request in any order.

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

id Required. A correlation value to associate individual responses with requests. This


value allows the server to process requests in the batch in the most efficient order.

method Required. The HTTP method.

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.

Sequencing requests with the dependsOn


property
Individual requests can be executed in a specified order by using the dependsOn
property. This property is an array of strings that references the id of a different
individual request. For this reason, the values for id must be unique. For example, in the
following request, the client is specifying that requests should be run in the order
request 1 then request 2, then request 4, then request 3.

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

Batch should be either fully sequential or fully parallel.

Bypassing URL length limitations with batching


An additional use case for JSON batching is to bypass URL length limitations. In cases
where the filter clause is complex, the URL length might surpass limitations built into
browsers or other HTTP clients. You can use JSON batching as a workaround for running
these requests because the lengthy URL simply becomes part of the request payload.
Batch size limitations
JSON batch requests are currently limited to 20 individual requests in addition to the
following limitations:

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 .

For more information, see Throttling and batching.

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 the number of concurrent calls to a service to prevent overuse of


resources. Microsoft Graph is designed to handle a high volume of requests. If an
overwhelming number of requests occurs, throttling helps maintain optimal
performance and reliability of the Microsoft Graph service.

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

What happens when throttling occurs?


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 requests 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.

Common throttling scenarios


The most common causes of throttling of clients include:

A large number of requests across all applications in a tenant.


A large number of requests from a particular application across all tenants.
Sample response
Whenever the throttling threshold is exceeded, Microsoft Graph responds with a
response similar to this one.

HTTP

HTTP/1.1 429 Too Many Requests


Content-Length: 312
Content-Type: application/json
Retry-After: 10

{
"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."
}
}

Best practices to handle throttling


The following are best practices for handling throttling:

Reduce the number of operations per request.


Reduce the frequency of calls.
Avoid immediate retries, because all requests accrue against your usage limits.

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.

1. Wait the number of seconds specified in the Retry-After header.


2. Retry the request.
3. If the request fails again with a 429 error code, you are still being throttled.
Continue to use the recommended Retry-After delay and retry the request until it
succeeds.
All the resources and APIs described in the Service-specific limits provide a Retry-After
header except when noted.

For a broader discussion of throttling in the Microsoft Cloud, see Throttling pattern.

7 Note

If no Retry-After header is provided by the response, we recommend


implementing an exponential backoff retry policy. You can also implement more
advanced patterns when building large-scale applications.

Microsoft Graph SDKs already implement handlers that rely on the Retry-After
header or default to an exponential backoff retry policy.

Best practices to avoid throttling


Programming patterns like continuously polling a resource to check for updates and
regularly scanning resource collections to check for new or deleted resources are more
likely to lead to applications being throttled and degrade overall performances. You
should instead leverage change tracking and change notifications when available.

7 Note

Best practices for discovering files and detecting changes at scale describes best
practices in details.

Throttling and batching


JSON batching allows you to optimize your application by combining multiple requests
into a single JSON object. Requests in a batch are evaluated individually against
throttling limits and if any request exceeds the limits, it fails with a status of 429 and an
error similar to the preceding sample response. The batch itself fails with a status code
of 424 (Failed Dependency). It is possible for multiple requests to be throttled in a single
batch. You should retry each failed request from the batch using the value provided in
the retry-after response header from the JSON content. You may retry all the failed
requests in a new batch after the longest retry-after value.

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:

Request type Per app across all tenants

Any 2000 requests per second

7 Note

The specific limits described here are subject to change.

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.

Assignment service limits


The following limits apply to requests on the assignment service API:

Request Type Limit per app per tenant Limit per tenant for all apps

Any 500 requests per 10 seconds 1000 requests per 10 seconds

Any 15000 requests per 3600 seconds 30000 requests per 3600 seconds

GET me/Assignment 50 requests per 10 seconds 150 requests per 10 seconds

The preceding limits apply to the following resources:

educationAssignment
educationSubmission
trending
educationResource

Cloud communication service limits


Resource Limits per app

Calls 10,000 calls/month and 100 concurrent calls

Meeting information 2000 meetings/user each month

Presence 1500 requests in a 30 second period, per application per tenant

Call records limits


The limits listed in the following table apply to the following resource:

callRecord
Limit type Limit

Per tenant 10,000 requests per 20 seconds

Per application per tenant 1,500 requests per 20 seconds

Per call record 10 requests per 20 seconds (first page)


50 requests per 5 minutes (subsequent pages)

Excel service limits


For explanations and best practices related to Excel service throttling, see Reduce throttling errors. In addition, following are
some throttling limits.

Request type Limit per app for all tenants Limit per app per tenant

Any 5000 requests per 10 seconds 1500 requests per 10 seconds

The preceding limits apply to the following resources:

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

Education service limits


Request type Limit per app for all tenants Limit per app per tenant

Any 400000 requests per 20 seconds 35000 requests per 10 seconds

The preceding limits apply to the following resources:

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.

The preceding information applies to the following resources:

baseItem itemActivityStat
baseItemVersion itemAnalytics
columnDefinition list
columnLink listItem
contentType listItemVersion
drive permission
driveItem sharedDriveItem
driveItemVersion site
fieldValueSet thumbnailSet
itemActivity

Identity and access reports service limits


Request type Limit per app per tenant

Any 5 requests per 10 seconds

The preceding limits apply to the following resources:

applicationSignInDetailedSummary credentialUserRegistrationDetails
applicationSignInSummary directoryAudit
auditLogRoot provisioningObjectSummary
authenticationMethod relyingPartyDetailedSummary
azureADUserFeatureUsage signIn
credentialUsageSummary userCredentialUsageDetails
credentialUserRegistrationCount

Identity and access reports best practices


Azure AD reporting APIs are throttled when Azure AD receives too many calls during a given timeframe from a tenant or app.
Calls may also be throttled if the service takes too long to respond. If your requests still fail with a 429 Too Many Requests error
code despite applying the best practices to handle throttling, try reducing the amount of data returned. Try these approaches
first:

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.

Identity and access service limits

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.

Limit type Resource unit quota Write quota

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

application 150,000 requests per 20 seconds 70,000 requests per 5 minutes

tenant Not Applicable 18,000 requests per 5 minutes

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.

The preceding limits apply to the following resources:

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.

Operation Request Path Base Resource Unit Cost Write Cost

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

GET Any identity path not listed in the table 1 0

POST Any identity path not listed in the table 1 1

PATCH Any identity path not listed in the table 1 1

PUT Any identity path not listed in the table 1 1

DELETE Any identity path not listed in the table 1 1

) 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.

Other factors that affect a request cost:

Using $select decreases cost by 1


Using $expand increases cost by 1
Using $top with a value of less than 20 decreases cost by 1
Creating a user in an Azure AD B2C tenant increases cost by 4

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.

Regular responses requests


x-ms-resource-unit - Indicates the resource unit used for this request. Values are positive integers.
x-ms-throttle-limit-percentage - Returned only when the application consumed more than 0.8 of its limit. The value
ranges from 0.8 to 1.8 and is a percentage of the use of the limit. The value can be used by the callers to set up an alert
and take action.

Throttled responses requests


x-ms-throttle-scope - eg. Tenant_Application/ReadWrite/9a3d526c-b3c1-4479-ba74-197b5c5751ae/0785ef7c-2d7a-4542-
b048-95bcab406e0b . Indicates the scope of throttling with the following format
<Scope>/<Limit>/<ApplicationId>/<TenantId|UserId|ResourceId> :

Scope: (string, required)


Tenant_Application - All requests for a particular tenant for the current application.
Tenant - All requests for the current tenant, regardless of the application.
Application - All requests for the current application.
Limit: (string, requied)
Read: Read requests for the scope (GET)
Write: Write requests for the scope (POST, PATCH, PUT, DELETE...)
ReadWrite: All Requests for the scope (any)
ApplicationId (Guid, required)
TenantId|UserId|ResourceId: (Guid, required)
x-ms-throttle-information - Indicates the reason for throttling and can have any value (string). The value is provided for
diagnostics and troubleshooting purposes, some examples include:
CPULimitExceeded - Throttling is because the limit for cpu allocation is exceeded.
WriteLimitExceeded - Throttling is because the write limit is exceeded.
ResourceUnitLimitExceeded - Throttling is because the limit for the allocated resource unit is exceeded.

Identity and access data policy operation service limits


Request type Limit per tenant

POST on exportPersonalData 1000 requests per day for any subject and 100 per subject per day

Any other request 10000 requests per hour

The preceding limits apply to the following resources:

dataPolicyOperation

7 Note

The resources listed earlier do not return a Retry-After header on 429 Too Many Requests responses.

Identity protection and conditional access service limits


Request type Limit per tenant for all apps

Any 1 request per second

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.

Identity providers service limits


Request type Limit per tenant for all apps Limit per app per tenant

Any 300 requests per 1 minute 200 requests per 1 minute

The preceding limits apply to the following resources:

assignmentOrder identityUserFlowAttribute
authenticationFlowsPolicy identityUserFlowAttributeAssignment
b2cAuthenticationMethodsPolicy openIdConnectIdentityProvider
b2cIdentityUserFlow openIdConnectProvider
b2xIdentityUserFlow socialIdentityProvider
builtInIdentityProvider trustFrameworkKeySet
identityApiConnector trustFrameworkPolicy
identityBuiltInUserFlowAttribute userFlowLanguageConfiguration
identityCustomUserFlowAttribute userFlowLanguagePage
identityProvider
identityUserFlow

Information protection service limits


The following limits apply to any request on /informationProtection .

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

10,000 API requests in a 10 minute period v1.0 and beta endpoints

4 concurrent requests v1.0 and beta endpoints

The preceding limits apply to the following resources:

people
sharedInsight
trending
usedInsight

Intune 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

microsoftTunnelConfiguration
microsoftTunnelHealthThreshold
microsoftTunnelServer
microsoftTunnelServerLogCollectionResponse
microsoftTunnelSite

Intune android for work 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

androidDeviceOwnerEnrollmentProfile
androidForWorkAppConfigurationSchema
androidForWorkEnrollmentProfile
androidForWorkSettings
androidManagedStoreAccountEnterpriseSettings
androidManagedStoreAppConfigurationSchema

Intune applications 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds


The preceding limits apply to the following resources:

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

Intune auditing 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

auditEvent

Intune books 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:


deviceInstallState
eBookInstallSummary
iosVppEBook
iosVppEBookAssignment
managedEBook
managedEBookAssignment
managedEBookCategory
userInstallStateSummary

Intune bundles 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

assignmentFilterEvaluationStatusDetails managedDeviceMobileAppConfigurationPolicySetItem
deviceAndAppManagementAssignmentFilter mdmWindowsInformationProtectionPolicyPolicySetItem
deviceCompliancePolicyPolicySetItem mobileAppPolicySetItem
deviceConfigurationPolicySetItem policySet
deviceManagementConfigurationPolicyPolicySetItem policySetAssignment
deviceManagementScriptPolicySetItem policySetItem
enrollmentRestrictionsConfigurationPolicySetItem targetedManagedAppConfigurationPolicySetItem
iosLobAppProvisioningConfigurationPolicySetItem, windows10EnrollmentCompletionPageConfigurationPolicySetItem
managedAppProtectionPolicySetItem windowsAutopilotDeploymentProfilePolicySetItem

Intune chromebook sync 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

chromeOSOnboardingSettings

Intune company terms 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

deviceManagementConfigurationCategory deviceManagementConfigurationSettingDefinition
deviceManagementConfigurationChoiceSettingCollectionDefinition deviceManagementConfigurationSettingGroupCollectionDefinition
deviceManagementConfigurationChoiceSettingDefinition deviceManagementConfigurationSettingGroupDefinition
deviceManagementConfigurationPolicy deviceManagementConfigurationSettingTemplate
deviceManagementConfigurationPolicyAssignment deviceManagementConfigurationSimpleSettingCollectionDefinition
deviceManagementConfigurationPolicyTemplate deviceManagementConfigurationSimpleSettingDefinition
deviceManagementConfigurationSetting deviceManagementReusablePolicySetting

Intune device configuration 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

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

Intune device enrollment service limits

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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

complianceManagementPartner deviceManagementExchangeOnPremisesPolicy
deviceAppManagement deviceManagementPartner
deviceCategory enrollmentConfigurationAssignment
deviceComanagementAuthorityConfiguration mobileThreatDefenseConnector
deviceEnrollmentConfiguration onPremisesConditionalAccessSettings
deviceEnrollmentLimitConfiguration sideLoadingKey
deviceEnrollmentPlatformRestrictionsConfiguration vppToken
deviceEnrollmentWindowsHelloForBusinessConfiguration windows10EnrollmentCompletionPageConfiguration
deviceManagementExchangeConnector

Intune device intent 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

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

Intune devices service limits

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

Any 4000 requests per 20 seconds 2000 requests per 20 seconds

The preceding limits apply to the following resources:


applePushNotificationCertificate userExperienceAnalyticsAppHealthDevicePerformance
appLogCollectionRequest userExperienceAnalyticsAppHealthDevicePerformanceDetails
cloudPCConnectivityIssue userExperienceAnalyticsAppHealthOSVersionPerformance
comanagementEligibleDevice userExperienceAnalyticsBaseline
dataSharingConsent userExperienceAnalyticsCategory
detectedApp userExperienceAnalyticsDevicePerformance
deviceComplianceScript userExperienceAnalyticsDeviceScores
deviceComplianceScriptDeviceState userExperienceAnalyticsDeviceStartupHistory
deviceComplianceScriptRunSummary userExperienceAnalyticsDeviceStartupProcess
deviceCustomAttributeShellScript userExperienceAnalyticsDeviceStartupProcessPerformance
deviceHealthScript userExperienceAnalyticsDeviceWithoutCloudIdentity
deviceHealthScriptAssignment userExperienceAnalyticsImpactingProcess
deviceHealthScriptDeviceState userExperienceAnalyticsMetric
deviceHealthScriptRunSummary userExperienceAnalyticsMetricHistory
deviceLogCollectionResponse userExperienceAnalyticsNotAutopilotReadyDevice
deviceManagementScript userExperienceAnalyticsOverview
deviceManagementScriptAssignment userExperienceAnalyticsRegressionSummary
deviceManagementScriptDeviceState userExperienceAnalyticsRemoteConnection
deviceManagementScriptGroupAssignment userExperienceAnalyticsResourcePerformance
deviceManagementScriptRunSummary userExperienceAnalyticsScoreHistory
deviceManagementScriptUserState userExperienceAnalyticsWorkFromAnywhereDevice
deviceShellScript userExperienceAnalyticsWorkFromAnywhereMetric
malwareStateForWindowsDevice windowsDeviceMalwareState
managedDevice windowsMalwareInformation
managedDeviceOverview windowsManagedDevice
remoteActionAudit windowsManagementApp
userExperienceAnalyticsAppHealthApplicationPerformance windowsManagementAppHealthState
userExperienceAnalyticsAppHealthAppPerformanceByAppVersion windowsManagementAppHealthSummary
userExperienceAnalyticsAppHealthAppPerformanceByOSVersion windowsProtectionState
userExperienceAnalyticsAppHealthDeviceModelPerformance

Intune endpoint protection 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

deviceManagementDerivedCredentialSettings
deviceManagementResourceAccessProfileAssignment
deviceManagementResourceAccessProfileBase
windows10XCertificateProfile
windows10XSCEPCertificateProfile
windows10XTrustedRootCertificate
windows10XVpnConfiguration
windows10XWifiConfiguration

Intune enrollment 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:


complianceManagementPartner deviceManagementExchangeOnPremisesPolicy
deviceAppManagement deviceManagementPartner
deviceCategory enrollmentConfigurationAssignment
deviceComanagementAuthorityConfiguration mobileThreatDefenseConnector
deviceEnrollmentConfiguration onPremisesConditionalAccessSettings
deviceEnrollmentLimitConfiguration sideLoadingKey
deviceEnrollmentPlatformRestrictionsConfiguration vppToken
deviceEnrollmentWindowsHelloForBusinessConfiguration windows10EnrollmentCompletionPageConfiguration
deviceManagementExchangeConnector

Intune GPAnalytics 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

groupPolicyMigrationReport
groupPolicyObjectFile
groupPolicySettingMapping
unsupportedGroupPolicyExtension

Intune managed applications 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

androidManagedAppProtection managedAppStatusRaw
androidManagedAppRegistration managedMobileApp
defaultManagedAppProtection mdmWindowsInformationProtectionPolicy
iosManagedAppProtection targetedManagedAppConfiguration
iosManagedAppRegistration targetedManagedAppPolicyAssignment
managedAppConfiguration targetedManagedAppProtection
managedAppOperation windowsInformationProtection
managedAppPolicy windowsInformationProtectionAppLockerFile
managedAppPolicyDeploymentSummary windowsInformationProtectionDeviceRegistration
managedAppProtection windowsInformationProtectionPolicy
managedAppRegistration windowsInformationProtectionWipeAction
managedAppStatus

Intune notifications 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:


localizedNotificationMessage
notificationMessageTemplate

Intune ODJ 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

deviceManagementDomainJoinConnector

Intune partner integration 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

appVulnerabilityManagedDevice
appVulnerabilityMobileApp
appVulnerabilityTask
configManagerCollection
deviceAppManagementTask
securityConfigurationTask
unmanagedDeviceDiscoveryTask
vulnerableManagedDevice

Intune rbac 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

deviceAndAppManagementRoleAssignment
deviceAndAppManagementRoleDefinition
resourceOperation
roleAssignment
roleDefinition
roleScopeTag
roleScopeTagAutoAssignment

Intune remote assistance 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

remoteAssistancePartner
remoteAssistanceSettings

Intune telephony 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

embeddedSIMActivationCodePool
embeddedSIMActivationCodePoolAssignment
embeddedSIMDeviceState

Intune TEM 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

telecomExpenseManagementPartner

Intune troubleshooting 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

windowsDefenderApplicationControlSupplementalPolicy
windowsDefenderApplicationControlSupplementalPolicyAssignment
windowsDefenderApplicationControlSupplementalPolicyDeploymentStatus
windowsDefenderApplicationControlSupplementalPolicyDeploymentSummary

Intune updates 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

windowsFeatureUpdateCatalogItem
windowsFeatureUpdateProfile
windowsFeatureUpdateProfileAssignment
windowsQualityUpdateCatalogItem
windowsQualityUpdateProfile
windowsQualityUpdateProfileAssignment
windowsUpdateCatalogItem

Intune wip 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

intuneBrandingProfile
intuneBrandingProfileAssignment
windowsInformationProtectionAppLearningSummary
windowsInformationProtectionNetworkLearningSummary

Invitation manager service limits


The following limits apply to any request on /invitations .

Operation Limit per tenant for all apps

Any operation 150 requests per 5 seconds


Microsoft 365 reports service limits
The following limits apply to any request on /reports .

Operation Limit per app per tenant Limit per tenant for all apps

Any request (CSV) 14 requests per 10 minutes 40 requests per 10 minutes

Any request (JSON, beta) 100 requests per 10 minutes n/a

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.

The preceding limits apply to all usage reports resources.

Microsoft Teams service limits


Limits are expressed as requests per second (rps).

Teams request type Limit per app per tenant Limit per app across all tenants

GET team, channel, tab, installedApps, appCatalogs 30 rps 600 rps

POST/PUT channel, tab, installedApps, appCatalogs 30 rps 300 rps

PATCH team, channel, tab, installedApps, appCatalogs 30 rps 300 rps

DELETE channel, tab, installedApps, appCatalogs 15 rps 150 rps

GET /teams/ {team-id} , joinedTeams 30 rps 300 rps

POST /teams 10 rps 100 rps

PUT /groups/ {team-id} /team, clone 6 rps 150 rps

GET channel message 20 rps 200 rps

GET 1:1/group chat message 20 rps 200 rps

POST channel message 50 rps 500 rps

POST 1:1/group chat message 20 rps 200 rps

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

POST /teams/ {team-id} /sendActivityNotification 5 rps 50 rps

POST /chats/ {chat-id} /sendActivityNotification 5 rps 50 rps

POST /users/ {user-id} /teamwork/sendActivityNotification 5 rps 50 rps

POST /teamwork/sendActivityNotificationToRecipients 2 rps 20 rps

GET /teams/ {team-id} /members 60 rps 1200 rps

GET /teams/ {team-id} /channels 60 rps 1200 rps

GET /teams/ {team-id} /channels/ {channel-id} /members 60 rps 1200 rps

Get all channel messages for a team 200rps 1000rps


GET teams/ {team-id} /channels/getAllMessages
GET teams/ {team-id} /channels/allMessages
Teams request type Limit per app per tenant Limit per app across all tenants

Get all chat messages for a user 200rps 1000rps


GET users/ {user-id} /chats/getAllMessages
GET users/ {user-id} /chats/allMessages

Other GET API calls for Microsoft Teams 30 rps 1500 rps

Other API calls for Microsoft Teams 30 rps 300 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).

See also Microsoft Teams limits and polling requirements.

The preceding limits apply to the following resources:

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

Multi-tenant management 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

Any 2000 requests per 20 seconds 1000 requests per 20 seconds

The preceding limits apply to the following resources:

aggregatedPolicyCompliance managementIntent
cloudPcConnection managementTemplate
cloudPcDevice riskyUser
cloudPcOverview tenant
conditionalAccessPolicyCoverage tenantCustomizedInformation
credentialUserRegistrationsSummary tenantDetailedInformation
deviceCompliancePolicySettingStateSummary tenantGroup
managedDeviceCompliance tenantRelationship
managedDeviceComplianceTrend tenantTag
managedTenant windowsDeviceMalwareState
managementAction windowsProtectionState
managementActionTenantDeploymentStatus

OneNote service limits


Limit type Limit per app per user (delegated context) Limit per app (app-only context)

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)

Concurrent requests 5 concurrent requests 20 concurrent requests

The preceding limits apply to the following resources:

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.

Open and schema extensions service limits


Request type Limit per app per tenant

Any 455 requests per 10 seconds

The preceding limits apply to the following resources:

administrativeUnit openTypeExtension
contact organization
device post
event schemaExtension
group user
message

Outlook service limits


Outlook service limits apply to the public cloud and national cloud deployments.

Limits per app ID and mailbox combination


The Outlook service applies limits to each app ID and mailbox combination - that is, a specific app accessing a specific user or
group mailbox. Exceeding the limit for one mailbox does not affect the ability of the application to access another mailbox.

Limit Applies to

10,000 API requests in a 10 minute period v1.0 and beta endpoints

4 concurrent requests v1.0 and beta endpoints

150 megabytes (MB) upload (PATCH, POST, PUT) in a 5 minute period v1.0 and beta endpoints

Outlook service resources

API Resources
API Resources

Search API (preview) External item (Microsoft Search)

Profile API Photo

Calendar API event


eventMessage
calendar
calendarGroup
outlookCategory
attachment
place (preview)

Mail API message


mailFolder
mailSearchFolder
messageRule
outlookCategory
attachment

Personal contacts API contact


contactFolder
outlookCategory

Social and workplace intelligence person

To-do tasks API (preview) outlookTask


outlookTaskFolder
outlookTaskGroup
outlookCategory
attachment

Outlook service limits for JSON batching


When an app makes a JSON batch request that consists of multiple, unordered individual requests to the Outlook service, by
default, Microsoft Graph sends the Outlook service up to 4 individual requests from the batch at a time, regardless of the
target mailboxes of those requests. The Outlook service can execute these requests in parallel at any point, also irrespective of
the target mailbox. Since Microsoft Graph sends only up to 4 requests to run in parallel, the execution of that batch stays
within Outlook's concurrency limits for the same mailbox.

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.

Project Rome service limits


Request type Limit per user for all apps

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

The preceding limits apply to the following resources:

activityHistoryItem
userActivity
Security detections and incidents service limits
The following limits apply to any request on /security .

Operation Limit per app per tenant

Any operation on alert , securityActions , secureScore 150 requests per minute

Any operation on tiIndicator 1000 requests per minute

Any operation on secureScore or secureScorecontrolProfile 10,000 API requests in a 10 minute period

Any operation on secureScore or secureScorecontrolProfile 4 concurrent requests

Security eDiscovery service limits


The following limits apply to any request on /security/eDiscoveryCases .

Operation Limit per app per tenant

Any 5 requests per minute

Service Communications service limits


The following limits apply to any type of requests for service communications under /admin/serviceAnnouncement/ .

Request type Limit per app per tenant

Any 240 requests per 60 seconds

Any 800 requests per hour

Skype service limits


Request type Limit per app for all tenants

Any 5000 requests per 10 seconds

The preceding limits apply to the following resources:

audioRoutingGroup onlineMeeting
call participant
cancelMediaProcessingOperation participantJoiningNotification
cloudCommunications participantLeftNotification
commsApplication playPromptOperation
commsOperation presence
inviteParticipantsOperation recordOperation
meetingAttendanceReport subscribeToToneOperation
muteParticipantOperation unmuteParticipantOperation
muteParticipantOperation updateRecordingStatusOperation

Subscription service limits


Request type Limit per app for all tenants Limit per app per tenant

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

GET Subscription List 40 requests per 20 seconds 25 requests per 20 seconds

The preceding limits apply to the subscription resource.

Tasks and plans service limits


Service limits for Planner are not available.

The preceding information applies to the following resources:

planner plannerPlanDetails
plannerAssignedToTaskBoardTaskFormat plannerProgressTaskBoardTaskFormat
plannerBucket plannerTask
plannerBucketTaskBoardTaskFormat plannerTaskDetails
plannerGroup plannerUser
plannerPlan
Set up notifications for changes in
resource data
Article • 04/20/2023

Change notifications enable applications to receive alerts when a Microsoft Graph


resource they're interested in changes; that is, created, updated, or deleted. Microsoft
Graph sends notifications to the specified client endpoint, and the client service
processes the notifications according to the business requirements. For example, the
service may fetch more data, update its cache and views, and so on.

Why get change notifications?


Change notifications follow an event-driven model where customers receive alerts when
changes occur instead of them polling Microsoft Graph. Depending on your business
logic, change notifications are suitable when:

You're subscribing to a resource that changes frequently.


You need to react to changes in near real-time.
You want to avoid frequently polling Microsoft Graph which might cause you to hit
the throttling limits.

https://www.youtube-nocookie.com/embed/rC1bunenaq4

Types of change notifications


Microsoft Graph supports three types of change notifications:

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

Subscriptions to resources marked with an asterisk ( * ) are available on the /beta


endpoint only.

Resource Supported resource paths Limitations

Cloud printing Changes when a print job is ready to be downloaded -


printer (jobFetchable event): /print/printers/{id}/jobs

Cloud printing Changes when there is a valid job in the queue (jobStarted -
printTaskDefinition event): /print/printtaskdefinition/{id}/tasks

driveItem on Changes to content within the hierarchy of any folder: -


OneDrive (personal) /users/{id}/drive/root

driveItem on Changes to content within the hierarchy of the root folder: -


OneDrive for /drives/{id}/root , /users/{id}/drive/root
Business
Resource Supported resource paths Limitations

group Changes to all groups: /groups Maximum


subscription
Changes to a specific group: /groups/{id} quotas:
Per app
Changes to owners of a specific group: /groups/{id}/owners (for all
tenants
Changes to members of a specific group: /groups/{id}/members combined):
50,000 total
subscriptions.
Per tenant
(for all
applications
combined):
1000 total
subscriptions
across all
apps.
Per app
and tenant
combination:
100 total
subscriptions
.

Not
supported for
Azure AD
B2C tenants.

A known
issue for the
subscription
changeType.

list under a Changes to content within the list: /sites/{site- -


SharePoint site id}/lists/{list-id}

Microsoft 365 group Changes to a group's conversations: -


conversation groups/{id}/conversations
Resource Supported resource paths Limitations

Outlook message Changes to all messages in a user's mailbox: A maximum


/users/{id}/messages , /me/messages of 1,000
active
Changes to messages in a user's Inbox: subscriptions
/users/{id}/mailFolders('inbox')/messages , per mailbox
/me/mailFolders('inbox')/messages for all
applications
is allowed.

Outlook event Changes to all events in a user's mailbox: /users/{id}/events , A maximum


/me/events of 1,000
active
subscriptions
per mailbox
for all
applications
is allowed.

Outlook personal Changes to all personal contacts in a user's mailbox: A maximum


contact /users/{id}/contacts , /me/contacts of 1,000
active
subscriptions
per mailbox
for all
applications
is allowed.

Security alert Changes to a specific alert: /security/alerts/{id} -

Changes to filtered alerts: /security/alerts/?$filter=


{parameters}

Teams callRecord Changes to all call records: /communications/callRecords Maximum


subscription
quotas:
Per
organization:
100 total
subscriptions.
Resource Supported resource paths Limitations

Teams chat Changes to any chat in the tenant: /chats Maximum


subscription
Changes to a specific chat: /chats/{id} quotas:
Per app
Changes to all chats in an organization where a particular and chat
Teams app is installed: combination:
/appCatalogs/teamsApps/{id}/installedToChats 1
subscription.
Per
organization:
10,000 total
subscriptions.

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

Teams channel Changes to channels in all teams: /teams/getAllChannels Maximum


subscription
Changes to channel in a specific team: /teams/{id}/channels quotas:
Per app
and team
combination:
1
subscription.
Per
organization:
10,000 total
subscriptions.

Teams Changes to membership in a specific team: Maximum


conversationMember /teams/{id}/members subscription
quotas:
Changes to membership in all channels under a specific team: Per app
teams/{id}/channels/getAllMembers and team
combination:
Changes to membership in a specific chat: 1
/chats/{id}/members subscription.
Per
Changes to membership for all chats in an organization where organization:
a particular Teams app is installed: 10,000 total
/appCatalogs/teamsApps/{id}/installedToChats/getAllMembers subscriptions.

Changes to membership in all chats: /teams/getAllMembers

Teams onlineMeeting Changes to an online meeting:


* /communications/onlineMeetings/?$filter=JoinWebUrl eq
{joinWebUrl}

Teams presence Changes to a single user's presence:


/communications/presences/{id}

Changes to multiple user presences:


/communications/presences?$filter=id in ({id},{id}...)
Resource Supported resource paths Limitations

Teams team Changes to any team in the tenant: /teams Maximum


subscription
Changes to a specific team: /teams/{id} quotas:
Per app
and team
combination:
1
subscription.
Per
organization:
10,000 total
subscriptions.

todoTask Changes to all task in a specific task list: -


/me/todo/lists/{todoTaskListId}/tasks
Resource Supported resource paths Limitations

user Changes to all users: /users Maximum


subscription
Changes to a specific user: /users/{id} quotas:
Per app
(for all
tenants
combined):
50,000 total
subscriptions.
Per tenant
(for all
applications
combined):
1000 total
subscriptions
across all
apps
Per app
and tenant
combination:
100 total
subscriptions.

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.

Receiving change notifications


Microsoft Graph can deliver change notifications to clients via the following channels.

Webhooks. For more information, see Receive change notifications through


webhooks.
Azure Event Hubs. For more information, see Receive change notifications through
Azure Event Hubs.
Azure Event Grid (preview). For more information, see Receive change notifications
through Azure Event Grid.

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.

Resource Maximum expiration time

Security alert 43,200 minutes (under 30 days)

Teams callRecord 4,230 minutes (under 3 days)

Teams channel 60 minutes (1 hour)

Teams chat 60 minutes (1 hour)

Teams chatMessage 60 minutes (1 hour)

Teams 60 minutes (1 hour)


conversationMember

Teams onlineMeeting 4,320 minutes (3 days)

Teams team 60 minutes (1 hour)

Group conversation 4,230 minutes (under 3 days)

OneDrive driveItem 42,300 minutes (under 30 days)

SharePoint list 42,300 minutes (under 30 days)

Outlook message, event, 4,230 minutes (under 3 days)


contact

user, group, other 41,760 minutes (under 29 days)


directory resources
Resource Maximum expiration time

onlineMeeting 4,230 minutes (under 3 days)

presence 60 minutes (1 hour)

Print printer 4,230 minutes (under 3 days)

Print printTaskDefinition 4,230 minutes (under 3 days)

todoTask 4,230 minutes (under 3 days)

Webhooks for this resource are only available in the global endpoint
and not in the national clouds.

baseTask (deprecated) 4,230 minutes (under 3 days)

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.

Receive change notifications through webhooks.


Receive change notifications through Azure Event Hubs.
Receive change notifications through Azure Event Grid (preview).

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.

Resource Average latency Maximum latency

alert 1 Less than 3 minutes 5 minutes

callRecord Less than 15 minutes 60 minutes

channel Less than 10 seconds 60 minutes

chat Less than 10 seconds 60 minutes

chatMessage Less than 10 seconds 1 minute

contact Unknown Unknown

conversation Unknown Unknown

conversationMember Less than 10 seconds 60 minutes

driveItem Less than 1 minute 5 minutes

event Unknown Unknown

group Less than 2 minutes 15 minutes

list Less than 1 minute 5 minutes

message Unknown Unknown

onlineMeeting Less than 10 seconds 1 minute

presence Less than 10 seconds 1 minute

printer Less than 1 minute 5 minutes

printTaskDefinition Less than 1 minute 5 minutes

team Less than 10 seconds 60 minutes

todoTask Less than 2 minutes 15 minutes

user Less than 2 minutes 15 minutes


1
The latency provided for the alert resource is only applicable after the alert is created.
It doesn't include the time it takes for a rule to create an alert from the data.

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.

Use delta query to track changes in a resource


collection
The typical call pattern is as follows:

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.

a. If a @odata.nextLink URL is returned, there may be additional pages of data to


be retrieved in the session. The application continues making requests using the
@odata.nextLink URL to retrieve all pages of data until a @odata.deltaLink URL is

returned in the response.

b. If a @odata.deltaLink URL is returned, there is no more data about the existing


state of the resource to be returned. For future requests, the application uses the
@odata.deltaLink URL to learn about changes to the resource.

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

and the response will contain a @odata.deltaLink and no resource data.


Resources in OneDrive and SharePoint also support this feature. For resources
in OneDrive and SharePoint, append token=latest instead.
The delta query function is generally referred to by appending /delta to the
resource name. However, /delta is a shortcut for the fully qualified name
/microsoft.graph.delta that you see in requests generated by the Microsoft

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 ,

and a @odata.deltaLink URL includes a $deltaToken .

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.

Optional query parameters


If a client uses a query parameter, it must be specified in the initial request. Microsoft
Graph automatically encodes the specified parameter into the @odata.nextLink or
@odata.deltaLink provided in the response. The calling application only needs to
specify the query parameters once upfront. Microsoft Graph adds the specified
parameters automatically for all subsequent requests.

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:

$expand is not supported.

$top is not supported.

$orderby is not supported.

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

groups respectively. Selecting those properties allows tracking of changes to user's


manager and group memberships.

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'

Resource representation in the delta query


response
Newly created instances of a supported resource are represented in the delta
query response using their standard representation.

Updated instances are represented by their id with at least the properties that have
been updated, but additional properties may be included.

Relationships on users and groups are represented as annotations on the standard


resource representation. These annotations use the format propertyName@delta.
The annotations are included in the response of the initial delta query request.

Removed instances are represented by their id and an @removed object. The


@removed object may include additional information about why the instance was
removed. For example, "@removed": {"reason": "changed"} .

Possible @removed reasons can be changed or deleted .

changed indicates the item was deleted and can be restored from deletedItems.

deleted indicates the item is deleted and cannot be restored.

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.

Resource collection API

Applications delta function of the application resource

Administrative units delta function of the administrativeUnit resource

Chat messages in a channel delta function (preview) of the chatMessage


resource

Device objects delta function of the device resource

Directory roles delta function of the directoryRole resource

Directory objects delta function of the directoryObject resource

Drive items* delta function of the driveItem resource

Education assignments delta function of the educationAssignment


resource

Education categories delta function of the educationCategory resource

Education classes delta function of the educationClass resource

Education schools delta function of the educationSchool resource

Education users delta function of the educationUser resource

Events in a calendar view (date range) of the delta function of the event resource
primary calendar

Groups delta function of the group resource

List items* delta function of the listItem resource

Mail folders delta function of the mailFolder resource

Messages in a folder delta function of the message resource

Organizational contacts delta function of the orgContact resource


Resource collection API

OAuth2PermissionGrants delta function of the oauth2permissiongrant


resource

Personal contact folders delta function of the contactFolder resource

Personal contacts in a folder delta function of the contact resource

Planner buckets (preview) delta function (preview) of the plannerBucket


resource

Planner items** (preview) delta function (preview) of the all segment of


plannerUser resource

Planner plans (preview) delta function (preview) of the plannerPlan


resource

Planner tasks (preview) delta function (preview) of the plannerTask


resource

Service principals delta function of the servicePrincipal resource

To-do tasks in a task list delta function of the todoTask resource

To-do task lists delta function of the todoTaskList resource

Users delta function of the user resource

* 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

Properties stored outside of the main data store


Some resources contain properties that are stored outside of the main data store for the
resource (for example, the user resource is mostly stored in the Azure AD system, while
some properties, like skills, are stored in SharePoint Online). Currently, those properties
are not supported as part of change tracking; a change to one of those properties will
not result in an object showing up in the delta query response. Currently, only the
properties stored in the main data store trigger changes in the delta query.

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

HTTP/1.1 501 Not Implemented


Content-type: application/json

{
"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.

For directory objects, the limit is seven days.


For education objects (educationSchool, educationUser, and educationClass), the
limit is seven days.
For Outlook entities (message, mailFolder, event, contact, contactFolder,
todoTask, and todoTaskList), the upper limit is not fixed; it's dependent on the size
of the internal delta token cache. While new delta tokens are continuously added
in the cache, after the cache capacity is exceeded, the older delta tokens are
deleted.

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.

Delta query request examples


Training module: Use change notifications and track changes with Microsoft Graph
Get incremental changes to events in a calendar view
Get incremental changes to messages in a folder
Get incremental changes to groups
Get incremental changes to users
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

Do not use extensions to store sensitive personally identifiable information, such as


account credentials, government identification numbers, cardholder data, financial
account data, healthcare information, or sensitive background information.

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?

Why add custom data to Microsoft Graph?


As an ISV developer, you might decide to keep your app lightweight and store
app-specific user profile data in Microsoft Graph by extending the user resource.
Alternatively, you might want to retain your app's existing user profile store, and
add an app-specific identifier to the user resource.
As an enterprise developer, the in-house applications that you build might rely on
your organization's HR-specific data. Integration within multiple applications can
be simplified by storing this custom data in Microsoft Graph.

Custom data options in Microsoft Graph


Microsoft Graph offers four types of extensions for adding custom data.

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.

Add or update data in extension attributes


The following example shows how to store data in extensionAttribute1 and delete
existing data from extensionAttribute13 through an update operation with a PATCH
method.

HTTP

HTTP

PATCH https://graph.microsoft.com/v1.0/users/071cc716-8147-4397-a5ba-
b2105951cc0b

{
"onPremisesExtensionAttributes": {
"extensionAttribute1": "skypeId.adeleVance",
"extensionAttribute13": null
}
}

The request returns a 204 No Content response object.

Read the extension attributes


Request

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
}
}
]
}

Considerations for using extension attribute properties


The onPremisesExtensionAttributes object can be updated only for objects that aren't
synced from on-premises AD.

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.

Directory (Azure AD) extensions


Directory extensions provide developers with a strongly typed, discoverable and
filterable extension experience for directory objects.

Directory extensions are first registered on an application through the Create


extensionProperty operation and must be explicitly targeted to specific and supported
directory objects. After the application has been consented to by a user or an admin, the
extension properties become immediately accessible in the tenant. All authorized
applications in the tenant can read and write data on any extension properties defined
on an instance of the target directory object.

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.

Define the directory extension

Before you can add a directory extension to a resource instance, you must first define
the directory extension.

Request

In the following request, 30a5435a-1871-485c-8c7b-65f69e287e7b is the object ID of the


application that owns the directory extension. On the beta endpoint, you can create
directory extensions that store a collection of values.
HTTP

HTTP

POST https://graph.microsoft.com/v1.0/applications/30a5435a-1871-485c-
8c7b-65f69e287e7b/extensionProperties

{
"name": "jobGroupTracker",
"dataType": "String",
"targetObjects": [
"User"
]
}

Response

A directory extension property named


extension_b7d8e648520f41d3b9c0fdeb91768a0a_jobGroupTracker is created with an

extension name that follows the following naming convention: extension_{appId-


without-hyphens}_{extensionProperty-name}.

HTTP

HTTP/1.1 201 Created


Content-type: application/json

{
"@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"
]
}

Add a directory extension property to a target object


After defining the directory extension, you can now add it to an instance of a target
object type. You can store data in the directory extension when creating a new instance
of the target object or when updating an existing object. The following example shows
how to store data in the directory extension when creating a new user object.

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.

Retrieve a directory extension


The following example shows how the directory extensions and associated data are
presented on a resource instance. The extension property will be returned by default
through the beta endpoint, but only on $select through the v1.0 endpoint.

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
}
]
}

Update or delete directory extensions

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"
}

The request returns a 204 No Content response code.


Considerations for using directory extensions
If you accidentally delete a directory extension definition, any data that's stored in the
associated property becomes undiscoverable. To resolve this, create a new directory
extension definition on the same owner app and with exactly the same name as the
deleted definition.

When a definition object is deleted before the corresponding extension property is


updated to null , the property will still count against the 100-limit for the object.

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.

Define a schema extension

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"
}
]
}

Add a schema extension to a resource instance


After defining the schema extension, you can now add the extension property to an
instance of a target object type. You can store data in the schema extension when
creating a new instance of the target object or when updating an existing object. The
following example shows how to store data in the schema extension property when
creating a new user object.

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

Update or delete a schema extension property


Use the PATCH operation to update a schema extension or delete an existing schema
extension. To delete the extension property and its associated value from the resource
instance, set its value to null .

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
}
}

The request returns a 204 No Content response object.

Retrieve the schema extension property


To read the schema extension properties on a resource instance, specify the extension
name in a $select request.

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
}
}

Considerations for using schema extensions


A schema extension must have an owner app. Ownership of the schema extension can't
be reassigned to another app.

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.

Create an open extension


The following example shows an open extension definition with three properties and
how the custom properties and associated data are presented on a resource instance.

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.

Update an existing open extension

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"
}

This request returns a 204 No Content response code.

Retrieve the open extensions

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"
}

Considerations for using open extensions


Deleting a creator app doesn't affect the open extension and the data it stores.

Comparison of extension types


The table below contrasts and compares the extension types, which should help you
decide which option is most appropriate for your scenario.

Capability Extension Directory Schema Open


attributes 1-15 extensions extensions extensions
Capability Extension Directory Schema Open
attributes 1-15 extensions extensions extensions

Supported resource user user user user


types device group group group
administrativeUnit administrativeUnit contact
application contact device
device device event1 (both
organization event (both user user and
and group group
calendars) calendars)
message message
organization organization
post post
todoTask
todoTaskList

Strongly typed No Yes Yes No

Filterable Yes Yes Yes No

Can store a No Yes No No


collection2

Managed via Microsoft Microsoft Graph Microsoft Graph Microsoft


Graph Graph
Exchange
admin center

Sync data from on- Yes, for users Yes No No


premises to
extensions using
AD connect

Create dynamic Yes Yes No No


membership rules
using custom
extension
properties and data

Usable for Yes Yes No No


customizing token
claims

Available in Azure Yes Yes Yes Yes


AD B2C
Capability Extension Directory Schema Open
attributes 1-15 extensions extensions extensions

Limits 15 100 extension Maximum of Two open


predefined values per five definitions extensions per
attributes per resource instance per owner app creator app
user or device 100 extension per resource
resource values per instance3
instance resource instance Max. of 2
(directory objects Kb per open
only) extension3
For
Outlook
resources,
each open
extension is
stored in a
MAPI named
property4

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.

Permissions and privileges


The same privileges that your app requires to read from or write to a resource instance
are also required to manage any extensions data on that resource instance. For example,
for an app to update any user's profile with custom app data, the app must have been
granted the User.ReadWrite.All Microsoft Graph permission.

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.

Use the following steps to create and link a Microsoft.GraphServices/accounts Azure


resource to your application:

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 create to create a new instance of the


Microsoft.GraphServices/accounts resource type to associate your application
registration with the active subscription. 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 newly created resource.

Azure Cloud Shell

PowerShell

az resource create --resource-group myRG --name myGraphAppBilling --


resource-type Microsoft.GraphServices/accounts --properties "
{`"appId`": `"myAppGUID`"}" --location Global --subscription
mySubscriptionGUID
Parameter Description

myRG The name of an existing Azure resource group to add the newly created
resource to.

myGraphAppBilling The name you want to give to this resource instance.

myAppGUID The Application (client) ID of the application being enabled, provided as a


string parameter; for example, 00000000-0000-0000-0000-000000000000.

mySubscriptionGUID The ID of the Azure subscription that will receive billing events, provided
as a string parameter; for example, 00000000-0000-0000-0000-
000000000000.

A successful JSON result will look something like this:

{
"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

az resource list --resource-type Microsoft.GraphServices/accounts

A successful JSON result will look something like this:

[
{
"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

az resource show --resource-group myRg --name myGraphAppBilling --


resource-type Microsoft.GraphServices/accounts

Parameter Description

myRG The name of the Azure resource group provided in the result of step 2.

myGraphAppBilling The name of the resource provided in the result of step 2.

A successful JSON result will look something like this:

{
"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.

Consume metered APIs in your application


After you associate your application registration and subscription, your application can
start using metered APIs and services in Microsoft Graph. Costs generated from those
requests will be charged to the Azure subscription associated with the application.

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.

Bills for metered API and service usage


After the subscription billing cycle runs, typically on the 5th day of the month, a
subscription owner or users with role-based permissions can download an invoice. For
details, see View and download your Azure invoice.

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.

Use Graph Explorer to:

Try out Microsoft Graph APIs.


Learn about the permissions required for the different APIs.
Explore all the resources available on Microsoft Graph.
Explore Microsoft Graph Toolkit components, adaptive cards and code snippets for
your queries.

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.

Retrieve data in Graph Explorer


To run a GET request in Graph Explorer, you don't have to sign in. You can retrieve
sample data from the default sample tenant.

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.

Modify data in Graph Explorer


To try POST, PUT, PATCH, and DELETE requests, sign in to Graph Explorer by using a
Microsoft 365 account. This can be an organizational account for testing or
demonstration purposes. To get a free instant sandbox preconfigured with sample data
packs to test with, join the Microsoft 365 Developer Program.

) Important

If you choose to sign in by using your organizational account, running a non-GET


request might affect the data in the tenant.

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.

Tenant: View the tenant you are currently using.


Settings: Access Graph Explorer settings to change the interface theme or to get a
free instant sandbox preconfigured with sample data packs.
Help: Access useful links such as the documentation or the GitHub repo for Graph
Explorer.
Feedback: If you want to provide feedback, you can fill in the survey form.
Profile avatar: Sign in, view your profile, consent to permissions, switch accounts,
or sign out of your account. For details about consenting to permissions, see
Consent to permissions.

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:

1. Select a sample query and run it.


2. Select the Modify permissions tab.
3. See the list of permissions required to run the query.
4. Select the Consent button next to the permission that you want to consent to.

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:

Export all history items in .har format.


Delete all history items.
View a history item.
Run a query.
Export a history item in .har format.
Delete a history item.
To share queries that you run, select the Share button situated next to the Run query
button, and then select Copy. This copies a shareable link that allows others to see your
query and the results.

Query area
Use the query area to run requests and see the responses. The query area includes the
following elements:

HTTP methods: A dropdown list of the HTTP methods.


API version: A dropdown list of the API versions available publicly.
Query box: A bar where you can manually build your query, or see the
autopopulated query if you selected one from the left pane.
Request body: A space to write the request body in JSON format or MIME content,
according to the desired request.
Request headers: A section to add headers to your request by specifying the key
and value.
Modify permissions: You need to consent to the right permissions to be able to
run a query. For details, see consenting to permissions.
Access token: This tab shows your access token when you're signed in. You can
copy the token if you need to use it in your favorite REST client application.

When you run a query, you will see a Response preview and Response headers in the
response pane.

In addition to the response, this pane also includes:

Code snippets
Microsoft Graph Toolkit integration
Adaptive cards integration

Use the power of the client libraries


For each REST API query that you select or enter in Graph Explorer, you can find how to
make that call in each of the supported languages: C#, Java, JavaScript, Go and
PowerShell.
Microsoft Graph Toolkit integration
Microsoft Graph Toolkit is a collection of reusable, framework-agnostic web components
and helpers for accessing and working with Microsoft Graph. The components are fully
functional, with built-in providers that authenticate with and fetch data from Microsoft
Graph.

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.

Adaptive cards integration


Adaptive cards are platform-agnostic snippets of UI, authored in JSON, that apps and
services can openly exchange. A blue dot on the Adaptive cards tab indicates that an
adaptive card is available for the selected query.
Next steps
Visit Graph Explorer and start learning about Microsoft Graph.
Explore the Microsoft Graph Toolkit documentation.
Contribute or provide feedback in the Graph Explorer GitHub repo .
Use Postman with the Microsoft Graph
API
Article • 11/11/2022

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.

Update the request URL, replacing graph.microsoft.com with the Microsoft


Graph service root endpoint for your national cloud.
Update the Auth URL and Access Token URL values on the Authorization tab
of the Delegated and Application folders, replacing
login.microsoftonline.com with the Azure AD endpoint for your national

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.

Step 1: Fork the Microsoft Graph Postman


collection
To use the Postman collection, fork it to your own Postman workspace. Do this from the
web browser.

1. Go to Postman and sign in.


2. Go to the Postman collection labeled Microsoft Graph .
3. Fill in a label for your own fork; this can be any text.
4. Under Workspace, ensure that My Workspace is selected in the dropdown list.
5. Select Fork Collection.

You are redirected to a fork of the main Microsoft Graph Postman collection in your own
workspace.

Step 2: Download the Postman Agent (optional


- Postman web browser only)
To use this particular 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.

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.

1. Go to portal.azure.com and sign in with your developer tenant administrator


account.
2. Under Azure Services, select Azure Active Directory.
3. On the left menu, select App registrations.
4. On the horizontal menu, select New registration.
5. Set the Application name to Postman .
6. From the dropdown menu, select Web.
7. Set the Redirect URI to https://oauth.pstmn.io/v1/browser-callback .
8. Select Register.
9. On the left menu, select API Permissions.
10. On the horizontal menu, select Add a permission, select Microsoft Graph, and
then select Delegated Permissions.
11. Type Mail. , expand the Mail options, and then select Mail.Read .
12. Select Application permissions, type User. , and then select Application
Permissions.
13. Expand the User options, and then select User.Read.All .
14. Select Add permissions.
15. On the horizontal menu, select Grant admin consent for, and then select Yes.
16. On the left menu, select Overview. From here, you can get the application (client)
ID and directory (tenant) ID. You'll need these in step 4.
17. On the left menu, select Certificates and secrets.
18. Select New client secret, enter a description, and then select Add. Hover over the
new client secret Value and copy it; you'll need this in step 4.

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.

Step 4: Configure authentication


In this step, you set up the environment variables in Postman that you use to retrieve an
access token.

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.

Step 5: Get a delegated access token


Because this is the first time that you are running a request as a delegated
authentication flow, you need to get an access token.

1. Select the Delegated folder.


2. Select the Authorization tab.
3. In the Configure New Token section, select the Configuration Options tab. Make
sure the call back URL matches with what you provided when you created the
application registration. Leave all the fields as pre-configured, including the Grant
type, which is set to Authorization Code .
4. Scroll down on the right and select Get New Access Token.
5. Sign in with your developer tenant administrator account.
6. Select Proceed, and then select the Use Token button.

You now have a valid access token to use for delegated requests.

Step 6: Run your first delegated request


Inside the Delegated folder are requests for various Microsoft Graph workloads that you
can call.

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.

Step 7: Get an application access token


Because this is the first time that you are running a request as an application
authentication flow, you need to get an access token.

1. Select the Application folder.


2. Select the Authorization tab.
3. In the Configure New Token section, select the Configuration Options tab. Leave
all the fields as pre-configured, including the Grant type, which is set to Client
Credentials .
4. Scroll down on the right and select Get New Access Token.
5. Select Proceed, and then select the Use Token button.

You now have a valid access token to use for application requests.

Step 8: Run your first application request


Inside the Application folder are requests for various Microsoft Graph workloads that
you can call.

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.

Contribute to the collection


If you want to contribute your own requests, you need a Postman license. You can make
your changes to the forked collection, and then hover over the collection top node and
select Create pull request.

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.

"Access to OData is disabled."


See 403 Forbidden "Access to OData is disabled.".

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.

Why use Microsoft Graph?


Microsoft Graph represents our best-in-breed API surface. It offers a single unified
endpoint to access Azure AD services and Microsoft 365 services such as Microsoft
Teams and Microsoft Intune. Microsoft Graph API's usage has more than doubled that of
Azure AD Graph, and in the past two years we have added 167 new features. All new
functionalities will only be available through the Microsoft 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.

Switch to Microsoft Graph to take advantage of these enhanced capabilities and:

Microsoft 365 group management.


External user invitations.
The ability to restore users, Microsoft 365 groups, applications, and service
principals after they've been deleted.
Webhook notifications on users and groups.
Advanced license management features including group-based licensing.
Identity governance features such as:
Privileged identity management (PIM) to elevate users to privileged roles only
when needed and for a limited time period.
Access reviews for one-time or recurring access reviews for attestation of user's
access rights.
Terms-of-use to enable organizations to present information for legal or
compliance requirements, like disclaimer notices.
Security features such as:
Identity risk events.
Risky users.
Client libraries and samples available on many more platforms and languages.
Microsoft Graph SDKs provide a discoverable interface to easily access your data
while transparently handling token acquisition, retry handling due to errors and
throttling, secure redirect handling and model serialization and deserialization.
More OData query capabilities supported by resources such as users, groups,
applications, and service principals.

The rest of the articles in this section help you migrate your app from Azure AD Graph
to Microsoft Graph. You'll find:

A checklist to help you plan the migration.


Guidance describing specific differences between the APIs.
Links to more resources and examples to illustrate specific differences.
An FAQ to address other questions or concerns.

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.

Step 1: Review the differences between the APIs


In many respects, Microsoft Graph is similar to the earlier Azure AD Graph. In many
cases, simply change the endpoint service name and version in your code, and
everything should continue to work.

Nonetheless, there are differences. Certain resources, properties, methods, and core
capabilities have changed.

Specifically, look for differences in the following areas:

Request call syntax between the two services


Feature differences, such as directory extensions, batching, differential queries, and
so on
Entity resource names and their types
Properties of request and response objects
Methods, including parameters and types
Permissions

Step 2: Examine API use


Examine the APIs used by your app, the permissions they require, and compare to the
list of known differences.

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.

Step 4: Deploy, test, and extend your app


Before updating your app for everyone, ensure you test thoroughly and stage your
rollout to your customer audience.

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.

Microsoft authentication library (MSAL) is now the recommended authentication library


for use with the Microsoft identity platform. If you're currently using the Azure Active
Directory Authentication Library (ADAL), plan to switch to MSAL. See further guidance to
migrate applications to the Microsoft Authentication Library (MSAL).

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:

Request details Azure AD Graph Microsoft Graph

Request syntax https://graph.windows.net/{tenant_id}/ https://graph.microsoft.com/


{resource}?{version}&query-parameters {version}/{resource}?query-parameters

Service endpoints:

- Global https://graph.windows.net https://graph.microsoft.com

- US Gov L4 https://graph.microsoftazure.us https://graph.microsoft.us

- US Gov L5 (DOD) https://graph.microsoftazure.us https://dod-graph.microsoft.us

- Germany https://graph.cloudapi.de https://graph.microsoft.de

- China (21Vianet) https://graph.chinacloudapi.cn https://microsoftgraph.chinacloudapi.cn

{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.

If you specify the tenant ID, it goes


between the {version} and the
{resource} in the request URL.

{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.

Example request comparison


Suppose you want a list of all users with names beginning with "Dan".

In Azure AD Graph, you might use this request:

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:

Targets version 1.6 of Azure AD Graph.


Specifies contoso.com as the tenant ID. The alternative shows the use of an alias
myOrganization based on the tenant ID in the access token.

Calls the users resource.


Uses the $filter query parameter to limit the response to given names that begin
with Dan .

Results include users with names like Daniel, Danforth, Danielle, Danerys, and so on.

A similar request for Microsoft Graph would be:

GET https://graph.microsoft.com/v1.0/users?$filter=startswith(givenName,'Dan')

Here:

The version is v1.0 .


The tenant ID is inferred from the access token (not shown).
The resource and $filter query parameter are the same as the Azure AD query.

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.

Key identifiers: objectId vs id


In Azure AD Graph, all entity resource types have a unique identifier (or key) called
objectId. For the most part (unless otherwise stated) this same identifier is called id in
Microsoft Graph.

Default properties and $select


Use the $select query parameter, in GET requests, to customize the response to include
all the properties that your app requires.

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.

To learn more about:

Default properties on user, see users


The $select parameter and other supported ODATA query parameters, see Use
query parameters to customize responses.
This and other recommended optimizations, see Best practices.

Relationships and navigation properties


Relationships (or navigation properties) are a key concept in Azure AD Graph and
Microsoft Graph, creating a network of related resources. For example, the manager and
directReports properties extend the user resource to provide organizational hierarchy.

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.

Azure AD Graph requests use $links to indicate relationships between resources. In


Microsoft Graph this uses the OData v4.01 $ref notation instead.

The following table shows several examples:

Task Azure AD Graph Microsoft Graph

Add member POST /groups/{id}/$links/members POST /groups/{id}/members/$ref

List member GET /groups/{id}/$links/members GET /groups/{id}/members/$ref


links

List members GET /groups/{id}/members GET /groups/{id}/members

Remove DELETE DELETE


member /groups/{id}/$links/members/{id} /groups/{id}/members/{id}/$ref

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.

This article explores how Microsoft Graph handles:

Directory schema extensions


Differential queries
Batching

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:

Manage directory extension definitions using the extensionProperty resource and


associated methods.
Get available extension properties using the getAvailableExtensionProperties
action.
Read extension values using GET and for users, only with a $select query via the
v1.0 endpoint
Search on extension values using GET and $filter
Update extension values using PATCH
Remove extension values using PATCH (set to null)

Microsoft Graph provides an enhanced schema extensions developer experience, which


today is not backwards compatible with Azure AD Graph directory extensions. To learn
more, see Choose an extension type for your application.

Recommended migration approach


If your Azure AD Graph app uses directory extensions, take an incremental approach to
migrate the app to Microsoft Graph.
First, switch your app to using Microsoft Graph API calls, but let the app continue to
leverage Azure AD Graph directory extensions.

Then, you can switch to using Microsoft Graph schema extensions. In some cases,
switching will not be appropriate. Do not switch if:

Your app uses directory extensions created through AD Connect


Your app sets directory extension values that are used in token claims by other
apps
Your app sets directory extension values that are used in dynamic membership
rules

NOTE: Using Microsoft Graph schema extension properties as claims in a token


using optional claims or in a dynamic membership rule is not yet supported.

To switch to the newer Microsoft Graph schema extension model, you'll need to:

Define new schema extension definitions using Microsoft Graph.


Update the app to support the new schema extension definitions.
Migrate the data from the Azure AD schema extension properties to the new
Microsoft Graph schema extension properties. Automatic migration of data is not
supported.

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.

The following table highlights key similarities and differences:

Delta request Azure AD Graph Microsoft Graph

Initial data Uses a query parameter: Uses a function:


request GET /groups?deltaLink= GET /groups/delta

Get new GET /groups?deltaLink= GET /groups/delta?$deltaToken={deltaToken}


changes {deltaToken}

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=

Get resource All requests return resource GET /groups/delta?$expand=members


and relationship and relationship changes, if
changes the resource has
relationships.

Response Represents newly Represents newly created instances


indicating new created instances using using their standard representation.
and changed their standard Updated instances are represented by
items representation. their id with at least the properties that
Updated instances are have been updated. Other properties
represented by their id may be included.
with at least the Relationships are represented as
properties that have annotations on the standard resource
been updated. Other representation. These annotations use
properties may be the format propertyName@delta , for
included. example members@delta for a group's
Relationships are membership changes.
represented as the
directoryLinkChange
type.

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

Resource type names in Azure AD Graph are Pascal-cased, whereas in Microsoft


Graph they are camel-cased.

Azure AD Graph Microsoft Graph Comments


(v1.6) resource resource

CertificateAuthorityInformation beta - certificateAuthority


v1.0 - certificateAuthority

Contact beta - orgContact


v1.0 - orgContact

DirectoryLinkChange beta - New approach Delta query supports


v1.0 - New approach relationship change
detection with a mechanism
that doesn't require this
resource. Please see Feature
differences between Azure
AD Graph and Microsoft
Graph.
Azure AD Graph Microsoft Graph Comments
(v1.6) resource resource

OAuth2Permission beta - permissionScope


v1.0 - permissionScope

Policy beta - policies Each type of policy has a


v1.0 - policies unique type name and
structure, under the policies
URL path segment, in
Microsoft Graph. In Azure
AD Graph this was a single
policy type. For example, for
Azure AD Graph you would
work with the Policy
resource, and set the type
property to
TokenIssuancePolicy , while
in Microsoft Graph this
would be the
tokenIssuancePolicy
resource.

ProvisioningError beta - Not available This resource is deprecated.


v1.0 - Not available However, a new resource
describing any AD Connect
related provisioning errors
can be found in
onPremisesProvisioningError.

ServiceEndpoint beta - endpoint endpoints are only available


v1.0 - endpoint as part of the group
resource in beta, and the
servicePrincipal resource in
both beta and v1.0.

SignInName beta - New approach New modeling for the


v1.0 - New approach identifiers used to sign into a
user account. See
objectIdentity resource type
for more details. Supports
Azure AD B2C scenarios.

TenantDetail beta - organization


v1.0 - organization

TrustedCasForPasswordAuth beta - certificateBasedAuthConfiguration


v1.0 - certificateBasedAuthConfiguration
Azure AD Graph Microsoft Graph Comments
(v1.6) resource resource

UserIdentity beta - objectIdentity New modeling for the


v1.0 - objectIdentity identifiers used to sign into a
user account, called
objectIdentity. Supports
Azure AD B2C scenarios.

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:

Azure AD Graph metadata


Microsoft Graph beta metadata
Microsoft Graph v1.0 metadata

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.

User property differences


The Azure AD Graph User resource inherits from DirectoryObject; it has been renamed to user in Microsoft Graph and
inherits from directoryObject.

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.

The following table lists the additional property differences.

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

deletedTimestamp beta - deletedDateTime


v1.0 - deletedDateTime

dirSyncEnabled beta - onPremisesSyncEnabled


v1.0 - onPremisesSyncEnabled

facsimileTelephoneNumber beta - faxNumber


v1.0 - faxNumber

immutableId beta - onPremisesImmutableId


v1.0 - onPremisesImmutableId

isCompromised beta - Not available The Microsoft Graph identity


v1.0 - Not available protection API provides more
sophisticated functionality.

lastDirSyncDateTime beta - onPremisesLastSyncDateTime


v1.0 - onPremisesLastSyncDateTime

mobile beta - mobilePhone


v1.0 - mobilePhone

passwordProfile/enforceChangePasswordPolicy beta - passwordProfile/forceChangePasswordNextSignIn


v1.0 - passwordProfile/forceChangePasswordNextSignIn

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


v1.0 - Not available information is deprecated.
However, a new property
describing any AD Connect
related provisioning errors can
be found in
onPremisesProvisioningErrors

refreshTokensValidFromDateTime beta - signinSessionsValidFromDateTime


v1.0 - signinSessionsValidFromDateTime

signinNames beta - identities/signInType This property is now part of


v1.0 - identities/signInType the objectIdentity resource.

telephoneNumber beta - businessPhones


v1.0 - businessPhones

thumbnailPhoto beta - photo, photos The Azure AD thumbnail


v1.0 - photo, photos photo is not available through
Microsoft Graph. Use the
photo API instead.

userIdentities beta - identities See objectIdentity resource


v1.0 - identities type for more details.

userState beta - externalUserState


v1.0 - externalUserState

userStateChangedOn beta - externalUserStateChangeDateTime


v1.0 - externalUserStateChangeDateTime

Group property differences


The Azure AD Graph Group resource inherits from DirectoryObject; it has been renamed to group in Microsoft Graph and
inherits from directoryObject. Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

dirSyncEnabled beta - onPremisesSyncEnabled


v1.0 - onPremisesSyncEnabled

lastDirSyncDateTime beta - onPremisesLastSyncDateTime


v1.0 - onPremisesLastSyncDateTime

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

Application property differences


The Azure AD Graph Application resource inherits from DirectoryObject; it has been renamed to application in Microsoft
Graph and inherits from directoryObject. Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

acceptMappedClaims beta - api/acceptMappedClaims acceptMappedClaims is now part of


v1.0 - api/acceptMappedClaims the new api resource.
Azure AD Graph Microsoft Graph Comments
(v1.6) property property

availableToOtherTenants beta - signInAudience The default value for


v1.0 - signInAudience availableToOtherTenants is false
(meaning AzureADMyOrg ) while for
signInAudience is
AzureADandPersonalMicrosoftAccount .

errorUrl beta - not available This property is deprecated.


v1.0 - not available

homepage beta - web/homePageUrl homepage is now part of the new


v1.0 - web/homePageUrl web resource.

informationalUrls beta - info


v1.0 - info

knownClientApplications beta - api/knownClientApplications knownClientApplications is now part


v1.0 - api/knownClientApplications of the new api resource.

logoutUrl beta - web/logoutUrl logoutUrl is now part of the web


v1.0 - web/logoutUrl resource.

logoUrl beta - info/logoUrl logoUrl is now part of the new info


v1.0 - info/logoUrl resource.

mainLogo beta - logo


v1.0 - logo

oauth2AllowIdTokenImplicitFlow beta - web/implicitGrantSettings/enableIdTokenIssuance Renamed, and now part of the new


v1.0 - web/implicitGrantSettings/enableIdTokenIssuance implicitGrantSettings resource.

oauth2AllowImplicitFlow beta - web/implicitGrantSettings/enableAccessTokenIssuance Renamed, and now part of the new


v1.0 implicitGrantSettings resource.
- web/implicitGrantSettings/enableAccessTokenIssuance

oauth2AllowUrlPathMatching beta - not available This property is deprecated.


v1.0 - not available

oauth2Permissions beta - api/oauth2PermissionScopes Renamed and now part of the new


v1.0 - api/oauth2PermissionScopes api resource.

publicClient beta - isFallbackPublicClient This property now has a new


v1.0 - isFallbackPublicClient meaning - it contains the public
client settings like redirectUris.
Determining whether the app is a
public or confidential client or not is
now done automatically, with the
isFallbackPublicClient property
handling the one special case that
cannot be determined automatically.

recordConsentConditions beta - not available This property is deprecated.


v1.0 - not available

replyUrls beta - web/redirectUris, publicClient/redirectUris As well as being renamed,


v1.0 - web/redirectUris, publicClient/redirectUris redirectUris is now part of the new
web and publicClient resources. This
allows developers to use specific
URIs for their web and public clients
(such as an installed application on a
desktop device).

samlMetadataUrl beta - samlMetadataUrl


v1.0 - Not yet available

serviceEndpoints beta - Not available This property is deprecated, but is


v1.0 - Not available planned for servicePrincipal.
AppRoleAssignment differences
The Azure AD Graph AppRoleAssignment resource inherits from DirectoryObject; it has been renamed to
appRoleAssignment in Microsoft Graph and inherits from directoryObject. Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

creationTimestamp beta - creationTimestamp


v1.0 - createdDateTime

id beta - appRoleId
v1.0 - appRoleId

Contact property differences


The Azure AD Graph Contact resource inherits from DirectoryObject; it has been renamed to orgContact in Microsoft
Graph and inherits from directoryObject. Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

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.

dirSyncEnabled beta - onPremisesSyncEnabled


v1.0 - onPremisesSyncEnabled

facsimileTelephoneNumber beta - phones/businessFax Now part of the phones collection which supports various phone
v1.0 - phones/businessFax types.

physicalDeliveryOfficeName beta - officeLocation


v1.0 - officeLocation

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 .

sipProxyAddress beta - imAddresses


v1.0 - imAddresses

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.

thumbnailPhoto beta - Not yet available


v1.0 - Not yet available

Contract property differences


The Azure AD Graph Contract resource inherits from DirectoryObject; it has been renamed to contract in Microsoft Graph
and inherits from directoryObject. Here are the property differences:
Azure AD Graph Microsoft Graph Comments
(v1.6) property property

customerContextId beta - customerId


v1.0 - customerId

Device property differences


The Azure AD Graph Device resource inherits from DirectoryObject; it has been renamed to device in Microsoft Graph and
inherits from directoryObject. Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

approximateLastLogonTimestamp beta - approximateLastSignInDateTime


v1.0 - approximateLastSignInDateTime

complianceExpiryTime beta - complianceExpirationDateTime


v1.0 - complianceExpirationDateTime

deviceObjectVersion beta - deviceVersion


v1.0 - deviceVersion

deviceOSType beta - operatingSystem


v1.0 - operatingSystem

deviceOSVersion beta - operatingSystemVersion


v1.0 - operatingSystemVersion

devicePhysicalIds beta - physicalIds


v1.0 - physicalIds

deviceTrustType beta - trustType


v1.0 - trustType

dirSyncEnabled beta - onPremisesSyncEnabled


v1.0 - onPremisesSyncEnabled

lastDirSyncTime beta - onPremisesLastSyncDateTime


v1.0 - onPremisesLastSyncDateTime

DirectoryObject property differences


The Azure AD Graph DirectoryObject resource has been renamed to directoryObject in Microsoft Graph. The changes to its
properties will also be seen in other resources that inherit from DirectoryObject. Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

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 .

DirectoryObjectReference property differences


The Azure AD Graph DirectoryObjectReference resource inherits from DirectoryObject; it has been renamed to
directoryObjectPartnerReference in Microsoft Graph and inherits from directoryObject. Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

externalContextId beta - externalPartnerTenantId


v1.0 - externalPartnerTenantId

Domain property differences


The Azure AD Graph Domain resource has been renamed to domain in Microsoft Graph. Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

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.

isDefaultForCloudRedirections beta - Not yet available


v1.0 - Not yet
available

OAuth2PermissionsGrant property differences


The Azure AD Graph OAuth2PermissionsGrant resource has been renamed to oAuth2PermissionsGrant in Microsoft Graph.
Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property 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

Policy property differences


In Microsoft Graph, there are named policy types (such as tokenIssuancePolicy or tokenLifetimePolicy) rather than a
generic policy resource type. More details are available in the policy overview.

ServiceEndpoint property differences


The Azure AD Graph ServiceEndpoint resource inherits from DirectoryObject; it has been renamed to endpoint in Microsoft
Graph and inherits from directoryObject. Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

serviceId beta - providerId


v1.0 - providerId

serviceName beta - providerName


v1.0 - providerName
Azure AD Graph Microsoft Graph Comments
(v1.6) property property

resourceId beta - providerResourceId


v1.0 - providerResourceId

ServicePrincipal property differences


The Azure AD Graph ServicePrincipal resource inherits from DirectoryObject; it has been renamed to servicePrincipal in
Microsoft Graph and inherits from directoryObject. Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

appOwnerTenantId beta - appOwnerOrganizationId Renamed.


v1.0 - appOwnerOrganizationId

informationalUrls beta - info


v1.0 - info

oauth2Permissions beta - publishedPermissionScopes Renamed.


v1.0 - oauth2PermissionScopes

preferredTokenSigningKeyEndDateTime beta - Not yet available


v1.0 - Not yet available

signInAudience beta - Not yet available


v1.0 - Not yet available

serviceEndpoints beta - endpoint Renamed.


v1.0 - endpoint

TenantDetails property differences


The Azure AD Graph TenantDetail resource inherits from DirectoryObject; it has been renamed to organization in Microsoft
Graph and inherits from directoryObject. Here are the property differences:

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

companyLastDirSyncTime beta - onPremisesLastSyncDateTime


v1.0 - onPremisesLastSyncDateTime

dirSyncEnabled beta - onPremisesSyncEnabled


v1.0 - onPremisesSyncEnabled

provisioningErrors beta - Not available This property and its information is deprecated.
v1.0 - Not available

telephoneNumber beta - businessPhones


v1.0 - businessPhones

TrustedCasForPasswordlessAuth property differences


The Azure AD Graph TrustedCasForPasswordlessAuth resource has been renamed to certificateBasedAuthConfiguration.
There are no property differences; however, there are differences in the certificateAuthority resource type used by the
certificateAuthorities property.

CertificateAuthorityInformation property differences


The Azure AD Graph CertificateAuthorityInformation has been renamed to certificateAuthority in Microsoft Graph. The
following are the property differences.

Azure AD Graph Microsoft Graph Comments


(v1.6) property property

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".

crlDistributionPoint beta - certificateRevocationListUrl


v1.0 - certificateRevocationListUrl

deltaCrlDistributionPoint beta - deltaCertificateRevocationListUrl


v1.0 - deltaCertificateRevocationListUrl

trustedCertificate beta - certificate


v1.0 - deltaCertificateRevocationListUrl

trustedIssuer beta - issuer


v1.0 - issuer

trustedIssuerSki beta - issuerSki


v1.0 - issuerSki

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.

Azure AD Graph Microsoft Graph Comments


(v1.6) method (resource/method)

getAvailableExtensionProperties beta - Not available


v1.0 - directoryObjects/getAvailableExtensionProperties

getObjectsByObjectId beta - directoryObjects/getByIds


v1.0 - directoryObjects/getByIds

invalidateAllRefreshTokens beta - revokeSignInSessions


v1.0 - revokeSignInSessions

isMemberOf beta - Not planned Use


v1.0 - Not planned checkMemberGroups
instead.

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.

The article provides a mapping of Azure AD Graph to Microsoft Graph permissions to


help you migrate your apps.

Application.Read.All

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID Not available c79f8feb-a9db-4090-85f9-90d820caa0eb

Display String Not available Read applications

Admin consent required? Not available Yes

Application

Parameter Azure AD Graph Microsoft Graph


Parameter Azure AD Graph Microsoft Graph

Permission 3afa6a7d-9b1a-42eb-948e- 9a5d68dd-52b0-4cc2-bd40-


ID 1650a849e176 abcf44ac3a30

Display Read all applications Read all applications


String

Application.ReadWrite.All

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID Not available bdfbf15f-ee85-4955-8675-146e8e5296b5

Display String Not available Read and write all applications

Admin consent required? Not available Yes

Application

Parameter Azure AD Graph Microsoft Graph

Permission 1cda74f2-2616-4834-b122- 1bfefb4e-e0b5-418b-a88f-


ID 5cb1b07f8a59 73c46d2cc8e9

Display Read and write all applications Read all applications


String

Application.ReadWrite.OwnedBy

Delegated
Not applicable.

Application

Parameter Azure AD Graph Microsoft Graph

Permission 1cda74f2-2616-4834-b122- 18a4783c-866b-4cc7-a460-


ID 5cb1b07f8a59 3d5e5662c884
Parameter Azure AD Graph Microsoft Graph

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

Parameter Azure AD Graph Microsoft Graph

Permission 1138cb37-bd11-4084-a2b7- 1138cb37-bd11-4084-a2b7-


ID 9f71582aeddb 9f71582aeddb

Display Read and write devices Read and write devices


String

Directory.Read.All

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID 5778995a-e1bf-45b8-affa- 06da0dbc-49e2-44d2-8312-


663a9f3f4d04 53f166ab848a

Display String Read directory data Read directory data

Admin consent Yes Yes


required?

Application

Parameter Azure AD Graph Microsoft Graph

Permission 5778995a-e1bf-45b8-affa- 7ab1d382-f21e-4acd-a863-


ID 663a9f3f4d04 ba3e13f7da61
Parameter Azure AD Graph Microsoft Graph

Display Read directory data Read directory data


String

Directory.ReadWrite.All

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID 78c8a3c8-a07e-4b9e-af1b- c5366453-9fb0-48a5-a156-


b5ccab50a175 24f0c49a4b84

Display String Read and write directory data Read and write directory data

Admin consent Yes Yes


required?

Application

Parameter Azure AD Graph Microsoft Graph

Permission 78c8a3c8-a07e-4b9e-af1b- 19dbc75e-c2e2-444c-a770-


ID b5ccab50a175 ec69d8559fc7

Display Read and write directory data Read and write directory data
String

Directory.AccessAsUser.All

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID a42657d6-7f20-40e3-b6f0- 0e263e50-5827-48a4-b97c-


cee03008a62a d940288653c7

Display String Access the directory as the signed- Access the directory as the signed-
in user in user

Admin consent Yes Yes


required?
Application
Not applicable.

Domain.ReadWrite.All

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID Not available Read and write domains

Display String Not available Read and write domains

Admin consent required? Not available Yes

Application

Parameter Azure AD Graph Microsoft Graph

Permission abefe9df-d5a9-41c6-a60b- 7e05723c-0bb0-42da-be95-


ID 27b38eac3efb ae9f08a6e53c

Display Read and write domains Read and write domains


String

Group.Read.All

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID 6234d376-f627-4f0f-90e0- 5f8c59db-677d-491f-a6b8-


dff25c5211a3 5f174b11ec1d

Display String Read all groups Read all groups

Admin consent Yes Yes


required?

Application
----------------- ----------------- ---------------------------------------

Permission ID Not available 5b567255-7703-4780-807c-7be8301ae99b

Display String Not available Read all groups

Group.ReadWrite.All

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID 970d6fa6-214a-4a9b-8513- 4e46008b-f24c-477d-8fff-


08fad511e2fd 7bb4ec7aafe0

Display String Read and write all groups Read and write all groups

Admin consent Yes Yes


required?

Application

Parameter Azure AD Graph Microsoft Graph

Permission ID Not available 62a82d76-70ea-41e2-9197-370581804d09

Display String Not available Read and write all groups

Member.Read.Hidden

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID 2d05a661-f651-4d57-a595- f6a3db3e-f7e8-4ed2-a414-


489c91eda336 557c8c9830be

Display String Read hidden memberships Read hidden memberships

Admin consent Yes Yes


required?
Application

Parameter Azure AD Graph Microsoft Graph

Permission 9728c0c4-a06b-4e0e-8d1b- 658aa5d8-239f-45c4-aa12-


ID 3d694e8ec207 864f4fc7e490

Display Read all hidden memberships Read all hidden memberships


String

Policy.Read.All

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID Not available 572fea84-0151-49b2-9301-11cb16974376

Display String Not available Read your organization's policies

Admin consent required? Not available Yes

Application

Parameter Azure AD Graph Microsoft Graph

Permission 6c2d1b1d-a490-4178-ba6b- 246dd0d5-5bd0-4def-940b-


ID 7efceda9129b 0421030a5b68

Display Read your organization's policies Read your organization's policies


String

User.Read

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID 311a71cc-e848-46a1-bdf8- e1fe6dd8-ba31-4d61-89e7-


97ff7156d8e6 88639da4683d

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

Parameter Azure AD Graph Microsoft Graph

Permission ID cba73afc-7f69-4d86-8450- b340eb25-3456-403f-be2f-


4978e04ecd1a af7a0d370277

Display String Read all users' basic profiles Read all users' basic profiles

Admin consent No No
required?

Application

Parameter Azure AD Graph Microsoft Graph

Permission ID Not available 97235f07-e226-4f63-ace3-39588e11d3a1

Display String Not available Read all users' basic profiles

User.Read.All

Delegated

Parameter Azure AD Graph Microsoft Graph

Permission ID c582532d-9d9e-43bd-a97c- a154be20-db9c-4678-8ab7-


2667a28ce295 66f6cc099a59

Display String Read all users' full profiles Read all users' full profiles
Parameter Azure AD Graph Microsoft Graph

Admin consent Admin Admin


required?

Application

Parameter Azure AD Graph Microsoft Graph

Permission ID Not available df021288-bdef-4463-88db-98f22de89214

Display String Not available Read all users' full profiles

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

This is step 2 of the process to migrate apps.

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.

To learn more, see Permissions.

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.

For any app update, there are three areas to consider:

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.

Permissions: You should change your configured permissions to the equivalent


Microsoft Graph permissions. Delegated permissions which were granted for Azure
Active Directory (Azure AD) Graph will be implicitly considered granted for
Microsoft Graph also. Application permissions (app roles) will need to be granted
again.

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.

Simple migration projects should experience no issues in these areas.

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:

Azure Active Directory Authentication Library (ADAL)


Microsoft Authentication Library (MSAL)

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.

Once you've updated resourceURL and verified functionality, release an interim


update to get your users up and runnning.

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#

var scopes = new string[] { "https://graph.microsoft.com/.default" };

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

Overview of the migration steps


The following steps assume your app is already using ADAL to acquire access tokens to
call Azure AD Graph, and that for now you will continue to use ADAL. Switching to MSAL
can be done as a separate step described in migrating to MSAL.

1. To acquire an access token to Microsoft Graph, update resourceUrl from


https://graph.windows.net to https://graph.microsoft.com .

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.

4. Update your client constructor to create a GraphServiceClient , rather than


ActiveDirectoryClient . The following code snippets assume your app is using the
AcquireTokenAsyncForUser() method to acquire new tokens. You can find a

definition for this method as part of the active-directory-dotnet-graphapi-console


sample .

Change:

C#

ActiveDirectoryClient client = new ActiveDirectoryClient(serviceRoot,


async () => await AcquireTokenAsyncForUser());

To:

C#

GraphServiceClient graphClient = new GraphServiceClient(serviceRoot,


new DelegateAuthenticationProvider(async (requestMessage) => {
var token = await AcquireTokenAsyncForUser();
requestMessage.Headers.Authorization = new
AuthenticationHeaderValue("bearer", token);
}));

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#

signedInUser = (User)await client.Me.ExecuteAsync();

To:

C#

signedInUser = (User)await client.Me.Request().GetAsync();


7 Note

The Azure AD Graph client library supported LINQ-based query syntax.


However, the Microsoft Graph client library does not. Consequently, you'll
need to convert the relevant queries to a more RESTful expression.

To do so, change:

C#

var groups = await


client.Groups.Where(g => g.DisplayName.StartsWith("a")).ExecuteAsync();

To:

C#

var groups = await


client.Groups.Request().Filter("startswith(displayName,'a')").GetAsync(
);

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#

Group retrievedGroup = client.Groups.


Where(g => g.ObjectId.Equals(id)).ExecuteAsync().Result;
IGroupFetcher retrievedGroupFetcher = (IGroupFetcher) retrievedGroup;

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

This is step 4 of the process to migrate apps.

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.

2. Deploy staged updates

Consider deploying your updates in stages. A limited roll-out to a small set of


friendly users can help identify glitches and other potentially-embarrassing issues.
This also gives you a chance to monitor initial reception and feedback.

If the initial roll-out goes well, monitor progress as you deploy to larger audiences.

3. Explore new value

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.

See Major services and features in Microsoft Graph.


Take a look at some partner solutions.
Explore the Microsoft Graph blog for the latest news about Microsoft Graph
and some great learning series.
The changelog summarizes service and document updates. Following these
updates will help you track new APIs introduced to /beta (preview) and those
promoted to v1.0 (GA). These new APIs can provide new ways for you to add
more value and new experiences to your apps.
See also
If you run into problems or need help during the migration process, you can:

Review the checklist again


Post questions to Microsoft Graph on Q&A
Review Microsoft Graph samples to contrast and compare with your existing
application code:
Apps that use the REST API: explore quick starts and samples, choose your
platform of choice and run through the quick start or search for an appropriate
sample
App that use the .NET client library: review console-csharp-snippets-sample
or dotnetcore-console-sample

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.

How is Microsoft Graph different from Azure


AD Graph and why should I migrate my apps?
The Azure AD Graph API offers access to only Azure AD services. The Microsoft Graph
API offers a single unified endpoint to access Azure AD services and other Microsoft
services such as Microsoft Teams, Microsoft Exchange, and Microsoft Intune.

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.

As a developer, how do I identify apps that use


Azure AD Graph?
Follow these steps to identify apps with a dependency on Azure AD Graph:

Step 1: Scan the application source code


If you own an application's source code, search for the https://graph.windows.net/ URI
in the code. This is the Azure AD Graph endpoint and apps that call this endpoint use
Azure AD Graph. Record the value of the affected app's app ID.

Step 2: Check the app's API permissions on the Azure


portal
1. Sign in to the Azure portal as a global administrator.

2. Search for and select Azure Active Directory.


3. Under Manage, select App registrations.

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.

6. Select the app. This reveals the app's menu.

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.

Method 1: Through network proxy logs


Check your network server traffic logs through a filter proxy for any apps calling the
https://graph.windows.net/ endpoint. These apps use Azure AD Graph.

Method 2: Use the App registrations menu of the Azure


portal
1. Sign in to the Azure portal as a global administrator.

2. Search for and select Azure Active Directory.

3. Under Manage, select App registrations.

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.

Microsoft sent me an email with a list of App


IDs for apps using Azure AD Graph. How do I
find the details of each app, including its
owner?
1. Sign in to the Azure portal as a global administrator.

2. Search for and select Azure Active Directory.

3. Under Manage, select App registrations.

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.

Microsoft sent me an email with a list of App


IDs for apps using Azure AD Graph. Are these
all the affected apps?
This list captures only apps used within the last 28 days and that called the Azure AD
Graph endpoint. Because some apps may have seasonal use, their app ID might be
captured in one month's list but not in another. To retrieve the full list of affected apps,
we recommend you follow one of the three methods listed previously.

I'm a subscription Owner and Microsoft sent


me an email about Azure AD Graph
deprecation with a list of App IDs. What should
I do?
The email you receive includes the tenant IDs linked to the app IDs. Follow these steps
to retrieve the technical contact details for the specific tenants.

1. Sign in to the Azure portal as an administrator.

2. If you're a subscription owner in multiple Azure AD tenants, first switch to the


relevant tenant or directory.
a. On the top right of the window, select your profile icon and choose Switch
directory. This reveals the Portal settings | Directories + subscriptions window.
b. From the list, use the Switch tab to switch to the directory whose Directory ID
matches the tenant ID you received in the email. The active directory is marked
Current.
c. Close the window.

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.

I know apps that are using Azure AD Graph.


How do I migrate them to Microsoft Graph?
To migrate your apps from Azure AD Graph to Microsoft Graph, follow the App
migration planning checklist.

I don't own some apps in my tenant but they


use Azure AD Graph. How do I migrate them to
Microsoft Graph API? Can I find the owner of
such apps?
First, confirm the full list of apps owned by your tenant or third-party applications
integrated in your tenant.

1. Sign in to the Azure portal as an administrator.

2. Search for and select Azure Active Directory.

3. Under Manage, select App registrations.

4. In the App registrations window, select the All Applications tab.

5. Select the app. This reveals the app's menu.

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.

I need to add new Azure AD Graph permissions


to my app, but I can't select Azure AD Graph as
a required permission for my app registration.
How can I add the Azure AD Graph
permissions?
First, we recommend that you follow the App migration planning checklist to help you
transition your apps to the Microsoft Graph API.
If you've identified a gap where Microsoft Graph doesn't support a feature available in
Azure AD Graph, let us know through Microsoft Q&A by using the tag azure-ad-graph-
deprecation.

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

Note: Adding Azure AD Graph permissions using these workarounds won't be


supported after retirement of the Azure AD Graph. Any app using Azure AD Graph
will stop functioning after the retirement.

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.

Option 1: Use the Azure portal to find the APIs


your organization uses
1. Sign in to the Azure portal as a global administrator or application administrator.

2. Search for and select Azure Active Directory.

3. Under Manage, select App registrations.

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.

7. Select the Delegated permissions or Application permissions tab to choose from


delegated and application permissions respectively. Select Add permissions to add
the permission to your app registration.

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.

Option 2: Update the application manifest on


the Azure portal
1. Sign in to the Azure portal as a global administrator or application administrator.

2. Search for and select Azure Active Directory.

3. Under Manage, select App registrations.

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.

Add the resourceAppId property and assign the value 00000002-0000-0000-c000-


000000000000 representing Azure AD Graph

Add the resourceAccess property and assign the required permissions.

The following JSON snippet shows a requiredResourceAccess property with Azure


AD Graph as the resource, and assigned the User.Read and Application.Read.All
oauth2PermissionScope (delegated permission) and appRole (application
permission) respectively.

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.

Option 3: Use the Microsoft Graph API


The Microsoft Graph application API includes a requiredResourceAccess property that is
a collection of requiredResourceAccess objects. Use this property to configure required
Azure AD Graph permissions as described in the following steps.

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.

Step 1: Identify the permission IDs for the Azure AD


Graph permissions your app requires
Identify the Azure AD Graph permissions your app requires, their permission IDs, and
whether they're app roles (application permissions) or oauth2PermissionScopes
(delegated permissions).

Azure AD Graph is identified as a servicePrincipal object with 00000002-0000-0000-c000-


000000000000 as its globally unique appId and Windows Azure Active Directory as its

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"
}
]
}
]
}

From the above truncated output, 311a71cc-e848-46a1-bdf8-97ff7156d8e6 is the


permission ID for the User.Read delegated permission while 3afa6a7d-9b1a-42eb-948e-
1650a849e176 is the permission ID for the Application.Read.All application permission.

Step 2: Add required Azure AD Graph permissions to your


app
The following example calls the Update application API to add the required Azure AD
Graph permissions to an app registration identified by object ID 581088ba-83c5-4975-
b8af-11d2d7a76e98 . From Step 1, these permissions were User.Read and

Application.Read.All delegated permission and application permission respectively.

) Important

To update the requiredResourceAccess property, you must pass in both existing


and new permissions. Passing in only new permissions overwrites and removes the
existing permissions.

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/1.1 204 No Content

Step 3: Verify that the required Azure AD Graph


permissions were added to your app
Verify that your app registration has the required Azure AD Graph API permissions you
added in Step 2 by using the Microsoft Graph API or by checking the App registrations
page in the Azure portal.
Use the Microsoft Graph GET /application/{id} API
The following request retrieves the id and requiredResourceAccess properties of the
app identified by object id 581088ba-83c5-4975-b8af-11d2d7a76e98 .

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.

Option 4: Use the Microsoft Graph PowerShell


SDK
The Update-MgApplication cmdlet in Microsoft Graph PowerShell SDK includes a
RequiredResourceAccess parameter that is a collection of
IMicrosoftGraphRequiredResourceAccess objects. Use this parameter to configure the
required Azure AD Graph permissions as described in the following steps.

Prerequisites
To complete the following steps, the following privileges are required:

An authenticated PowerShell session (for example, using Connect-MgGraph ).


Microsoft Graph PowerShell must be granted the Application.ReadWrite.All
permission.
The signed-in user must be granted the Global Administrator or Application
Administrator Azure AD directory roles, or be owner of the target app registration.
For more information about the actions supported by these roles, see Azure AD
built-in roles.

Step 1: Identify the permission IDs for the Azure AD


Graph permissions your app requires
Identify the Azure AD Graph permissions your app requires, their permission IDs, and
whether they're app roles (application permissions) or delegated permissions.
Azure AD Graph is identified as a ServicePrincipal object with 00000002-0000-0000-c000-
000000000000 as its globally unique AppId and Windows Azure Active Directory as its
DisplayName and AppDisplayName. Run the following request to retrieve the
ServicePrincipal object for Azure AD Graph.

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

# Sign in with the required Application.ReadWrite.All scope


Connect-Graph -Scopes "Application.ReadWrite.All"

# Retrieve the service principal details for Azure AD Graph API.


$AADGraph = Get-MgServicePrincipal -Filter "appId eq '00000002-0000-0000-
c000-000000000000'"

# Format output of the request above and display AppRoles (application


permissions) and oauth2PermissionScopes (delegated permissions)
Echo "Azure AD Graph service principal object and its supported
permissions:"
Echo "Application permissions:"
$AADGraph.AppRoles | Format-List
Echo "Delegated permissions:"
$AADGraph.Oauth2PermissionScopes | Format-List

Run the script using the following command

PowerShell

.\fetchPermissions.ps1

Response
The following is an example of the output.

PowerShell

Welcome To Microsoft Graph!


Azure AD Graph service principal object and its supported permissions:
Application permissions:
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
AdditionalProperties : {}

Delegated permissions:

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
Origin :
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
AdditionalProperties : {}

From this output, 311a71cc-e848-46a1-bdf8-97ff7156d8e6 is the permission ID of the


User.Read delegated permission while 3afa6a7d-9b1a-42eb-948e-1650a849e176 is the
permission ID of the Application.Read.All application permission.

Step 2: Add Azure AD Graph permissions to your app


Create a new PowerShell script named updatePermissions.ps1 and add the following
code. This code adds the required Azure AD Graph permissions to an app registration
identified by object ID 581088ba-83c5-4975-b8af-11d2d7a76e98 . From Step 1, these
permissions were User.Read and Application.Read.All delegated permission and
application permission respectively.

) Important

To update the RequiredResourceAccess property, you must pass in both existing


and new permissions. Passing in only new permissions overwrites and removes the
existing permissions.
Request

Azure AD Graph permissions only

PowerShell

## Sign in with the required Application.ReadWrite.All scope


Connect-Graph -Scopes "Application.ReadWrite.All"

## Azure AD Graph's globally unique appId is 00000002-0000-0000-c000-


000000000000 identified by the ResourceAppId
$graphResourceId = "00000002-0000-0000-c000-000000000000"

## Replace 581088ba-83c5-4975-b8af-11d2d7a76e98 with the object ID of


the app you wish to add new permissions to
$applicationId = "581088ba-83c5-4975-b8af-11d2d7a76e98"

## Define the new permissions to be added to the target app


$newResourceAccess = @{
ResourceAppId = $graphResourceId;
ResourceAccess = @(

## Replace the following with values of ID and type for all


permissions you want to configure for the app
@{
# User.Read scope (delegated permission) to sign-in and read
user profile
id = "311a71cc-e848-46a1-bdf8-97ff7156d8e6";
type = "Scope";
},

@{
# Application.Read.All app role (application permission) to
view application data
id = "3afa6a7d-9b1a-42eb-948e-1650a849e176";
type = "Role";
}
)
}

$app = Get-MgApplication -ApplicationId $applicationId

## Get the existing permissions of the application


$existingResourceAccess = $app.RequiredResourceAccess

## If the app has no existing permissions, or no existing permissions


from our new permissions resource
if ( ([string]::IsNullOrEmpty($existingResourceAccess) ) -or
($existingResourceAccess | Where-Object { $_.ResourceAppId -eq
$graphResourceId } -eq $null) ) {
$existingResourceAccess += $newResourceAccess
Update-MgApplication -ApplicationId $applicationId -
RequiredResourceAccess $existingResourceAccess
}

## If the app already has existing permissions from our new permissions
resource
else {
$newResourceAccess.ResourceAccess +=
$existingResourceAccess.ResourceAccess
Update-MgApplication -ApplicationId $applicationId -
RequiredResourceAccess $newResourceAccess
}

Run the script using the following command.

PowerShell

.\updatePermissions.ps1

Response
The following is an example of the output.

PowerShell

Welcome To Microsoft Graph!

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.

Why use Microsoft Graph?


Microsoft Graph offers improvements over EWS in terms of security, simplicity, and
efficiency. Switch to Microsoft Graph to take advantage of these improvements, all
through one single endpoint.

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

EWS currently also supports basic authentication. Basic authentication is


deprecated and is being deactivated across Microsoft 365 organizations. Microsoft
Graph does not support basic authentication, so apps that have not yet migrated to
OAuth 2.0 must do so to access Microsoft Graph.

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.

For a full list of Exchange-related Microsoft Graph permissions, see:

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

ConvertId Translate Exchange IDs

ResolveNames List people

GetServerTimeZones Get time zone choices

Mail APIs

Messages

EWS API Microsoft Graph API

CreateItem Create message

CopyItem Copy message

DeleteItem Delete message

FindItem List messages

GetItem Get message

MoveItem Move message

SendItem Send message or Send mail

UpdateItem Update message

Folders

EWS API Microsoft Graph API


EWS API Microsoft Graph API

CreateFolder Create mail folder

CopyFolder Copy mail folder

DeleteFolder Delete mail folder

GetFolder Get mail folder

MoveFolder Move mail folder

UpdateFolder Update mail folder

Attachments

EWS API Microsoft Graph API

CreateAttachment Add attachment

GetAttachment Get attachment

DeleteAttachment Delete attachment

Rules

EWS API Microsoft Graph API

GetInboxRules List rules

UpdateInboxRules Create rule


Update rule
Delete rule

MailTips

EWS API Microsoft Graph API

GetMailTips Get MailTips

Out of Office (OOF) settings

EWS API Microsoft Graph API

GetUserOofSettings Get user mailbox settings


EWS API Microsoft Graph API

SetUserOofSettings Update user mailbox settings

Notifications

7 Note

Microsoft Graph only requires a subscription for push notifications. If you are
currently using EWS pull notifications, see Get messages delta.

EWS API Microsoft Graph API

GetEvents Get messages delta

Subscribe (Push notifications) Create subscription

Unsubscribe (Push notifications) Delete subscription

Synchronization

EWS API Microsoft Graph API

SyncFolderHierarchy Get mail folder delta

SyncFolderItems Get messages delta

Calendar APIs

Availability

EWS API Microsoft Graph API

GetUserAvailability Get free/busy schedule


FindAvailableMeetingTimes

Reminders

EWS API Microsoft Graph API

GetReminders Reminder view


EWS API Microsoft Graph API

PerformReminderAction Dismiss reminder


Snooze reminder

Permissions

EWS API Microsoft Graph API

GetReminders Reminder view

PerformReminderAction Dismiss reminder


Snooze reminder

CreateSharingPermission,GetSharingPermission Calendar owner: Get sharing or delegation


information and permissions

UpdateSharingPermission Get calendar information about sharees and


delegates, and update individual permissions

DeleteSharingPermission Delete a sharee or delegate of a calendar

GetSharingPermissionInfo Calendar owner: Get properties of a shared or


delegated calendar

Invitations

EWS API Microsoft Graph API

ActivateSharingInvitation Share or delegate a calendar in Outlook

GetSharingInvitation Sharee: Get a shared calendar or its events directly from calendar
owner's mailbox

DeleteSharingInvitation Calendar owner: Update permissions for an existing sharee or


delegate on a calendar

CreateSharingInvitation Create Outlook events in a shared or delegated calendar

Shared Information

EWS API Microsoft Graph API

GetCalendarSharedInformation,GetConsumerCalendarSharedInformation List calendars


Groups APIs
EWS API Microsoft Graph API

GetUserUnifiedGroups List memberof

GetUnifiedGroupsSettings groupSetting

GetUnifiedGroupDetails Get group

GetUnifiedGroupMembers List members

GetUnifiedGroupUnseenCount Get group

SetUnifiedGroupMembershipState Add/remove member/owner

FindUnifiedGroups List groups

SetUnifiedGroupUserSubscribeState Subscribe/unsubscribeByMail

UpdateUnifiedGroup Update group

CreateUnifiedGroup Create group

RemoveUnifiedGroup Delete group

SetUnifiedGroupFavoriteState Group addFavorite

JoinPrivateUnifiedGroup Subscribe/unsubscribeByMail

GetDlMembersForUnifiedGroup List group members


Microsoft Graph SDK overview
Article • 01/31/2023

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)

SDKs in preview or GA status


A release of an SDK can be in preview status upon debut or a significant update. Do not
assume that a preview release will always be promoted to generally available (GA)
status.

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.

Microsoft 365 developer subscription


When building applications using Microsoft Graph, we recommend that you get a free
Microsoft 365 developer subscription by signing up for the Microsoft 365 Developer
Program.

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.

SDKs are available in the following languages:

.NET
Go (preview)
Java
JavaScript
PHP
PowerShell
Python (preview)

Install the Microsoft Graph .NET SDK


The Microsoft Graph .NET SDK is included in the following NuGet packages:

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

Install the Microsoft Graph Go SDK (preview)


) Important

The Microsoft Graph SDK for Go is currently in preview. Use of this SDK in
production is not supported.

The Microsoft Graph Go SDK is included in the following packages:

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

Install the Microsoft Graph Java SDK


The Microsoft Graph Java SDK is included in the following packages:

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.

To install the Microsoft Graph Java SDK, do one of the following:

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>

Install the Microsoft Graph JavaScript SDK


The Microsoft Graph JavaScript SDK is included in the following packages:

@microsoft/microsoft-graph-client (npm ): The core library for making calls to


Microsoft Graph.
@microsoft/microsoft-graph-types (npm ): The TypeScript types for the Microsoft
Graph entities.

Use npm to install the Microsoft Graph JavaScript SDK:

Shell

npm install @microsoft/microsoft-graph-client --save


npm install @microsoft/microsoft-graph-types --save-dev

Install the Microsoft Graph PHP SDK


The Microsoft Graph PHP SDK is available from packagist.org and can be installed
in the following ways:

Use composer to install the Microsoft Graph PHP SDK manually:


Shell

composer require microsoft/microsoft-graph

Use composer.json to install the Microsoft Graph PHP SDK:

JSON

{
"require": {
"microsoft/microsoft-graph": "^1.8"
}
}

Install the Microsoft Graph PowerShell SDK


All the modules are published on PowerShell Gallery . To install:

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

Install-Module Microsoft.Graph -AllowClobber -Force

Install the Microsoft Graph Python SDK


(preview)

) Important

The Microsoft Graph SDK for Python is currently in preview. Use of this SDK in
production is not supported.

The Microsoft Graph Python SDK (preview) is available on PyPI .

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#

var scopes = new[] { "User.Read" };

// Multi-tenant apps can use "common",


// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Value from app registration


var clientId = "YOUR_CLIENT_ID";

// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};

// Callback function that receives the user prompt


// Prompt contains the generated device code that you must
// enter during the auth process in the browser
Func<DeviceCodeInfo, CancellationToken, Task> callback = (code,
cancellation) => {
Console.WriteLine(code.Message);
return Task.FromResult(0);
};

//
https://learn.microsoft.com/dotnet/api/azure.identity.devicecodecredenti
al
var deviceCodeCredential = new DeviceCodeCredential(
callback, tenantId, clientId, options);

var graphClient = new GraphServiceClient(deviceCodeCredential, scopes);


Customize the Microsoft Graph SDK
service client
Article • 03/14/2023

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(...);

var authProvider = new


AzureIdentityAuthenticationProvider(tokenCredential, scopes: scopes);

var handlers = GraphClientFactory.CreateDefaultHandlers();

// Remove a default handler


var compressionHandler =
handlers.Where(h => h is CompressionHandler).FirstOrDefault();
handlers.Remove(compressionHandler);

// Add a new one


// ChaosHandler simulates random server failures
handlers.Add(new ChaosHandler());

var httpClient = GraphClientFactory.Create(handlers);

var customGraphClient = new GraphServiceClient(httpClient,


authProvider);

var messages = await graphClient.Me.Messages


.GetAsync(requestConfiguration =>
{
requestConfiguration.QueryParameters.Top = 100;
requestConfiguration.QueryParameters.Select = new string[] {
"subject" };
});
Configuring the HTTP proxy for the client
Some environments require client applications to use a HTTP proxy before they can
access the public internet. This section shows how to configure the proxy for the
Microsoft Graph SDKs.

C#

C#

// URI to proxy
var proxyAddress = "http://localhost:8888";

// Create a new System.Net.Http.HttpClientHandler with the proxy


var handler = new HttpClientHandler
{
// Create a new System.Net.WebProxy
// See WebProxy documentation for scenarios requiring
// authentication to the proxy
Proxy = new WebProxy(new Uri(proxyAddress))
};

// Create an options object for the credential being used


// For example, here we're using a ClientSecretCredential so
// we create a ClientSecretCredentialOptions object
var options = new ClientSecretCredentialOptions
{
// Create a new Azure.Core.HttpClientTransport
Transport = new HttpClientTransport(handler)
};

var credential = new ClientSecretCredential(


"YOUR_TENANT_ID",
"YOUR_CLIENT_ID",
"YOUR_CLIENT_SECRET",
options
);

var scopes = new[] { "https://graph.microsoft.com/.default" };

// This example works with Microsoft.Graph 5+


var httpClient = GraphClientFactory.Create(proxy: new WebProxy(new
Uri(proxyAddress)));

var graphClient = new GraphServiceClient(httpClient, new


AzureIdentityAuthenticationProvider(credential, scopes: scopes));
Choose a Microsoft Graph
authentication provider based on
scenario
Article • 03/02/2023

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.

Scenario Flow/Grant Audience Provider

Single Page App Authorization Code Delegated Authorization code


with PKCE Consumer/Org provider

Web App that calls web


APIs

Authorization Code Delegated Authorization code


Consumer/Org provider

Client Credentials App Only Client credentials


provider

Web API that calls web


APIs

On Behalf Of Delegated On-behalf-of provider


Consumer/Org

Client Credentials App Only Client credentials


provider

Desktop app that calls


web APIs

Interactive Delegated Interactive provider


Consumer/Org

Integrated Windows Delegated Org Integrated Windows


provider

Resource Owner Delegated Org Username/password


provider
Scenario Flow/Grant Audience Provider

Device Code Delegated Org Device code provider

Daemon app

Client Credentials App Only Client credentials


provider

Mobile app that calls


web APIs

Interactive Delegated Interactive provider


Consumer/Org

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:

.NET developers need to add the Azure.Identity package.


JavaScript developers need to add the @azure/identity library.
Java and Android developers need to add the azure-identity library.

Authorization code provider


The authorization code flow enables native and web apps to securely obtain tokens in
the name of the user. To learn more, see Microsoft identity platform and OAuth 2.0
authorization code flow.

C#

C#

var scopes = new[] { "User.Read" };

// Multi-tenant apps can use "common",


// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Values from app registration


var clientId = "YOUR_CLIENT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";
// For authorization code flow, the user signs into the Microsoft
// identity platform, and the browser is redirected back to your app
// with an authorization code in the query parameters
var authorizationCode = "AUTH_CODE_FROM_REDIRECT";

// 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);

var graphClient = new GraphServiceClient(authCodeCredential, scopes);

Client credentials provider


The client credential flow enables service applications to run without user interaction.
Access is based on the identity of the application. For more information, see Microsoft
identity platform and the OAuth 2.0 client credentials flow.

C#

Using a client secret


C#

// The client credentials flow requires that you request the


// /.default scope, and preconfigure your permissions on the
// app registration in Azure. An administrator must grant consent
// to those permissions beforehand.
var scopes = new[] { "https://graph.microsoft.com/.default" };

// Multi-tenant apps can use "common",


// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Values from app registration


var clientId = "YOUR_CLIENT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";

// 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);

var graphClient = new GraphServiceClient(clientSecretCredential,


scopes);

Using a client certificate


C#

var scopes = new[] { "https://graph.microsoft.com/.default" };

// Multi-tenant apps can use "common",


// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Values from app registration


var clientId = "YOUR_CLIENT_ID";
var clientCertificate = new X509Certificate2("MyCertificate.pfx");

// 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);

var graphClient = new GraphServiceClient(clientCertCredential, scopes);

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#

var scopes = new[] { "User.Read" };

// Multi-tenant apps can use "common",


// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Values from app registration


var clientId = "YOUR_CLIENT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";

// using Azure.Identity;
var options = new OnBehalfOfCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};

// This is the incoming token to exchange using on-behalf-of flow


var oboToken = "JWT_TOKEN_TO_EXCHANGE";

var onBehalfOfCredential = new OnBehalfOfCredential(tenantId, clientId,


clientSecret, oboToken, options);

var graphClient = new GraphServiceClient(onBehalfOfCredential,scopes);

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 .

Device code provider


The device code flow enables sign in to devices by way of another device. For details,
see Microsoft identity platform and the OAuth 2.0 device code flow.

C#

C#
var scopes = new[] { "User.Read" };

// Multi-tenant apps can use "common",


// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Value from app registration


var clientId = "YOUR_CLIENT_ID";

// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};

// Callback function that receives the user prompt


// Prompt contains the generated device code that use must
// enter during the auth process in the browser
Func<DeviceCodeInfo, CancellationToken, Task> callback = (code,
cancellation) => {
Console.WriteLine(code.Message);
return Task.FromResult(0);
};

//
https://learn.microsoft.com/dotnet/api/azure.identity.devicecodecredenti
al
var deviceCodeCredential = new DeviceCodeCredential(
callback, tenantId, clientId, options);

var graphClient = new GraphServiceClient(deviceCodeCredential, scopes);

Integrated Windows provider


The integrated Windows flow provides a way for Windows computers to silently acquire
an access token when they are domain joined. For details, see Integrated Windows
authentication .

C#

The Azure.Identity package does not currently support Windows integrated


authentication. Instead create a custom authentication provider using MSAL.

C#

public class TokenProvider : IAccessTokenProvider


{
private readonly IPublicClientApplication publicClientApplication;
public TokenProvider(string clientId, string tenantId)
{
publicClientApplication = PublicClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantId)
.Build();
AllowedHostsValidator = new AllowedHostsValidator();
}
public async Task<string> GetAuthorizationTokenAsync(Uri uri,
Dictionary<string, object> additionalAuthenticationContext = default,
CancellationToken cancellationToken = default)
{
var scopes = new[] { "User.Read" };
var result = await
publicClientApplication.AcquireTokenByIntegratedWindowsAuth(scopes).Exec
uteAsync(); ;
// get the token and return it in your own way
return Task.FromResult(result.A);
}

public AllowedHostsValidator AllowedHostsValidator { get; }


}

C#

// Multi-tenant apps can use "common",


// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Value from app registration


var clientId = "YOUR_CLIENT_ID";

var authenticationProvider = new


BaseBearerTokenAuthenticationProvider(new
TokenProvider(clientId,tenantId));
var graphServiceClient = new GraphServiceClient(authenticationProvider);

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" };

// Multi-tenant apps can use "common",


// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Value from app registration


var clientId = "YOUR_CLIENT_ID";

// 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);

var graphClient = new GraphServiceClient(interactiveCredential, scopes);

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#

var scopes = new[] { "User.Read" };

// Multi-tenant apps can use "common",


// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Value from app registration


var clientId = "YOUR_CLIENT_ID";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};

var userName = "[email protected]";


var password = "P@ssword1!";

//
https://learn.microsoft.com/dotnet/api/azure.identity.usernamepasswordcr
edential
var userNamePasswordCredential = new UsernamePasswordCredential(
userName, password, tenantId, clientId, options);

var graphClient = new GraphServiceClient(userNamePasswordCredential,


scopes);

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.

Configure the SDK


In order to connect to a national cloud deployment, you must configure your
authentication provider to connect to the correct token service endpoint. Then you must
configure the SDK client to connect to the correct Microsoft Graph service root
endpoint.

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.

For incremental or dynamic consent, User.Read and


https://graph.microsoft.us/User.Read are equivalent for the US Government L4
national cloud.
For statically defined permissions, or if you are using client credentials flow for
app-only permissions, https://graph.microsoft.us/.default is the correct
.default scope value.

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;

// Create the InteractiveBrowserCredential using details


// from app registered in the Azure AD for US Government portal
var credential = new InteractiveBrowserCredential(
"YOUR_TENANT_ID",
"YOUR_CLIENT_ID",
new InteractiveBrowserCredentialOptions
{
// https://login.microsoftonline.us
AuthorityHost = AzureAuthorityHosts.AzureGovernment,
RedirectUri = new Uri("YOUR_REDIRECT_URI")
});

// Create the authentication provider


var authProvider = new AzureIdentityAuthenticationProvider(
credential,
new[] { "https://graph.microsoft.us/.default" });

// Create the Microsoft Graph client object using


// the Microsoft Graph for US Government L4 endpoint
// NOTE: The API version must be included in the URL
var graphClient = new GraphServiceClient(
authProvider, "https://graph.microsoft.us/v1.0");
Make API calls using the Microsoft
Graph SDKs
Article • 01/31/2023

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.

Read information from Microsoft Graph


To read information from Microsoft Graph, you first need to create a request object and
then run the GET method on the request.

C#

C#

// GET https://graph.microsoft.com/v1.0/me

var user = await graphClient.Me


.GetAsync();

Use $select to control the properties returned


When retrieving an entity, not all properties are automatically retrieved; sometimes they
need to be explicitly selected. Also, in some scenarios it isn't necessary to return the
default set of properties. Selecting just the required properties can improve the
performance of the request. You can customize the request to include the $select
query parameter with a list of properties.
C#

C#

// GET https://graph.microsoft.com/v1.0/me?$select=displayName,jobTitle

var user = await graphClient.Me


.GetAsync(requestConfiguration =>
{
requestConfiguration.QueryParameters.Select = new string[] {
"displayName", "jobTitle"};
});

Retrieve a list of entities


Retrieving a list of entities is similar to retrieving a single entity except there a number of
other options for configuring the request. The $filter query parameter can be used to
reduce the result set to only those rows that match the provided condition. The
$orderBy query parameter will request that the server provide the list of entities sorted
by the specified properties.

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

var messages = await graphClient.Me.Messages


.GetAsync( requestConfig =>
{
requestConfig.QueryParameters.Select = new string[]
{ "subject", "sender"};
requestConfig.QueryParameters.Filter = "<filter
condition>";
requestConfig.QueryParameters.Orderby = new string[]
{ "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.

Access an item of a collection


For SDKs that support a fluent style, collections of entities can be accessed using an
array index. For template-based SDKs, it is sufficient to embed the item identifier in the
path segment following the collection. For PowerShell, identifiers are passed as
parameters.

C#

C#

// GET https://graph.microsoft.com/v1.0/me/messages/{message-id}

string messageId = "AQMkAGUy..";


var message = await graphClient.Me.Messages[messageId]
.GetAsync();

Use $expand to access related entities


You can use the $expand filter to request a related entity, or collection of entities, at the
same time that you request the main entity.

C#

C#

// GET https://graph.microsoft.com/v1.0/me/messages/{message-id}?
$expand=attachments

string messageId = "AQMkAGUy...";


var message = await graphClient.Me.Messages[messageId]
.GetAsync( requestConfig => requestConfig.QueryParameters.Expand =
new string[] { "attachments" });
Delete an entity
Delete requests are constructed in the same way as requests to retrieve an entity, but
use a DELETE request instead of a GET .

C#

C#

// DELETE https://graph.microsoft.com/v1.0/me/messages/{message-id}

string messageId = "AQMkAGUy...";


await graphClient.Me.Messages[messageId]
.DeleteAsync();

Make a POST request to create a new entity


For SDKs that support a fluent style, new items can be added to collections with an Add
method. For template-based SDKs, the request object exposes a post method. For
PowerShell, a New-* command is available that accepts parameters that map to the
entity to add. The created entity is usually returned from the call.

C#

C#

// POST https://graph.microsoft.com/v1.0/me/calendars

var calendar = new Calendar


{
Name = "Volunteer"
};

var newCalendar = await graphClient.Me.Calendars


.PostAsync(calendar);

Updating an existing entity with PATCH


Most updates in Microsoft Graph are performed using a PATCH method and therefore it
is only necessary to include the properties that you want to change in the object you
pass.

C#

C#

// PATCH https://graph.microsoft.com/v1.0/teams/{team-id}

var team = new Team


{
FunSettings = new TeamFunSettings
{
AllowGiphy = true,
GiphyContentRating = GiphyRatingType.Strict
}
};

var teamId = "71766077-aacc-470a-be5e-ba47db3b2e88";

await graphClient.Teams[teamId]
.PatchAsync(team);

Use HTTP headers to control request behavior


You can use a Header() function to attach custom headers to a request. For PowerShell,
adding headers is only possible with the Invoke-GraphRequest method. A number of
Microsoft Graph scenarios use custom headers to adjust the behavior of the request.

C#

C#

// GET https://graph.microsoft.com/v1.0/users/{user-id}/events

var events = await graphClient.Me.Events


.GetAsync( requestConfig =>
{
requestConfig.Headers.Add("Prefer",
@"outlook.timezone=""Pacific Standard Time""");
requestConfig.QueryParameters.Select = new string[]
{"subject", "body", "bodyPreview"};
});
Provide custom query parameters
For SDKs that support a fluent style, you can provide custom query parameter values by
using a list of QueryOptions objects. For template-based SDKs, the parameters are URL-
encoded and added to the request URI. For PowerShell and Go, defined query
parameters for a given API are exposed as parameters to the corresponding command.

C#

C#

//GET https://graph.microsoft.com/v1.0/me/calendarView

var calendar = await graphClient.Me.CalendarView


.GetAsync(requestConfiguration =>
{
requestConfiguration.QueryParameters.StartDateTime = "2020-12-
01T00:00:00Z";
requestConfiguration.QueryParameters.EndDateTime = "2020-12-
30T00:00:00Z";
});
Page through a collection using the
Microsoft Graph SDKs
Article • 03/02/2023

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.

Iterate over all the messages


The following example shows iterating over all the messages in a user's mailbox.

 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#

var messages = await graphClient.Me.Messages


.GetAsync(requestConfiguration =>
{
requestConfiguration.QueryParameters.Top = 10;
requestConfiguration.QueryParameters.Select = new string[] {
"sender", "subject", "body" };
requestConfiguration.Headers.Add("Prefer", "outlook.body-
content-type=\"text\"");
});

var pageIterator = PageIterator<Message,MessageCollectionResponse>


.CreatePageIterator(
graphClient,
messages,
// Callback executed for each item in
// the collection
(m) =>
{
Console.WriteLine(m.Subject);
return true;
},
// Used to configure subsequent page
// requests
(req) =>
{
// Re-add the header to subsequent requests
req.Headers.Add("Prefer", "outlook.body-content-
type=\"text\"");
return req;
}
);

await pageIterator.IterateAsync();

Stopping and resuming the iteration


Some scenarios require stopping the iteration process in order to perform other actions.
It is possible to pause the iteration by returning false from the iteration callback.
Iteration can be resumed by calling the resume method on the PageIterator.

C#

C#

int count = 0;
int pauseAfter = 25;

var messages = await graphClient.Me.Messages


.GetAsync(requestConfiguration =>
{
requestConfiguration.QueryParameters.Top = 10;
requestConfiguration.QueryParameters.Select = new string[] {
"sender", "subject" };
});

var pageIterator = PageIterator<Message, MessageCollectionResponse>


.CreatePageIterator(
graphClient,
messages,
(m) =>
{
Console.WriteLine(m.Subject);
count++;
// If we've iterated over the limit,
// stop the iteration by returning false
return count < pauseAfter;
}
);

await pageIterator.IterateAsync();

while (pageIterator.State != PagingState.Complete)


{
Console.WriteLine("Iteration paused for 5 seconds...");
await Task.Delay(5000);
// Reset count
count = 0;
await pageIterator.ResumeAsync();
}
Use the Microsoft Graph SDKs to batch
requests
Article • 03/02/2023

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.

Create a batch request


The Microsoft Graph SDKs provide three classes to work with batch requests and
responses.

BatchRequestStep - Represents a single request (such as GET /me ) within a batch.


It enables assigning a unique identifier to the request and specifying dependencies
between requests.
BatchRequestContent - Simplifies creating the batch request payload. It contains
multiple BatchRequestStep objects.
BatchResponseContent - Simplifies parsing the response from a batch request. It
provides the ability to get all responses, get a specific response by ID, and get the
@odata.nextLink property if present.

Simple batching example


This example shows how to send multiple requests in a batch that are not dependent on
each other. The requests can be run by the service in any order. This example gets the
user and gets the user's calendar view for the current day.

C#

C#
// Use the request builder to generate a regular
// request to /me
var userRequest = graphClient.Me.ToGetRequestInformation();

var today = DateTime.Now.Date;

// Use the request builder to generate a regular


// request to /me/calendarview?startDateTime="start"&endDateTime="end"
var eventsRequest = graphClient.Me.CalendarView
.ToGetRequestInformation(requestConfiguration =>
{
requestConfiguration.QueryParameters.StartDateTime =
today.ToString("yyyy-MM-ddTHH:mm:ssK");
requestConfiguration.QueryParameters.EndDateTime =
today.AddDays(1).ToString("yyyy-MM-ddTHH:mm:ssK");
});

// Build the batch


var batchRequestContent = new BatchRequestContent(graphClient);

// Using AddBatchRequestStepAsync adds each request as a step


// with no specified order of execution
var userRequestId = await
batchRequestContent.AddBatchRequestStepAsync(userRequest);
var eventsRequestId = await
batchRequestContent.AddBatchRequestStepAsync(eventsRequest);

var returnedResponse = await


graphClient.Batch.PostAsync(batchRequestContent);

// De-serialize response based on known return type


try
{
var user = await returnedResponse
.GetResponseByIdAsync<User>(userRequestId);
Console.WriteLine($"Hello {user.DisplayName}!");
}
catch (ServiceException ex)
{
Console.WriteLine($"Get user failed: {ex.Error.Message}");
}

// For collections, must use the *CollectionResponse class to


deserialize
// The .Value property will contain the *CollectionPage type that the
Graph client
// returns from GetAsync().
try
{
var events = await returnedResponse
.GetResponseByIdAsync<EventCollectionResponse>(eventsRequestId);
Console.WriteLine($"You have {events.Value.Count} events on your
calendar today.");
}
catch (ServiceException ex)
{
Console.WriteLine($"Get calendar view failed: {ex.Error.Message}");
}

Batches with dependent requests


This example shows how to send multiple requests in a batch that are dependent on
each other. The requests will be run by the service in the order specified by the
dependencies. This example adds an event with a start time during the current day to
the user's calendar and gets the user's calendar view for the current day. To make sure
that the calendar review returned includes the new event created, the request for the
calendar view is configured as dependent on the request to add the new event. This
ensures that the add event request will execute first.

7 Note

If the add event request fails, the get calendar view request will fail with a 424
Failed Dependency error.

C#

C#

var today = DateTime.Now.Date;

var newEvent = new Event


{
Subject = "File end-of-day report",
Start = new DateTimeTimeZone
{
// 5:00 PM
DateTime = today.AddHours(17).ToString("yyyy-MM-ddTHH:mm:ss"),
TimeZone = TimeZoneInfo.Local.StandardName
},
End = new DateTimeTimeZone
{
// 5:30 PM
DateTime = today.AddHours(17).AddMinutes(30).ToString("yyyy-MM-
ddTHH:mm:ss"),
TimeZone = TimeZoneInfo.Local.StandardName
}
};

// Use the request builder to generate a regular


// POST request to /me/events
var addEventRequest =
graphClient.Me.Events.ToPostRequestInformation(newEvent);

// Use the request builder to generate a regular


// request to /me/calendarview?startDateTime="start"&endDateTime="end"
var calendarViewRequest =
graphClient.Me.CalendarView.ToGetRequestInformation(
requestConfiguration => {
requestConfiguration.QueryParameters.StartDateTime =
today.ToString("yyyy-MM-ddTHH:mm:ssK");
requestConfiguration.QueryParameters.EndDateTime =
today.AddDays(1).ToString("yyyy-MM-ddTHH:mm:ssK");
});

// Build the batch


var batchRequestContent = new BatchRequestContent(graphClient);

// Force the requests to execute in order, so that the request for


// today's events will include the new event created.

// First request, no dependency


var addEventRequestId = await
batchRequestContent.AddBatchRequestStepAsync(addEventRequest);

// Second request, depends on addEventRequestId


var eventsRequestId = Guid.NewGuid().ToString();
var eventsRequestMessage = await
graphClient.RequestAdapter.ConvertToNativeRequestAsync<HttpRequestMessag
e>(calendarViewRequest);
batchRequestContent.AddBatchRequestStep(new BatchRequestStep(
eventsRequestId,
eventsRequestMessage,
new List<string> { addEventRequestId }
));

var returnedResponse = await


graphClient.Batch.PostAsync(batchRequestContent);

// De-serialize response based on known return type


try
{
var createdEvent = await returnedResponse
.GetResponseByIdAsync<Event>(addEventRequestId);
Console.WriteLine($"New event created with ID: {createdEvent.Id}");
}
catch (ServiceException ex)
{
Console.WriteLine($"Add event failed: {ex.Error.Message}");
}

// For collections, must use the *CollectionResponse class to


deserialize
// The .Value property will contain the *CollectionPage type that the
Graph client
// returns from GetAsync().
try
{
var events = await returnedResponse
.GetResponseByIdAsync<EventCollectionResponse>(eventsRequestId);
Console.WriteLine($"You have {events.Value.Count} events on your
calendar today.");
}
catch (ServiceException ex)
{
Console.WriteLine($"Get calendar view failed: {ex.Error.Message}");
}

Implementing batching using


BatchRequestContent, BatchRequestStep, and
HttpRequestMessage
The following example shows how to use BatchRequestContent , BatchRequestStep , and
HttpRequestMessage to send multiple requests in a batch and how to handle the limit of
20 with Microsoft Graph API requests. This example creates meeting links using the
onlineMeetings/createOrGet endpoint for the specified user ID. You can use this

example with other Microsoft Graph endpoints as well.

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;

public async void GenerateBatchedMeetingLink(List<ItemCollections>


meetingLinksToBeGenerated)
{
List<string> _joinWebUrls = new List<string>();
//Total number of items per batch supported is 20
int maxNoBatchItems = 20;
try
{
//valid GraphAccessToken is required to execute the call
var graphClient = GetAuthenticatedClient(GraphAccessToken);
var events = new List<OnlineMeeting>();
foreach (var item in meetingLinksToBeGenerated)
{
var externalId = Guid.NewGuid().ToString();
var @event = new OnlineMeeting
{
StartDateTime = item.StartTime,
EndDateTime = item.EndTime,
Subject = "Test Meeting",
ExternalId = externalId,

};
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);
}

if (batches.Count == 0 && batchRequestContent != null)


{
batches.Add(batchRequestContent);
}

foreach (BatchRequestContent batch in batches)


{
BatchResponseContent response = null;
response = await graphClient.Batch.Request().PostAsync(batch);
Dictionary<string, HttpResponseMessage> responses = await
response.GetResponsesAsync();
foreach (string key in responses.Keys)
{
HttpResponseMessage httpResponse = await
response.GetResponseByIdAsync(key);
var responseContent = await
httpResponse.Content.ReadAsStringAsync();
JObject eventResponse = JObject.Parse(responseContent);
//do something below
Console.WriteLine(eventResponse["joinWebUrl"].ToString());
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + ex.StackTrace);
}
}
Upload large files using the Microsoft
Graph SDKs
Article • 03/02/2023

A number of entities in Microsoft Graph support resumable file uploads to make it


easier to upload large files. Instead of trying to upload the entire file in a single request,
the file is sliced into smaller pieces and a request is used to upload a single slice. In
order to simplify this process, the Microsoft Graph SDKs implement a large file upload
task that manages the uploading of the slices.

Upload large file to OneDrive


C#

C#

using var fileStream = System.IO.File.OpenRead(filePath);

// Use properties to specify the conflict behavior


// in this case, replace
var uploadSessionRequestBody = new CreateUploadSessionPostRequestBody
{
Item = new DriveItemUploadableProperties
{
AdditionalData = new Dictionary<string, object>
{
{ "@microsoft.graph.conflictBehavior", "replace" }
}
}
};

// Create the upload session


// itemPath does not need to be a path to an existing item
var uploadSession = await graphClient.Drive.Root
.ItemWithPath(itemPath)
.CreateUploadSession
.PostAsync(uploadSessionRequestBody);

// Max slice size must be a multiple of 320 KiB


int maxSliceSize = 320 * 1024;
var fileUploadTask = new LargeFileUploadTask<DriveItem>(uploadSession,
fileStream, maxSliceSize, graphClient.RequestAdapter);

var totalLength = fileStream.Length;


// Create a callback that is invoked after each slice is uploaded
IProgress<long> progress = new Progress<long>(prog => {
Console.WriteLine($"Uploaded {prog} bytes of {totalLength} bytes");
});

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()}");
}

Resuming a file upload


The Microsoft Graph SDKs support resuming in-progress uploads. If your application
encounters a connection interruption or a 5.x.x HTTP status during upload, you can
resume the upload.

C#

C#

fileUploadTask.ResumeAsync(progress);

Upload large attachment to Outlook message


C#

C#

// Create message
var draftMessage = new Message
{
Subject = "Large attachment"
};

var savedDraft = await graphClient.Me


.Messages
.Request()
.AddAsync(draftMessage);

using var fileStream = System.IO.File.OpenRead(filePath);


var largeAttachment = new AttachmentItem
{
AttachmentType = AttachmentType.File,
Name = "largefile.gif",
Size = fileStream.Length
};

var uploadSession = await graphClient.Me


.Messages[savedDraft.Id]
.Attachments
.CreateUploadSession(largeAttachment)
.Request()
.PostAsync();

// Max slice size must be a multiple of 320 KiB


int maxSliceSize = 320 * 1024;
var fileUploadTask =
new LargeFileUploadTask<FileAttachment>(uploadSession, fileStream,
maxSliceSize);

var totalLength = fileStream.Length;


// Create a callback that is invoked after each slice is uploaded
IProgress<long> progress = new Progress<long>(prog => {
Console.WriteLine($"Uploaded {prog} bytes of {totalLength} bytes");
});

try
{
// Upload the file
var uploadResult = await fileUploadTask.UploadAsync(progress);

Console.WriteLine(uploadResult.UploadSucceeded ? "Upload complete" :


"Upload failed");
}
catch (ServiceException ex)
{
Console.WriteLine($"Error uploading: {ex.ToString()}");
}
Use the Microsoft Graph SDKs with the
beta API
Article • 01/21/2023

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;

// Create a new instance of GraphServiceClient.


GraphServiceClient graphClient = new GraphServiceClient(...);

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.

Microsoft Graph connector agent: A lightweight software component that


manages connector capabilities and coordinates between the Microsoft 365 admin
center 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.

Microsoft Graph connector agent capabilities


The connector agent is built on the same robust connector platform that is used to run
the Microsoft built-in connectors .

It includes the following capabilities:

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

The following capabilities are not currently available:


Microsoft Graph-based data source traversal during crawls; for example,
traversing through folder structures.
The ability to manage search permissions based on access control from your
data source.

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.

ConnectorCrawl Includes APIs that are called during a crawl.

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

GetBasicConnectorInfo GetBasicConnectorInfoRequest GetBasicConnectorInfoResponse Gets basic


information
about the
connector.
Used by the
platform to
fetch the
unique
connector ID.

HealthCheck HealthCheckRequest HealthCheckResponse Checks


communication
from the
platform to the
connector
server.

ConnectorInfo API models


The following sections describe the ConnectorInfo API models.

GetBasicConnectorInfoResponse
Response model that holds basic connector information.

Property Type Description

connectorId String Unique identifier and GUID for the connector.

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 .

Connection management APIs


Method Parameters Return Type Description

ValidateAuthentication ValidateAuthenticationRequest ValidateAuthenticationResponse Validates the


credentials
and data
source path
provided by
the admin in
the
connection
settings step.

ValidateCustomConfiguration ValidateCustomConfigurationRequest ValidateCustomConfigurationResponse Validates the


optional
configuration
provided by
the admin in
the
connection
configuration
step. If no
configuration
is required
for the
connector,
this API can
return a
success
response.

GetDataSourceSchema GetDataSourceSchemaRequest GetDataSourceSchemaResponse Gets the data


source
schema in a
format that
can be
understood
by Microsoft
Graph.

Connection management API models


The following sections describe the connection management API models.
ValidateAuthenticationRequest
Request model to validate the authentication request to the data source.

Property Type Description

authenticationData AuthenticationData Holds the data source access URL and the credentials to access it.

ValidateAuthenticationResponse

Response model to validate the authentication response to the data source.

Property Type Description

status OperationStatus Shows the status of the operation and details


like error messages.

oAuth2ClientCredentialResponse OAuth2ClientCredentialResponse Credential information to be sent to the


connector during the crawl if OAuth flow is
used (access token, refresh token, and so on,
sent by the auth server).

ValidateCustomConfigurationRequest

Request model to validate custom configuration request information.

Property Type Description

customConfiguration CustomConfiguration Provides configuration data for the connector.

authenticationData AuthenticationData Holds the data source access URL and the credentials to access it.

ValidateCustomConfigurationResponse

Request model to validate custom configuration response information.

Property Type Description

status OperationStatus Shows the status of the operation and details such as error messages.

GetDataSourceSchemaRequest

Request model to get the schema request of the data source.

Property Type Description

customConfiguration CustomConfiguration Provides configuration data for the connector.

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.

Property Type Description

status OperationStatus Shows the status of the operation and details such as error messages.

dataSourceSchema DataSourceSchema Shows the data source schema.

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.

Connector crawler API


Method Parameters Return Type Description

GetCrawlStream GetCrawlStreamRequest CrawlStreamBit as a Reads data


stream from the
data source.
This
method will
be called
during full
and
periodic full
crawls
where all
items
should be
read from
the data
source and
returned to
the
platform.
Method Parameters Return Type Description

GetIncrementalCrawlStream GetIncrementalCrawlStreamRequest IncrementalCrawlStreamBit Reads data


as a stream from the
data source.
This
method is
optional
and will be
called
during
incremental
crawls and
returns only
the
incremental
changes in
items since
last
incremental
crawl.

Connector crawler models


The following are the connector crawler models.

GetCrawlStreamRequest
Request model for getting items during crawl.

Property Type Description

customConfiguration CustomConfiguration Provides configuration data for the connector.

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.

Property Type Description

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

Request model for getting items during an incremental crawl.

Property Type Description

customConfiguration CustomConfiguration Provides configuration data for the connector.

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.

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.

Property Type Description

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.

Member Value Description

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.

Property Type Description

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

The properties linkItem and contentItem are mutually exclusive.

ItemType enumeration members for IncrementalCrawlItem

Enumeration fields for incremental crawl items.

Member Value Description

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.

Property Type Description

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

The properties linkItem, contentItem, and deletedItem are mutually exclusive.

ContentItem

Item that holds the content of the data source entity to be ingested. For example: the
content of a website.

Property Type Description

propertyValues SourcePropertyValueMap Holds the key and values of each property in the item.

accessList AccessControlList Restricts the access to the item to specific users or


groups.

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.

Property Type Description


Property Type Description

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.

Property Type Description

Entries repeated AccessControlEntry Shows the array or collection of access control list entries.

AclAccessType enumeration members


Enumeration members of the access control list type.

Member Value Description

None 0 Indicates the default value: deny.

Grant 1 The entry is for users/groups with access to the item.

Deny 2 The entry is for users/groups with no access the item and overrides grant for any
user/group.

AccessControlEntry

Holds individual access control entries.

Property Type Description

accessType AclAccessType Shows the access type of the entity either grant or deny.

principal Principal Represents a group or user with defined access.

PrincipalType enumeration members

Enumeration members of the principal type.


Member Value Description

PT_None 0 Indicates the default value: user.

User 1 Type of user.

Group 2 Type of group.

Everyone 3 Special group to grant access to everyone.

EveryoneExceptGuests 4 Special group to grant access to everyone except guests.

IdentitySource enumeration members

Enumeration members of identity source.

Member Value Description

IS_None 0 Indicates the default value: Azure Active Directory (Azure AD).

AzureActiveDirectory 1 The source of identity is Azure AD.

External 2 The source of identity isn't Azure AD.

IdentityType enumeration members

Enumeration members of identity type.

Member Value Description

IT_None 0 Indicates the default value: (Azure ADId).

ActiveDirectorySId 1 SID (On premise security identifier) provided by Active Directory (AD).

UserPrincipalName 2 User principal name (UPN).

AadId 3 Azure ADId.

Principal

Structure to store attributes of the principal (user/group).

Property Type Description

type PrincipalType Type of principal.

value string Principal value: the value of the SID, UPN, Azure ADId,
and so on.
Property Type Description

identitySource IdentitySource The source of identity.

identityType IdentityType Identity representation type.

identitySourceProperties map<string, Metadata about the identity source.


string>

SourcePropertyValueMap

Map of the source property key and its value in the data source. It stores the property value
of each item.

Property Type Description

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.

ContentType enumeration members


Enumeration members of content type.

Member Value Description

None 0 Default value

Text 1 Text content type

Html 2 Html content type

Binary 3 Binary content type

Bmp 4 Bmp content type

Jpg 5 Jpg content type

Pdf 6 Pdf content type

Png 7 Png content type

Tif 8 Tif content type

UnknownFutureValue 9 For future-proofing, following Microsoft Graph enumerations. All new


enumerations will be added below until a major API version change.
Content
Value of the content property of the item, used to render search results.

Property Type Description

contentType ContentType Type of the content.

contentValue string Value of the content property.

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.

Property Type Description

pagenumber uint32 Shows the page number to mark crawl progress.

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.

Property Type Description

stringValue string Represents a string value.

intValue int64 Represents an int64 (long) value.

doubleValue double Represents a double value.

dateTimeValue google.protobuf.Timestamp Represents a dateTime value.

boolValue bool Represents a Boolean value.

stingCollectionValue StringCollectionType Represents a collection of strings.

intCollectionValue IntCollectionType Represents a collection of int64 (long).

doubleCollectionValue DoubleCollectionType Represents a collection of double.

dateTimeCollectionValue TimestampCollectionType Represents a collection of dateTime.


StringCollectionType
Collection of strings.

Property Type Description

values repeated string Collection or array of strings.

IntCollectionType

Collection of integer values.

Property Type Description

values repeated int64 Collection or array of int64 (long) values.

DoubleCollectionType

Collection of double values.

Property Type Description

values repeated double Collection or array of double values.

TimestampCollectionType

Collection of DateTime values.

Property Type Description

values repeated google.protobuf.Timestamp Collection or array of dateTime values.


Microsoft Graph connectors SDK
connector OAuth API
Article • 03/16/2023

The Microsoft Graph connectors SDK contracts connector OAuth API is used for OAuth
flows such as refreshing access tokens during crawls.

Connector OAuth APIs


This API is used to generate a refreshed token from the auth server of the data source
and send the token details to the platform.

Method Parameters Return Type Description

RefreshAccessToken RefreshAccessTokenRequest RefreshAccessTokenResponse Shows the


refreshed
access
token.

Connector OAuth API models

RefreshAccessTokenRequest
Request model for refreshing the OAuth token.

Property Type Description

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.

Property Type Description

status OperationStatus Shows the status of the operation


and details such as error
messages.
Property Type Description

refreshedCredentialData OAuth2ClientCredentialsResponse Holds the refreshed token


information.
Microsoft Graph connectors SDK
common models
Article • 03/16/2023

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.

Property Type Description

configuration string Holds the configuration information as a string. The connector should
have the capability to interpret the content of the string.

AuthenticationType enumeration members


The following table lists the members of the AuthenticationType enumeration.

Member Value Description

Anonymous 0 No authentication is required to access the data source.

Basic 1 Basic Authentication in the form of username and password to


access the data source.

Windows 2 Windows Active Directory-based authentication supports


username, password, and domain info.

oAuth2ClientCredential 3 OAuth2 based authentication with client credentials. It supports


application ID and application secret.

AuthenticationData
Contains credentials provided by the admin to access the data source, including the
authentication type, data source URL, and the credentials data.

Property Type Description


Property Type Description

authType AuthenticationType Type of authentication information held in this


object.

DatasourceUrl string URL or path to access data source - path to


the resource that needs to be crawled.
Example: Connection string for a database.

basicCredential BasicCredential Credentials in the form of username and


password to access the data source. This
property will be set exclusive to
windowsCredential, and the authType will be
set to Basic when this property is set.

windowsCredential WindowsCredential Credentials in the form of Windows AD


username, password, and domain to access
the data source. This property will be set
exclusive to basicCredential, and the
authType will be set to Windows when this
property is set.

oAuth2ClientCredential oAuth2ClientCredential Credentials in the form of app ID and app


secret for OAuth client credentials based
authentication for accessing the datasource.
This property will be set exclusive to
oAuth2ClientCredential and the authType
will be set to oAuth2ClientCredential when
this property is set.

BasicCredential
Represents the basic credentials model.

Property Type Description

username string Username for accessing the data source.

secret string Secret to use with the username for accessing data source.

WindowsCredential
Represents the Windows credentials model.

Property Type Description


Property Type Description

username string Username for accessing the data source.

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.

Property Type Description

appId string Application ID/client ID for


the OAuth2 application.

appSecret String Application secret/client


secret for the OAuth2
application.

oAuth2ClientCredentialResponse oAuth2ClientCredentialResponse Contains OAuth token


related details. This
property will be set to the
response that the
connector sends after the
first validate authentication
call succeeds.

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.

Property Type Description

accessToken string The access token from auth server.

refreshToken string The refresh token if auth server sends it.

tokenType string Type of the token – usually Bearer token for OAuth.

expiresIn uint64 The expiry time of the token in Unix timestamp.


Property Type Description

scope string Scopes supported by the token if auth server sends it.

idToken string The ID token if auth server supports open ID connect.

OperationResult
The OperationResult enumeration contains the possible values for operation results.

Member Value Description

Success 0 The operation succeeded without any error.

PartialSuccess 1 Operation is a success, but there's a warning message to be


processed.

ValidationFailure 2 One or more validations failed.

AuthenticationIssue 3 Credentials provided didn't work.

DatasourceError 4 Data source read error.

NetworkError 5 Network operation error.

Canceled 6 The cancellation token canceled the operation.

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.

Property Type Description

result OperationResult Result of the operation.

statusMessage string Custom message that can be used for logging and
monitoring purposes.
Property Type Description

retryInfo RetryDetails Retry information to be used by the framework to retry the


same operation for a failed operation. If the operation
succeeds or partially succeeds, it will ignore.

RetryType enumeration members


This enumeration is used to define the strategy for retrying in case of errors.

Member Value Description

NoRetry 0 No retry has to be made.

Standard 1 Standard retry with linear wait time will be made.

ExponentialBackOff 2 Retry by exponential backoff will be made.

RetryDetails
This model is used for communicating the retry policy where retry is required.

Property Type Description

type RetryType Retry type defines the type of retry strategy


required for the error.

numberOfRetries uint32 Number of retries to be done for the exception.

pauseBetweenRetriesInMilliseconds uint64 Gets pause between retries in case of standard


retries.

backoffCoefficient float Gets coefficient used in the calculation of


Exponential Backoff.

backoffRate float Gets the backoffRate used in the calculation of


Exponential Backoff.

DataSourceSchema
Represents the schema of the properties that represent a data entity in the data source.
For details, see schema resource type.

Property Type Description


Property Type Description

PropertyList repeated Represents list of properties that define an item in


SourcePropertyDefinition data source.

SourcePropertyType enumeration members


Member Value Description

String 0 Property of type string.

Int64 1 Property of type int64 (long).

Double 2 Property of type double.

DateTime 3 Property of type DateTime.

Boolean 4 Property of type Boolean.

StringCollection 5 Property of type of array or collection of string type.

Int64Collection 6 Property of the type of array or collection of long type.

DoubleCollection 7 Property of type of array or collection of double type.

DateTimeCollection 8 Property of type of array or collection of DateTime type.

SearchAnnotations enumeration members


Member Value Description

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."

IsQueryable 2 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(*). For example, if the property is "Author," the search query can
be "Author: Smith"
Member Value Description

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.

IsRefinable 16 If a property is refinable, an admin can configure it as a custom filter on


the Microsoft Search results page. A refinable property can't be
searchable.

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.

SearchPropertyLabel enumeration members

Member Value Description

Title 0 The title of the item that you want to show in search and other
experiences.

Url 1 The target URL of the item in the data source.

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.

Authors 4 Name of all the people who participated/collaborated on 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.

FileName 7 In case of a file, the file's name is in the data source.


Member Value Description

FileExtension 8 In case of a file, the file's extension is 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.

AuthorsUpn 11 UPNs of all the people who participated/collaborated on the


item in the data source.

UnknownFutureValue 12 For future-proofing, following Microsoft Graph evolvable


enums. Add all new enumerations below this one until major
API version changes.

ContainerName 13 Name of the container.

ContainerUrl 14 The URL of the container.

IconUrl 15 The URL of an icon.

SourcePropertyDefinition
Defines a single source property for an item in data source. For details about schema
property definitions, see property resource type.

Property Type Description

name string Name of the property.

type SourcePropertyType Data type of the property.

defaultSearchAnnotations uint32 Default search annotations for the property.

requiredSearchAnnotations uint32 Required search annotations. Certain


properties like ID is always set to
isQueryable true and isRetrievable true .

defaultSemanticLabels repeated List of semantic labels for the source


SearchPropertyLabel property.

order int32 Order of this source property. Used by UI for


sorting the search results. Optional.

label string Label of this source property. Used by search


results UI to display the label (human-
readable name). Optional.
Property Type Description

aliases repeated string List of aliases of this source property.


Optional.
Microsoft Graph connectors SDK test
application
Article • 03/16/2023

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.

Update the following configuration files to use this test utility:

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.

CustomConnectorPortMap.json: After you create the custom connector, add the


mapping of the connector ID and the port it's running on to this file. This file is in
the Microsoft Graph connector agent installation folder.

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.

Provide the manifest details in the following format:


JSON

{
// 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" ],

// The list of additional crawl types that the connector supports in


addition to full and periodic full crawl. This is an optional field.
"additionalCrawlsSupported": [ "Incremental" ]
}

connectorId should be a GUID. This field is the same as ConnectorUniqueId in


the Connector Info Service implementation file or the GUID that you define.
AuthTypes must be a non-empty array with one or more of the following types:
Anonymous , Basic , Windows , OAuth2ClientCredentials .

additionalCrawlsSupported is optional; you can define crawl types in addition


to full and periodic full crawl, depending on your implementation and the data
source support. Only Incremental crawl is available as an option currently.

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 connection creation flow (ValidateAuthentication,


ValidateCustomConfiguration, GetDataSourceSchema APIs): Validates the methods
specified in ConnectionManagementService. It invokes each of the methods and
displays the results on the console.
Validate Manifest: Validates the content of manifest.json. It checks whether the
APIs related to the information provided in the manifest are implemented. The test
application returns the updated manifest after validation. Use this validated
manifest for further testing and use.

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.

How does the GraphConnectorAgentTest


executable file work?
When you open the GraphConnectorAgentTest executable file, it reads the
ConnectionInfo.json configuration file. After you select one of the test options, it will try
to connect to the specified connector over the port indicated in the
CustomConnectorPortMap configuration file. After it connects, the platform calls the
relevant methods.

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:

1. Ensure that the CustomConnectorPortMap.json file is updated. After you develop


the custom connector code, add the mapping of the connector ID and the port it's
running on to this file. This file is in the Microsoft Graph connector agent
installation folder.

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.

8. Manage the schema:

Select a Content Property. We recommend that you select a Content Property


from the drop-down menu of options, or keep the default, if one is present.
This property is used for full-text indexing of content and improving your
search relevance.
Define aliases for your properties. You can add aliases to your properties on
the Manage schema page in the Alias column. Aliases are friendly names for
your properties.
Set the search schema attributes. You can set the search schema attributes to
control the search functionality of each source property. A search schema
helps determine what results display on the search results page and what
information end users can view and access.

For details, see Step 7: Manage schema.

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.

The following image shows an example of a project structure.


5. Implement methods in the stubs generated by the compiler.

6. Create a server, run the application, and generate the executable/output binaries.

7. Test the connector code using the TestApp utility.

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.

Using the crawl progress marker


The crawl progress marker acts as an identifier for the particular item sent by the
connector that was last processed by the platform. You can implement two types of
crawls: periodic full and incremental.

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.

Usage of the crawl progress marker during periodic full


crawls
The SDK sends the crawl progress marker if the previous crawl crashed or a scheduled
crawl was missed due to the Microsoft Graph connector agent being offline during
periodic full crawls.

If the previous crawl did not crash, you have to crawl the data source from the
beginning.

Usage of the crawl progress marker during incremental


crawls
During one incremental crawl, the connector sends the crawl progress marker to the
connector platform, and it will continue to do so for the next incremental crawls. The
connector can use this crawl to fetch added or modified items after this marker.

Constructing generic types


The property values of the content item can have a range of data types. Because gRPC
doesn't have a construct for generic objects, the SDK includes a GenericType structure
that can hold any of the supported data types. GenericType has the following structure:

C#

// Represents a generic type that can hold any supported value


message GenericType {
// Value of the Generic type
oneof value {
// String type value
string stringValue = 1;

// Long value
int64 intValue = 2;

// Double value
double doubleValue = 3;

// DateTime value
google.protobuf.Timestamp dateTimeValue = 4;

// Boolean value
bool boolValue = 5;

// String collection value


StringCollectionType stringCollectionValue = 6;

// Long collection value


IntCollectionType intCollectionValue = 7;

// Double collection value


DoubleCollectionType doubleCollectionValue = 8;

// DateTime collection value


TimestampCollectionType dateTimeCollectionValue = 9;
}
}

// 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#

// Setting string value in generic type


GenericType stringType = new GenericType
{
StringValue = "Hello"
};

// Setting int64 value in generic type


GenericType int64Type = new GenericType
{
IntValue = 1000
};

// Setting double value in generic type


GenericType doubleType = new GenericType
{
DoubleValue = 12.54
};

// Setting dateTime value in generic type


GenericType dateTimeType = new GenericType
{
DateTimeValue =
Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(DateTime.UtcNow)
};

// Setting boolean value in generic type


GenericType boolType = new GenericType
{
BoolValue = true
};

// Setting string collection value in generic type - Initialize the


string collection first, add the values to the string collection and then
set it in the generic type
StringCollectionType stringCollection = new StringCollectionType();
stringCollection.Values.Add("Value1");
stringCollection.Values.Add("Value2");
GenericType stringCollectionType = new GenericType
{
StringCollectionValue = stringCollection
};

// Setting int64 collection value in generic type - Initialize the int64


collection first, add the values to the int64 collection and then set it in
the generic type
IntCollectionType intCollection = new IntCollectionType();
intCollection.Values.Add(1234);
intCollection.Values.Add(5436);
GenericType intCollectionType = new GenericType
{
IntCollectionValue = intCollection
};

// Setting double collection value in generic type - Initialize the


double collection first, add the values to the double collection and then
set it in the generic type
DoubleCollectionType doubleCollection = new DoubleCollectionType();
doubleCollection.Values.Add(12.54);
doubleCollection.Values.Add(34.213);
GenericType doubleCollectionType = new GenericType
{
DoubleCollectionValue = doubleCollection
};

// Setting datetime collection value in generic type - Initialize the


datetime collection first, add the values to the datetime collection and
then set it in the generic type
TimestampCollectionType dateTimeCollection = new
TimestampCollectionType();

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.

Fetching items during a crawl


The GetCrawlStream method is a server streaming method . It converts each item
from the data source into a CrawlStreamBit during the crawl and sends it over the
response stream.

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.

Exception handling in connector code


All responses from the gRPC calls have an OperationStatus that indicates whether the
operation succeeded or failed, the failure reason, and retry details if there are failures.
We recommend wrapping the entire code in a try-catch block. The connector should log
all exceptions and send a proper operation status to the platform.

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.

Sending back errors from connector to


platform
All responses use the OperationStatus in the response structure. If any errors occurred,
the connectors should use OperationStatus to send the failure reason and retry
information back to the platform. Use OperationStatus to set the errors during crawls if
connection-level errors like expired credentials to access data source occur.

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.

Items missing from the index


If items that previously existed are missing from the index, this might be due to the
delete detection logic in the platform. Items missing from a success response in
OperationStatus that are already in the index will be removed from the index.

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.

Handle connector port changes


When the connector needs to run on a different port, you need to update the port map
configuration file with the new values. When you edit the port map configuration file,
you must restart the GCA service for the changes to take effect. To restart the service,
open services.msc and restart GcaHostService.

Connection failure after GCA upgrade


If you notice connection failures after upgrading from a GCA version 1.8.0.0 or lower,
follow the following steps:

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.

Handle RPC errors


If you see any RPC errors during the communication between the Microsoft Graph
connector agent platform and the connector, you can look up the error codes on the
status codes page.

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.

Locating the log file for your custom connector


If you're using the GraphConnectorsTemplate to develop your custom connector, the
AppData folder of the current user account is used to store logs by default. You can also
provide an absolute path for storing logs in the ConnectorServer.cs file of the template.
The user account should have access to the absolute path you've provided.

The following are the locations of the log path, depending on your use case:

Connector not hosted as a Windows service:

Path

C:\Users\{User Account}\AppData\Local\Microsoft\{Connector
Name}\Logs\ConnectorLog.log

Connector hosted as a Windows service under the LOCAL SYSTEM account:

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

Connector hosted as a Windows service under the LOCAL SYSTEM account:

Path

C:\Windows\ServiceProfiles\LocalService\AppData\Local\Microsoft\
{Connector Name}\Logs\ConnectorLog.log

7 Note

GraphConnectorsTemplate v2.1 and above supports storing logs for


connectors hosted as a Windows service.
Make sure you provide a unique connector name in the ConnectorServer.cs
file to ensure that logs for each unique connector are stored separately.

Errors with hosting a connector as a Windows


service

Service failed to start due to access denied error


Use the following steps to make sure that the path of the executable is accessible to the
LocalService account.

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.

Service fails to start with any error


If the service fails to start, check the event viewer error logs. Open the event viewer and
go to Windows logs > Application and Windows logs > System.

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.

Microsoft Graph PowerShell features & benefits


The Microsoft Graph PowerShell SDK provides the following benefits:

Access to all Microsoft Graph APIs: Microsoft Graph PowerShell is based on


Microsoft Graph API. In addition to Azure AD, the Microsoft Graph API includes
APIs from other Microsoft services like SharePoint, Exchange, and Outlook, all
accessed through a single endpoint with a single access token.
Supports PowerShell 7: Microsoft Graph PowerShell works with PowerShell 7 and
later. It's also compatible with Windows PowerShell 5.1.
Cross-platform support: Microsoft Graph PowerShell works on all platforms
including Windows, macOS, and Linux.
Supports modern authentication: Microsoft Graph PowerShell supports the
Microsoft Authentication Library (MSAL) which offers more security. For example,
you can use passwordless sign-in experiences.
Supports external identities: Users from other Azure AD tenants can authenticate
to services in your tenant with Microsoft Graph PowerShell.
Uses least privilege: Microsoft Graph PowerShell permissions are not pre-
authorized and users must perform one-time request for app permissions
depending on their needs.
Advanced queries: Microsoft Graph PowerShell supports rich, advanced queries via
eventual consistency. For example, you can get a near-instant count of all users
using advanced queries.
Open source: Feature teams and the community can create great PowerShell
experiences and share them with everyone.
Receives regular updates: Microsoft Graph PowerShell commands are updated
regularly to support the latest Graph API updates.

Upgrade your environment to use the


Microsoft Graph PowerShell SDK
To understand how to migrate from Azure AD PowerShell to Microsoft Graph
PowerShell, follow the migration guide.

Install the Microsoft Graph PowerShell SDK


The Microsoft Graph PowerShell SDK is published on the PowerShell Gallery . Follow
the Install the SDK instructions to install the the Microsoft Graph PowerShell SDK.

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.

Upgrade to PowerShell 5.1 or later

Install .NET Framework 4.7.2 or later

Update PowerShellGet to the latest version using Install-Module PowerShellGet

The PowerShell script execution policy must be set to remote signed or less
restrictive . Use Get-ExecutionPolicy to determine the current execution policy.

For more information, see about_Execution_Policies. To set the execution policy,


run:

PowerShell

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

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

Install-Module Microsoft.Graph -Scope CurrentUser

Optionally, you can change the scope of the installation using the -Scope parameter.
This requires admin permissions.

PowerShell

Install-Module Microsoft.Graph -Scope AllUsers

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

To verify the installed sub-modules and their versions, run:

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

Uninstalling the SDK


First, use the following command to uninstall the main module.

PowerShell

Uninstall-Module Microsoft.Graph

Then, remove all of the dependency modules by running the following commands.

PowerShell

Get-InstalledModule Microsoft.Graph.* | %{ if($_.Name -ne


"Microsoft.Graph.Authentication"){ Uninstall-Module $_.Name } }
Uninstall-Module Microsoft.Graph.Authentication

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

Select-MgProfile -Name "beta"

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.

Determine required permission scopes


Each API in the Microsoft Graph is protected by one or more permission scopes. The
user logging in must consent to one of the required scopes for the APIs you plan to use.
In this example, we'll use the following APIs.

List users to find the user ID of the logged-in user.


List joinedTeams to get the Teams the user is a member of.
List channels to get the channels in a Team.
Send message to send a message to a Team's channel.

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.

Using Find-MgGraphCommand to find required permissions


The Find-MgGraphCommand cmdlet can be used to discover the required permissions for
another cmdlet. For example, to see all permissions that can be used to call Get-MgUser ,
run;

PowerShell

Find-MgGraphCommand -command Get-MgUser | Select -First 1 -ExpandProperty


Permissions

Output

Name IsAdmin Description


FullDescription
---- ------- -----------
---------------
Directory.Read.All True Read directory data
Allows the app to read data in your organization's directory.
Directory.ReadWrite.All True Read and write
directory data Allows the app to read and write data in your
organization's directory, such as other users, groups. It does not allow
the app to delete users or groups, or reset user passwords.
User.Read.All True Read all users' full
profiles Allows the app to read the full set of profile
properties, reports, and managers of other users in your organization, on
your behalf.
User.ReadBasic.All False Read all users' basic
profiles Allows the app to read a basic set of profile
properties of other users in your organization on your behalf. Includes
display name, first and last name, email address and photo.
User.ReadWrite.All True Read and write all
users' full profiles Allows the app to read and write the full set of
profile properties, reports, and managers of other users in your
organization, on your behalf.

This output has been shortened for readability.

For more information on using this cmdlet, see Using Find-MgGraphCommand.

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

Connect-MgGraph -Scopes "User.Read.All","Group.ReadWrite.All"

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

You can add additional permissions by repeating the Connect-MgGraph command


with the new permission scopes.

Call Microsoft Graph


Now that you're signed in, you can start making calls to Microsoft Graph.

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.

Get the signed-in user


In this section, you'll locate the signed-in user and get their user Id. You'll need the user
Id as a parameter to the other commands you'll run later. Start by running the following
command.

PowerShell

Get-MgUser

This command outputs a listing of users in your Microsoft 365 organization.

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

$user = Get-MgUser -Filter "displayName eq 'Megan Bowen'"

Verify that worked by entering the following.

PowerShell

$user.DisplayName

List the user's joined teams


Now use the user's Id as a parameter to the Get-MgUserJoinedTeam command.

PowerShell

Get-MgUserJoinedTeam -UserId $user.Id

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

Get-MgTeamChannel -TeamId $team.Id


$channel = Get-MgTeamChannel -TeamId ID_FROM_PREVIOUS_STEP -Filter
"displayName eq 'General'"

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

New-MgTeamChannelMessage -TeamId $team.Id -ChannelId $channel.Id -Body @{


Content="Hello World" }

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

New-MgTeamChannelMessage -TeamId $team.Id -ChannelId $channel.Id -Body @{


Content="Hello World" } -Importance "urgent"

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 naming conventions


The commands in the SDK are generated directly from the REST API, so the names are
influenced by the API. You don't have to understand the details of the API to use the
Microsoft Graph PowerShell SDK, but it helps to understand the naming convention.

PowerShell commands are named using a verb-noun pair, such as Get-Command or


Update-List . Let's start with the verb.

Command verbs
For basic REST operations, the verb is determined by the HTTP method used for the API.

HTTP method Command verb Example

GET Get Get-MgUser API reference

POST New New-MgUserMessage API reference

PUT New New-MgTeam API reference


HTTP method Command verb Example

PATCH Update Update-MgUserEvent API reference

DELETE Remove Remove-MgDriveItem API reference

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.

But what about commands like Get-MgUserMessage or Get-MgUserMailFolderMessage ?


Both of these commands get a message object, so why not Get-MgMessage ? The answer
comes from the get message API.

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

GET /users/{id | userPrincipalName}/messages/{id}


GET /users/{id | userPrincipalName}/mailFolders/{id}/messages/{id}

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 .

Use Find-MgGraphCommand to discover which API path a command calls by providing


a URI or a command name.

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

Get-Help Get-MgUser -Detailed

Finding available commands


Sometimes just knowing the naming conventions isn't enough to guess the right
command. In this case, you can use the Get-Command command to search the available
commands in the SDK. For example, if you're looking for commands related to Microsoft
Teams, you can run the following command.

PowerShell

Get-Command -Module Microsoft.Graph* *team*

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

App-only access grants permissions directly to an application, and requires an


administrator to consent to the required permission scopes. For more information
on app-only access, see Microsoft identity platform and the OAuth 2.0 client
credentials flow.

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.

Register the application


You can register the application either in the Azure Active Directory portal , or using
PowerShell.

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.

Set Name to Graph PowerShell Script .


Set Supported account types to Accounts in this organizational
directory only.
Leave Redirect URI blank.
4. Select Register.

5. On the Graph PowerShell Script page, copy the values of the Application
(client) ID and Directory (tenant) ID and save them.

6. Select API Permissions under Manage. Select Add a permission.

7. Select Microsoft Graph then select Application Permissions. Check


User.Read.All and Group.Read.All, then select Add permissions.

8. In the Configured permissions, remove the delegated User.Read permission


under Microsoft Graph by selecting the ... to the right of the permission and
selecting Remove permission. Select Yes, remove to confirm.

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.

Certificate subject or thumbprint of the certificate uploaded to your Azure AD app


registration.
Application ID for your app registration.
Your tenant ID.

We'll use this information to test authentication. Open PowerShell and run the following
command, replacing the placeholders with your information.

PowerShell

Connect-MgGraph -ClientID YOUR_APP_ID -TenantId YOUR_TENANT_ID -


CertificateName YOUR_CERT_SUBJECT ## Or -CertificateThumbprint instead of -
CertificateName

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

Welcome To Microsoft Graph!


USERS:
======================================================

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 is a collection of reusable, framework-agnostic components and


authentication providers for accessing and working with Microsoft Graph. The
components are fully functional right of out of the box, with built-in providers that
authenticate with and fetch data from Microsoft Graph.

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

Open this example in mgt.dev .

What's in Microsoft Graph Toolkit?

Components
Microsoft Graph Toolkit includes a collection of web components for the most
commonly built experiences powered by Microsoft Graph APIs.

The components are also available as React components.

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 Displays a group of people or contacts by their photos or initials.

Agenda Displays events in a user's or group's calendar.

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.

File list Displays a list of multiple files or folders.

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.

To Do Displays and enables adding, removing, completing, or editing of tasks from


Microsoft To Do.

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.

Electron Authenticates and provides Microsoft Graph access to components inside of


Electron apps.
Providers Description

SharePoint Authenticates and provides Microsoft Graph access to components inside of


SharePoint web parts.

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.

Why use Microsoft Graph Toolkit?


Microsoft Graph Toolkit enables you to quickly and easily integrate common
experiences powered by Microsoft Graph into your own application. The toolkit:

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.

Who should use it?


Microsoft Graph Toolkit is great for developers of all experience levels that want to
develop an app that connects to and accesses data from Microsoft Graph, such as a:

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:

Edge Firefox Chrome Safari Opera Samsung

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.

Watch this short video to get started using the toolkit.


https://www.youtube-nocookie.com/embed/oZCGb2MMxa0

For a step-by-step tutorial, see the Get started with Microsoft Graph Toolkit module.

Set up your Microsoft 365 tenant


To use Microsoft Graph Toolkit to develop an app, you need access to a Microsoft 365
tenant. If you don't have one, you can get a free Microsoft 365 developer subscription
by joining the Microsoft 365 Developer Program. For details about how to configure
your subscription, see Set up a Microsoft 365 developer subscription.

Set up your development environment


To develop with the toolkit, you need the following:

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 .

Use Microsoft Graph Toolkit


You can use Microsoft Graph Toolkit in your application by referencing the loader
directly (via unpkg ) or by installing the npm package.

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

The @microsoft/mgt-components package contains all the Microsoft Graph connected


web components, such as Person , PeoplePicker , and more.

Providers

Providers are available via a single package and can be installed as needed. The
following provider packages are available:

@microsoft/mgt-msal-provider

@microsoft/mgt-msal-provider contains the MsalProvider and 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-msal2-provider contains the Msal2Provider and mgt-msal2-

provider component. The MSAL2 provider uses msal-browser for authenticating in

web apps and PWAs.

@microsoft/mgt-teams-provider

@microsoft/mgt-teams-provider contains the TeamsProvider and mgt-teams-


provider component. The Microsoft Teams provider enables authentication in the
Microsoft Teams tab application.

@microsoft/mgt-teams-msal2-provider

@microsoft/mgt-teams-msal2-provider contains the TeamsMsal2Provider and mgt-

teams-msal2-provider component. The Microsoft Teams MSAL2 provider enables


authentication in the Microsoft Teams tab application.

@microsoft/mgt-sharepoint-provider

@microsoft/mgt-sharepoint-provider contains the SharePointProvider for


authenticating in a SharePoint environment.

@microsoft/mgt-proxy-provider

@microsoft/mgt-proxy-provider contains the ProxyProvider for an application that

proxy Graph calls through a backend service.

@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

The @microsoft/mgt-react package contains all the auto-generated React components


and takes dependency on the @microsoft/mgt package.

@microsoft/mgt-spfx

The @microsoft/mgt-spfx package contains a SharePoint Framework library that's


required to use Microsoft Graph Toolkit in SharePoint Framework solutions.

Next steps
You're now ready to start developing with Microsoft Graph Toolkit! The following guides
are available to help you get started:

Register an Azure Active Directory (Azure AD) app


Build a web app (JavaScript) (vanilla JavaScript)
Build a web app (React)
Build a web app (Angular)
Build a SharePoint web part
Build a Microsoft Teams tab
Build a Microsoft Teams SSO tab
Build an Electron app
Microsoft Graph Toolkit React
components
Article • 03/31/2022

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.

What components can I use?


The library is autogenerated from the Microsoft Graph Toolkit web components and all
components are available 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

npm install @microsoft/mgt-react

or

Bash

yarn add @microsoft/mgt-react

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

import { Person } from '@microsoft/mgt-react';


You can now use Person anywhere in your JSX as a regular React component.

tsx

<Person personQuery="me" />

All properties and events map exactly as they are defined in the component
documentation.

For example, you can set the personDetails property to an object:

jsx

const App = (props) => {


const personDetails = {
displayName: 'Bill Gates',
};

return <Person personDetails={personDetails}></Person>;


};

Or, register an event handler:

jsx

import { PeoplePicker, People } from '@microsoft/mgt-react';

const App = (props) => {


const [people, setPeople] = useState([]);

const handleSelectionChanged = (e) => {


setPeople(e.target.selectedPeople);
};

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

import { MgtTemplateProps } from '@microsoft/mgt-react';

const MyEvent = (props: MgtTemplateProps) => {


const { event } = props.dataContext;
return <div>
{event.subject}<br />
{event.attendees
.map((attendee: any) => attendee.emailAddress.name)
.join(', ')}
</div>;
};

Then use it as a child of the wrapped component and set the template prop to event .

tsx

import { Agenda } from '@microsoft/mgt-react';

const App = (props) => {


return <Agenda>
<MyEvent template="event">
</Agenda>
}

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

passed as part of the dataContext prop.

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

npm install @microsoft/mgt-spfx

or

Bash

yarn add @microsoft/mgt-spfx

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

import { Providers, SharePointProvider } from '@microsoft/mgt-spfx';

// [...] trimmed for brevity

export default class MgtWebPart extends


BaseClientSideWebPart<IMgtWebPartProps> {
protected async onInit() {
if (!Providers.globalProvider) {
Providers.globalProvider = new SharePointProvider(this.context);
}
}

// [...] trimmed for brevity


}

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);
}
}

public render(): void {


this.domElement.innerHTML = `
<div>
<mgt-person person-query="me"></mgt-person>
</div>`;
}

// [...] trimmed for brevity


}

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

import { Person } from '@microsoft/mgt-react/dist/es6/spfx';


import { ViewType } from '@microsoft/mgt-spfx';

// [...] trimmed for brevity

export default class MgtReact extends React.Component<IMgtReactProps, {}> {


public render(): React.ReactElement<IMgtReactProps> {
return (
<div className={ styles.mgtReact }>
<Person personQuery="me" view={ViewType.image}></Person>
</div>
);
}
}

) 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.

Add new application registration in Azure


Active Directory
To create an application in Azure Active Directory, you need to add a new application
registration, and then configure an app name and URL location.

To create the app in Azure Active Directory:

1. Go to the Azure portal at https://portal.azure.com .


2. From the menu, select Azure Active Directory.
3. From the Azure Active Directory menu, select App registrations.
4. From the top menu, select the New registration button.
5. Enter the name for your app; for example, My M365 app .
6. For the type of supported account types, select Accounts in any organizational
directory (Any Azure AD directory - Multitenant) and personal Microsoft
accounts (e.g. Skype, Xbox).
7. For the Redirect URI field:

If using Msal2Provider or TeamsMsal2Provider , select Single Page Application


(SPA), and in the URL field, enter your redirect URL (and/or http://localhost
if testing locally).
If using MsalProvider or TeamsProvider , select Web, and in the URL field,
enter your redirect URL (and/or http://localhost if testing locally).

8. Confirm changes by selecting the Register button.

Enable OAuth implicit flow (only for


MsalProvider and TeamsProvider)
In most cases, you will use Microsoft Graph Toolkit in client-side applications that
consist only of client-side code. Because client-side apps can't store secrets securely,
you need to use OAuth implicit flow, which assumes an app's identity based on its ID
and URL.

1. In the Azure Portal, open your newly created app registration.


2. From the menu, choose Authentication.
3. In the Implicit grant section, enable both Access tokens and ID tokens options.
4. Confirm your changes by choosing the Save button.

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:

1. Add Microsoft Graph Toolkit to your project.


2. Initialize the MSAL2 Provider.
3. Add components.
4. Test your application.

Add the Microsoft Graph Toolkit to your


project
You can use the Microsoft Graph Toolkit in your application by referencing the loader
directly (via unpkg) or by installing the npm package.

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>

Initialize the MSAL2 Provider


The Microsoft Graph Toolkit providers enable authentication and access to Microsoft
Graph for the components. To learn more, see Using the providers. The MSAL2 Provider
uses msal-browser to sign in users and acquire tokens. You can initialize this provider in
your HTML or JavaScript.
Note: If you are currently using the MSAL Provider and would like to update to
MSAL2 Provider, follow the steps listed here. If you would like to use your own
backend authentication, use the Proxy Provider in place of the MSAL2 Provider.

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>

Test your app


In order to test your app, MSAL requires the page to be hosted in a web server for the
authentication redirects.

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.

Track a user's sign in state


You can detect when a user has successfully signed in and display specific components
accordingly. For example, display the agenda component if the user has signed in.
Otherwise, display the sign in interface.

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

Microsoft Graph Toolkit is a set of web components that simplify connecting to


Microsoft Graph and allow you to focus on your application instead. Microsoft Graph
Toolkit is available as a generic set of web components distributed through the
@microsoft/mgt npm package.

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.

Create a React app


Create a new React app by running the following command. This will create a new React
app using TypeScript, which will help you write more robust code and avoid runtime
errors.

Command

npx create-react-app my-m365-app --template typescript --use-npm

Change the working directory to the newly created app.


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

npm i @microsoft/mgt-element @microsoft/mgt-msal2-provider

Confirm that you can run the app.

Command

npm start

You should be able to open your app in the browser via http://localhost:3000 .

Create an Azure Active Directory app


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.

Follow the steps in the Create an Azure Active Directory app article to create a new
Azure AD app.

Connect React app to Microsoft 365


Now that you have registered your application with Azure Active Directory (Azure AD),
you can connect the React app to Microsoft 365. First, allow users to sign in to the app
using their Microsoft account.
Copy the Azure AD application registration ID
1. In the Azure Portal, go to your application registration.
2. Verify that you are on the Overview page.
3. From the Essentials section, copy the value of the Application (client) ID property

Configure the Microsoft Graph Toolkit authentication


provider
Next, configure the authentication provider that the Microsoft Graph Toolkit should use.
In this case, you'll use MSAL, which is a good default for building standalone
applications. If you use any of the extensibility points in Microsoft 365, like Teams or
SharePoint, you will use other 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.

1. In the code editor, open the src/index.tsx file, and to the list of imports, add:

TypeScript

import { Providers } from '@microsoft/mgt-element';


import { Msal2Provider } from '@microsoft/mgt-msal2-provider';

2. After the last import statement, initialize the Microsoft Graph Toolkit with MSAL
provider.

TypeScript

Providers.globalProvider = new Msal2Provider({


clientId: 'REPLACE_WITH_CLIENTID'
});

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';

import { Providers } from '@microsoft/mgt-element';


import { Msal2Provider } from '@microsoft/mgt-msal2-provider';

Providers.globalProvider = new Msal2Provider({


clientId: 'REPLACE_WITH_CLIENTID'
});

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();

Add the Sign in button


Add the Login Microsoft Graph Toolkit React component, which will display the Sign in
button people can use to sign in with their Microsoft account to your app.

1. In the code editor, open the src/App.tsx file, and to the list of imports add:

TypeScript

import { Login } from '@microsoft/mgt-react';

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

import { Login } from '@microsoft/mgt-react';


import React from 'react';
import './App.css';

function App() {
return (
<div className="App">
<header>
<Login />
</header>
</div>
);
}

export default App;

Test signing in to your application


You should now be able to sign in to your application with your Microsoft account.

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.

Specify permissions needed for your application


Before you can load data from Microsoft 365, you need to specify the list of permission
scopes your application must be granted to access user's data. These scopes differ
depending on what kind of information you want to show. In this case, you will need
access to people's calendar as well as basic access to information about people that is
also displayed in the calendar. You can find the scopes required by each API in the
Microsoft Graph API documentation.

1. In the code editor, open the src/index.tsx file, and update the provider
initialization code.

TypeScript

Providers.globalProvider = new Msal2Provider({


clientId: 'REPLACE_WITH_CLIENTID',
scopes: ['calendars.read', 'user.read', 'openid', 'profile',
'people.read', 'user.readbasic.all']
});

Show user's data after signing in


Next, extend the application to show data from the user's calendar. You can access this
information only after the user has signed in. To do this, you will need to track the user's
sign in state and show the calendar data after the user has signed in with their Microsoft
account.

Track user's sign in state

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';

2. Import the Provider and ProviderState types from mgt-element , by adding to


imports.

TypeScript

import { Providers, ProviderState } from '@microsoft/mgt-element';

3. Add a custom function named useIsSignedIn that enables tracking the user's sign
in state in your application.

TypeScript

function useIsSignedIn(): [boolean] {


const [isSignedIn, setIsSignedIn] = useState(false);

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.

Load user's calendar if user is signed in


Now that you track the user's sign in state in your application, you can show their
calendar after they signed in.
1. In the code editor, open the src/App.tsx file, and extend the component import
statement with the Agenda component.

TypeScript

import { Agenda, Login } from '@microsoft/mgt-react';

2. Next, inside the App function, add:

TypeScript

const [isSignedIn] = useIsSignedIn();

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

import { Providers, ProviderState } from '@microsoft/mgt-element';


import { Agenda, Login } from '@microsoft/mgt-react';
import React, { useState, useEffect } from 'react';
import './App.css';

function useIsSignedIn(): [boolean] {


const [isSignedIn, setIsSignedIn] = useState(false);

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>
);
}

export default App;

Test showing user's calendar after they signed in


With these changes, after signing in to your application with your Microsoft account,
you should see your calendar.

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.

Add the Microsoft Graph Toolkit


First, you need to enable custom elements in your Angular application by adding the
CUSTOM_ELEMENT_SCHEMA to the @NgModule() decorator in app.module.ts . The following
example shows how to do this:

TypeScript

import { BrowserModule } from '@angular/platform-browser';


import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

import { AppComponent } from './app.component';

@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

npm install @microsoft/mgt

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

import { Component, OnInit } from '@angular/core';


import { Providers, Msal2Provider } from '@microsoft/mgt';

@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

<mgt-person person-query="me" view="twolines"></mgt-person>

Customizing components with Angular


All Microsoft Graph Toolkit components support custom templates, which allow you to
modify the content of a component. The default syntax for customizing the components
is to use double braces to refer to the property data for each of the returned items, as
shown:

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

import { Component, OnInit } from '@angular/core';


import { Providers, Msal2Provider, TemplateHelper } from '@microsoft/mgt';

@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:

1. Set up your development environment and create a web part.


2. Add the Microsoft Graph Toolkit SharePoint Framework package.
3. Add the SharePoint Provider.
4. Add components.
5. Configure permissions.
6. Deploy the Microsoft Graph Toolkit SharePoint Framework package.
7. Build and deploy your web part.
8. Test your web part.

Set up your SharePoint Framework


development environment and create a new
web part
Follow the steps to Set up your SharePoint Framework development environment and
then create a new web part.

Add the Microsoft Graph Toolkit SharePoint


Framework package
To prevent multiple SharePoint Framework components from registering their own set
of Microsoft Graph Toolkit components on the page, you should deploy the Microsoft
Graph Toolkit SharePoint Framework package to your tenant and reference Microsoft
Graph Toolkit components that you use in your solution from this package.

The Microsoft Graph Toolkit SharePoint Framework package contains a SharePoint


Framework library that registers a single instance of Microsoft Graph Toolkit
components in SharePoint.

Install the Microsoft Graph Toolkit SharePoint Framework npm package using the
following command:
Bash

npm install @microsoft/mgt-spfx

Add the SharePoint Provider


The Microsoft Graph Toolkit providers enable authentication and access to Microsoft
Graph for the components. To learn more, see Using the providers. SharePoint web parts
always exist in an authenticated context because the user has already had to sign in in
order to get to the page that hosts your web part. Use this context to initialize the
SharePoint provider.

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

import { Providers, SharePointProvider } from '@microsoft/mgt-spfx';

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

the public render(): void { line:

ts

protected async onInit() {


if (!Providers.globalProvider) {
Providers.globalProvider = new SharePointProvider(this.context);
}
}

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,

Just below that line, add the following:

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"
}
]

Deploy the Microsoft Graph Toolkit SharePoint


Framework package
Before deploying your SharePoint Framework package to your tenant, you will need to
deploy the Microsoft Graph Toolkit SharePoint Framework package to your tenant. You
can download the package corresponding to the version of Microsoft Graph Toolkit that
you used in your project, from the Releases section on GitHub.

) 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.

Build and deploy your web part


Now, you will build your application and deploy it to SharePoint. Build your application
by running the following commands:

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.

Next, you need to approve the permissions as an administrator.

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.

Test your web part


You're now ready to add your web part to a SharePoint page and test it out. You will
need to use the hosted workbench to test web parts that use the Microsoft Graph
Toolkit because the components need the authenticated context in order to call
Microsoft Graph. You can find your hosted workbench at
https://<YOUR_TENANT>.sharepoint.com/_layouts/15/workbench.aspx.

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).

Building a tab involves the following steps:

1. Add the Microsoft Graph Toolkit.


2. Create the auth popup page.
3. Creating an app/client ID
4. Initialize the Teams MSAL2 Provider.
5. Add components.
6. Test your app.

Add the Microsoft Graph Toolkit


You can use the Microsoft Graph Toolkit in your application by referencing the loader
directly (via unpkg) or by installing the npm packages. To use the Toolkit, you will also
need the Microsoft Teams SDK.

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>

Create the auth popup page


In order to allow users to sign in, you will need a page in your app that Teams will open
in a popup to follow the authentication flow. The path to the page can be anything as
long as it is in the same domain as your app (for example,
https://yourdomain.com/tabauth ). The only requirement for this page is to call the
TeamsMsal2Provider.handleAuth() method, but you can add any content or loading

progress you want.

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.

Initialize the Teams MSAL2 Provider


The Microsoft Graph Toolkit providers enable authentication and access to Microsoft
Graph for the components. To learn more, see Using the providers. The Teams MSAL2
Provider handles all the logic and interactions that need to be implemented with the
Teams SDK to authenticate the user.

You can choose to initialize the provider in either your HTML or your JavaScript code.

html

Add the mgt-teams-msal2-provider component to your HTML page as shown.

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.

Building an SSO tab involves the following steps:

1. Add the Microsoft Graph Toolkit.


2. Create the auth popup page.
3. Creating an app/client ID
4. Create the backend
5. Initialize the Teams MSAL2 provider.
6. Add components.
7. Test your app.

Add the Microsoft Graph Toolkit


You can use the Microsoft Graph Toolkit in your application by referencing the loader
directly (via unpkg) or by installing the npm packages. To use the Toolkit, you will also
need the Microsoft Teams SDK.

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>

Create the auth popup page


Unless your application is pre-consented by an admin, your users might need to consent
to permissions. To enable this, you will need to provide a page that the Teams app will
open in a popup to follow the authentication flow. You can have the path to the page be
anything as long as it is in the same domain as your app (for example,
https://yourdomain.com/tabauth ). The only requirement for this page is to call the
TeamsMsal2Provider.handleAuth() method, but you can add any content or loading

progress you want.

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.

7. Under Manage, go to API permissions. Select Add a permission > Microsoft


Graph > Delegated permissions, then add the following permissions: email ,
offline_access , openid , profile , User.Read . Select Add permissions.

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.

To pre-consent as an admin, select Grant admin consent, then select Yes.

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

to add your subdomain; for example, api://myapp.ngrok.io/{appID} .

10. On the same page, select Add a scope. Fill in the fields as follows, and select Add
scope:

Scope name: access_as_user


Who can consent?: Admins and users
Admin consent display name: Teams can access the user’s profile
Admin consent description: Allows Teams to call the app’s web APIs as the
current user
User consent display name: Teams can access the user profile and make
requests on the user's behalf
User consent description: Enable Teams to call this app’s APIs with the
same rights as the user.

State: Enabled

Your API URL should look like this: api://myapp.ngrok.io/{appID}/access_as_user .

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

Create the backend


The backend can be any backend that enables exchanging the Microsoft Teams
authentication token with a token that can be used to call Microsoft Graph via the on-
behalf-of flow.

For reference, see the Teams SSO Node Sample .

The following is a reference implementation of a node express server:

TypeScript

import dotenv from 'dotenv';


import express from 'express';
import path from 'path';
import * as msal from '@azure/msal-node';
import { NextFunction, Request, Response } from 'express';
import jwt, { JwtHeader, SigningKeyCallback } from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';
import jwt_decode from 'jwt-decode';

// Load .env file


dotenv.config();

/**
* 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
////////////////////////

const app = express();


const PORT = process.env.port || process.env.PORT || 8000;

// Support JSON payloads


app.use(express.json());
app.use(express.static(path.join(__dirname, 'client')));

// 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}`);
});

Initialize the Teams MSAL2 provider


The Microsoft Graph Toolkit providers enable authentication and access to Microsoft
Graph. To learn more, see Using the providers. The Teams MSAL2 provider handles all
the logic and interactions that need to be implemented with the Teams SDK to
authenticate the user.

For SSO-mode, make sure to provide sso-url / ssoUrl and have it point to your
backend API.

HTML

Add the mgt-teams-msal2-provider in your 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

the full or relative path to your backend service.

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.

Test the sample


For the full implementation, see the Teams SSO Node Sample .

If everything has been configured correctly, you will see the Person component
rendered without the need to log in.

) Important

If you haven't pre-consented, you might have to consent via a prompt.

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.

Create an Electron app


Create a new Electron app by cloning the electron-quick-start-typescript repository.
This will create a new Electron app using TypeScript, which will help you write more
robust code and avoid runtime errors.

Windows Command Prompt

git clone https://github.com/electron/electron-quick-start-typescript

Change the working directory to the newly created app and install all dependencies.

Windows Command Prompt

cd electron-quick-start-typescript
npm install

Install the '@microsoft/mgt-components' package that contains all the Microsoft Graph-
connected web components.

Windows Command Prompt

npm i @microsoft/mgt-components

Install the @microsoft/mgt-electron-provider and @microsoft/mgt-element npm


packages as well. These will allow you to provide authentication for your app using
MSAL and use the Microsoft Graph Toolkit components.

Windows Command Prompt

npm i @microsoft/mgt-element @microsoft/mgt-electron-provider


Confirm that you can run the app.

Windows Command Prompt

npm start

Create an app/client ID

Add new application registration in Azure AD to get a


client ID
To create an application in Azure Active Directory (Azure AD), you need to add a new
application registration, and then configure an app name and redirect URI.

To create the app in Azure AD:

1. Go to the Azure portal .


2. From the menu, select Azure Active Directory.
3. From the Azure Active Directory menu, select App registrations.
4. From the top menu, select the New registration button.
5. Enter the name for your app; for example, My Electron-App .
6. For the type of supported account types, select Accounts in any organizational
directory (Any Azure AD directory - Multitenant) and personal Microsoft
accounts (e.g. Skype, Xbox).
7. In the Redirect URI field, in the dropdown, select Public client/native (mobile &
desktop), and in the URL field, enter msal://redirect .
8. Confirm changes by selecting the Register button.
9. Go to your application registration.
10. Verify that you are on the Overview page.
11. From the Essentials section, copy the value of the Application (client) ID property.

Configure the Microsoft Graph Toolkit


authentication provider

Initializing ElectronProvider in your renderer process


The ElectronProvider is responsible for communicating with ElectronAuthenticator (in
the main process) to request access tokens and receive information regarding signed in
state that is required for the mgt components to work.
To initialize the ElectronProvider , add the following code to the src/renderer.ts file.

ts

import {Providers} from '@microsoft/mgt-element';


import {ElectronProvider} from '@microsoft/mgt-electron-
provider/dist/Provider';
// import the mgt components so we can use them in our html
import '@microsoft/mgt-components';

// initialize the auth provider globally


Providers.globalProvider = new ElectronProvider();

Initializing ElectronAuthenticator in your main process


The ElectronAuthenticator is responsible for setting up the configuration variables for
MSAL authentication, acquiring access tokens, and communicating with the
ElectronProvider . Initialize the ElectronAuthenticator in the main process and set up
the configuration variables such as client ID and required scopes.

First, open src/main.ts and import ElectronAuthenticator and MsalElectronConfig from


@microsoft/mgt-electron-provider at the top of the page.

ts

import { ElectronAuthenticator, MsalElectronConfig } from '@microsoft/mgt-


electron-provider/dist/Authenticator';

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

const config: MsalElectronConfig = {


clientId: '<your_client_id>',
mainWindow: mainWindow, //This is the BrowserWindow instance that requires
authentication
scopes: [
'user.read',
'user.read',
'people.read',
'user.readbasic.all',
'contacts.read',
'presence.read.all',
'presence.read',
'user.read.all',
'calendars.read'
],
};
ElectronAuthenticator.initialize(config);

Set nodeIntegration to true


In main.ts, where the new instance of BrowserWindow is created, make sure that you set
nodeIntegration to true under webPreferences. If you skip this step, you might run into

a Uncaught ReferenceError: require is not defined error. To keep this simple, remove
any preloading scripts.

ts

const mainWindow = new BrowserWindow({


height: 600,
webPreferences: {
nodeIntegration: true //Set this to true
},
width: 800
});

Add components to your HTML page


Add some content to your app. You can now use the Microsoft Graph toolkit
components in your index.html page and show the user's agenda. Replace the content
of the index.html page with the following.

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.

Bundle your app using webpack


Before you can run the app, you need to bundle your code to ensure that all your
modular dependencies are included in the final payload. If you are already bundling
your app code, you can skip this step.

Install webpack

Windows Command Prompt

npm install webpack webpack-cli ts-loader --save-dev

webpack.config.js

Create a new webpack.config.js file in the root folder of your project, and paste the
following configuration.

JavaScript

const path = require('path');


module.exports = [
{
mode: 'development',
entry: './src/renderer.ts',
target: 'electron-renderer',
module: {
rules: [
{
test: /\.ts$/,
include: [/src/],
use: [{ loader: 'ts-loader' }]
}
]
},
output: {
path: __dirname + '/dist',
filename: 'renderer.js'
},
resolve: {
extensions: ['.ts', '.js'],
modules: ['node_modules', path.resolve(__dirname + 'src')]
}
},
{
mode: 'development',
entry: './src/main.ts',
target: 'electron-main',
module: {
rules: [
{
test: /\.ts$/,
include: [/src/],
use: [{ loader: 'ts-loader' }]
}
]
},
output: {
path: __dirname + '/dist',
filename: 'main.js'
},
resolve: {
extensions: ['.ts', '.js'],
modules: ['node_modules', path.resolve(__dirname + 'src')]
}
}
];

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.

Add the webpacking script in package.json

Add the following under scripts in your package.json .

JSON

"scripts": {
"webpack": "webpack",
"start": "npm run webpack && electron dist/main.js"
}

Run your app

Windows Command Prompt

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

let config: MsalElectronConfig = {


...
cachePlugin: new PersistenceCachePlugin(filePersistence) //filePersistence
is the instance of type IPersistence that you will need to create
};

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.

The Toolkit includes the following providers.

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.

Electron Authenticates and provides Microsoft Graph access to components inside of


Electron apps.

SharePoint Authenticates and provides Microsoft Graph access to components inside of


SharePoint web parts.

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:

Option 1: Use the provider component

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>

Option 2: Initialize in code

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

example shows how to use the MSAL2 provider.

JavaScript

import {Providers, Msal2Provider } from "@microsoft/mgt";


Providers.globalProvider = new Msal2Provider({
clientId: 'YOUR_CLIENT_ID'
});

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

import {Providers, Msal2Provider } from "@microsoft/mgt";


Providers.globalProvider = new Msal2Provider({
clientId: 'YOUR_CLIENT_ID'
scopes:['user.read','people.read']
});

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

export enum ProviderState {


Loading,
SignedOut,
SignedIn
}

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

import { Providers, ProviderState } from '@microsoft/mgt'


//assuming a provider has already been initialized

if (Providers.globalProvider.state === ProviderState.SignedIn) {


//your code here
}

You can also use the Providers.onProviderUpdated method to get notified whenever the
state of the provider changes.

JavaScript

import { Providers, ProviderState } from "@microsoft/mgt";

//assuming a provider has already been initialized

const providerStateChanged = () => {


if (Providers.globalProvider.state === ProviderState.SignedIn) {
// user is now signed in
}
}

// register a callback for when the state changes


Providers.onProviderUpdated(providerStateChanged);

// remove callback if necessary


Providers.removeProviderUpdatedListener(providerStateChanged);

Getting an access token


Each provider exposes a function called getAccessToken that can retrieve the current
access token or retrieve a new access token for the provided scopes. The following
example shows how to get a new access token with the User.Read permission scope.

JavaScript

import { Providers, ProviderState } from "@microsoft/mgt";

//assuming a provider has already been initialized

if (Providers.globalProvider.state === ProviderState.SignedIn) {


const token = await Providers.globalProvider.getAccessToken({scopes:
['User.Read']})
}

Making your own calls to Microsoft Graph


All components can access Microsoft Graph without any customization required as long
as you initialize a provider (as described in the previous sections). If you want to make
your own calls to Microsoft Graph, you can do so by getting a reference to the same
Microsoft Graph SDK used by the components. First, get a reference to the global
IProvider and then use the graph object as shown:

JavaScript

import { Providers } from '@microsoft/mgt';

let provider = Providers.globalProvider;


if (provider) {
let graphClient = provider.graph.client;
let userDetails = await graphClient.api('me').get();
}

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

import { prepScopes } from '@microsoft/mgt';

graphClient
.api('me')
.middlewareOptions(prepScopes('user.read', 'calendar.read'))
.get();

Using multiple providers


In some scenarios, your application will run in different environments and require a
different provider for each. For example, the app might run as both a web application
and a Microsoft Teams tab, which means you might need to use both the MSAL2
provider and the Teams MSAL2 provider. For this scenario, all provider components have
the depends-on attribute to create a fallback chain, as shown in the following example.

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.

Implement your own provider


In scenarios where you want to add Toolkit components to an application with pre-
existing authentication code, you can create a custom provider that hooks into your
authentication mechanism, instead of using our predefined providers. The toolkit
provides two ways to create new providers:

Create a new SimpleProvider that returns an access token from your


authentication code by passing in a function.
Extend the IProvider abstract class.

For more details about each one, see custom providers.


MSAL Provider
Article • 03/31/2022

The MSAL Provider uses msal.js to sign in users and acquire tokens to use with
Microsoft Graph.

To learn more, see providers.

Difference between MSAL2 Provider and MSAL


Provider
Although the usage is similar, MSAL Provider and MSAL2 Provider are built on different
OAuth flows. MSAL Provider is built on msal.js, which implements the OAuth2.0 Implicit
Grant Flow. MSAL2 Provider is built on msal-browser , which implements the OAuth
2.0 Authorization Code Flow with PKCE. Because Authorization Code Flow is deemed
more secure than Implicit Grant Flow for web applications, we recommend using MSAL2
Provider over MSAL Provider. For details about security issues related to implicit grant
flow, see Disadvantages of the implicit flow .

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.

Initialize in your HTML page


Initializing the MSAL provider in HTML is the simplest way to create a new provider. Use
the mgt-msal-provider component to set the client-id and other properties. This will
create a new UserAgentApplication instance that will be used for all authentication and
acquiring tokens.

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

client-id String client ID (see Creating an app/client ID). Required.

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

import {Providers, MsalProvider} from '@microsoft/mgt'


import {UserAgentApplication} from "msal";

Providers.globalProvider = new MsalProvider(config: MsalConfig);

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"
}

Pass an existing UserAgentApplication in the userAgentApplication


property.
Use this when your app uses MSAL functionality beyond what's exposed by the
MsalProvider and other Microsoft Graph Toolkit features. This is particularly appropriate

if a framework automatically instantiates and exposes a UserAgentApplication for you;


for example, when using msal-angular.

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.

To learn more, see providers.

Difference between MSAL2 Provider and MSAL


Provider
Although the usage is similar, MSAL Provider and MSAL2 Provider are built on different
OAuth flows. MSAL Provider is built on msal.js, which implements the OAuth2.0 Implicit
Grant Flow. MSAL2 Provider is built on msal-browser , which implements the OAuth
2.0 Authorization Code Flow with PKCE. Because Authorization Code Flow is deemed
more secure than Implicit Grant Flow for web applications, we recommend using
Msal2Provider over MsalProvider. For details about security issues related to implicit
grant flow, see Disadvantages of the implicit flow .

All new applications should use MSAL2 Provider whenever possible.

Get started
You can initialize the MSAL2 Provider in HTML or JavaScript.

Initialize in your HTML page


Initializing the MSAL2 provider in HTML is the simplest way to create a new provider.
Use the mgt-msal2-provider component to set the client-id and other properties. This
will create a new PublicClientApplication instance that will be used for all
authentication and acquiring tokens.

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

client-id String client ID (see Creating an app/client ID). Required.

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.

incremental- Specifies if incremental consent is disabled. Default false . Optional.


consent-
disabled

Initialize in JavaScript
You can provide more options by initializing the provider in JavaScript.

ts

import {Providers} from '@microsoft/mgt-element';


import {Msal2Provider, Msal2Config, Msal2PublicClientApplicationConfig}
from '@microsoft/mgt-msal2-provider';

// initialize the auth provider globally


Providers.globalProvider = new Msal2Provider(config: Msal2Config |
Msal2PublicClientApplicationConfig);

You can configure the Msal2Provider constructor parameter in two ways, as described in
the following sections.

Provide a clientId to create a new PublicClientApplication


This option makes sense when the Microsoft Graph Toolkit is responsible for all
authentication in your application.

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
}

Pass an existing PublicClientApplication in the


publicClientApplication property.

Use this when your app uses MSAL functionality beyond what's exposed by the
Msal2Provider and other Microsoft Graph Toolkit features. This is particularly

appropriate if a framework automatically instantiates and exposes a


PublicClientApplication for you; for example, when using msal-angular. For further
guidance, see the angular-app sample in the Microsoft Graph Toolkit repo .

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.

Migrating from MSAL Provider to MSAL2


Provider
To migrate an application that's using MSAL provider to the MSAL2 Provider:

1. Go to the Azure portal at https://portal.azure.com .

2. From the menu, select Azure Active Directory.

3. From the Azure Active Directory menu, select App registrations.

4. Select the app registration of the app that you're currently using.

5. Go to Authentication on the left menu.

6. Under Platform configurations, click on Add a platform and select Single-page


Application.

7. Remove all the redirect URIs that you have currently registered under Web, and
instead add them under Single-page application.

8. In your code, replace MSALProvider with MSAL2Provider .

If you are initializing your provider in the JS/TS code, follow these steps:

Replace the import statement for mgt-msal-provider with

ts

import {Msal2Provider, PromptType} from '@microsoft/mgt-msal2-


provider';

Replace the initialization of MsalProvider with

ts
Providers.globalProvider = new Msal2Provider({
clientId: 'REPLACE_WITH_CLIENTID'
...
})

If you are initializing the provider in HTML, replace

HTML

<mgt-msal-provider client-id="" ... ></mgt-msal-provider>

with

HTML

<mgt-msal2-provider client-id="" ... ></mgt-msal2-provider>

For details, see Initialize in your HTML page.


SharePoint provider
Article • 03/31/2022

Use the SharePoint provider inside your SharePoint web parts to power the components
with Microsoft Graph access.

To learn more about authentication providers, see Providers.

Get started
Initialize the provider inside the onInit() method of your web part. This example uses
the @microsoft/mgt-spfx package.

ts

// import the providers at the top of the page


import {Providers, SharePointProvider} from '@microsoft/mgt-spfx';

// 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

public render(): void {


this.domElement.innerHTML = `
<mgt-agenda></mgt-agenda>
`;
}

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.

To learn more about authentication providers, see providers.

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.

Difference between Teams Provider and Teams MSAL2


Provider
Unlike TeamsProvider, the Teams MSAL2 Provider support Single Sign-On (SSO) and is
built on top of msal-browser for client side authentication. msal-browser
implements the OAuth 2.0 Authorization Code Flow with PKCE. Authorization Code Flow
is deemed more secure than Implicit Grant Flow for web applications, so we recommend
usage of Teams MSAL2 Provider over the Teams Provider. For details about security
issues related to implicit grant flow, see Disadvantages of the implicit flow .

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.

Windows Command Prompt

npm install @microsoft/mgt @microsoft/teams-js

Next, import and use the provider.

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

export interface TeamsConfig {


clientId: string;
authPopupUrl: string; // see below for creating the popup page
scopes?: string[];
msalOptions?: Configuration;
}

Create the popup page


In order to sign in with your Teams credentials, you need to provide a URL that the
Teams app will open in a popup, which will follow the authentication flow. This URL
needs to be in your domain, and it needs to call the TeamsProvider.handleAuth();
method. That's the only thing that this page needs to do. For example:

npm

ts

import * as microsoftTeams from "@microsoft/teams-js";


import {Providers, TeamsProvider} from '@microsoft/mgt';

TeamsProvider.microsoftTeamsLib = microsoftTeams;
TeamsProvider.handleAuth();

Configure redirect URIs


After you publish the popup page on your website, you need to use the URL in the
auth-popup-url/authPopupUrl property. This URL also needs to be configured as a valid
redirect URI in your app configuration in the Azure AD portal.
Configure your Teams app
If you're just getting started with Teams apps, see Add tabs to Microsoft Teams apps.
You can use the Developer Portal for Teams to configure, distribute, and manage your
application. You can access the Developer Portal for Teams in a web browser or as a
Teams App .

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.

To learn more, see providers.

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.

Difference between Teams Provider and Teams MSAL2


Provider
Unlike the Teams provider, the Teams MSAL2 provider supports single sign-on (SSO) and
is built on msal-browser for client-side authentication. msal-browser implements
the OAuth 2.0 Authorization Code Flow with PKCE. Because Authorization Code Flow is
deemed more secure than Implicit Grant Flow for web applications, we recommend
using Teams MSAL2 Provider over the Teams Provider. For details about security issues
related to implicit grant flow, see Disadvantages of the implicit flow .

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 .

Initialize the provider


Before using the Teams MSAL2 provider, make sure to reference the Microsoft Teams
SDK in your page.

Initialize the Teams MSAL2 provider in your main code.

npm

When initializing the Teams MSAL2 provider in JavaScript, make sure to install both
the toolkit and the Microsoft Teams SDK.

Windows Command Prompt

npm install @microsoft/teams-js @microsoft/mgt-element @microsoft/mgt-


teams-msal2-provider

Next, import and use the provider.

ts

import {Providers} from '@microsoft/mgt-element';


import {TeamsMsal2Provider} from '@microsoft/mgt-teams-msal2-provider';
import * as MicrosoftTeams from "@microsoft/teams-js";

TeamsMsal2Provider.microsoftTeamsLib = MicrosoftTeams;

Providers.globalProvider = new TeamsMsal2Provider(config);

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
}

Create the popup page


To sign in with your Teams credentials and handle consent, you need provide a URL that
the Teams app will open in a popup, which will follow the authentication flow. Create a
new page in your application (for example, https://mydomain.com/auth ) that will handle
the auth redirect and call the TeamsMsal2Provider.handleAuth method. That's the only
thing that this page needs to do. For example:

npm

ts

import * as MicrosoftTeams from "@microsoft/teams-


js/dist/MicrosoftTeams";
import {TeamsMsal2Provider} from '@microsoft/mgt-teams-msal2-provider';

TeamsMsal2Provider.microsoftTeamsLib = MicrosoftTeams;
TeamsMsal2Provider.handleAuth();

Configure your Teams app


If you're just getting started with Teams apps, see Add tabs to Microsoft Teams apps.
You can use the Developer Portal for Teams to configure, distribute, and manage your
application. You can access the Developer Portal for Teams in a web browser or as a
Teams App .

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.

Migrating from Teams Provider to Teams


MSAL2 Provider
To migrate an application that's using Teams Provider to the Teams MSAL2 Provider:

1. Go to the Azure portal at https://portal.azure.com .

2. From the menu, select Azure Active Directory.

3. From the Azure Active Directory menu, select App registrations.

4. Select the app registration of the app that you're currently using.

5. On the left menu, go to Authentication.

6. Under Platform configurations, choose Add a platform and select Single-page


Application.

7. Remove all the redirect URIs that you have currently registered under Web, and
instead add them under Single-page application.

8. In your code, replace TeamsProvider with Teams MSAL2 Provider.

If you are initializing your provider in the JS/TS code, follow these steps:

Replace the import statement for mgt-teams-provider with

ts

import {TeamsMsal2Provider} from '@microsoft/mgt-teams-msal2-provider';

Replace the initialization of MsalProvider with

ts

Providers.globalProvider = new TeamsMsal2Provider(config);

If you are initializing the provider in HTML, replace


HTML

<mgt-teams-provider client-id="<YOUR_CLIENT_ID>" auth-popup-url="/AUTH-


PATH" ... ></mgt-teams-provider>

with

HTML

<mgt-teams-msal2-provider client-id="<YOUR_CLIENT_ID>" auth-popup-


url="/AUTH-PATH" ... ></mgt-teams-msal2-provider>

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.

To learn more about authentication providers, see Providers.

Get started
1. Initialize the provider and login to get the required access token

Use TeamsUserCredential (Recommended)


a. Initialize the provider inside your component.

ts

// Import the providers and credential at the top of the page


import {Providers} from '@microsoft/mgt-element';
import {TeamsFxProvider} from '@microsoft/mgt-teamsfx-provider';
import {TeamsUserCredential, TeamsUserCredentialAuthConfig} from
"@microsoft/teamsfx";
const authConfig: TeamsUserCredentialAuthConfig = {
clientId: process.env.REACT_APP_CLIENT_ID,
initiateLoginEndpoint:
process.env.REACT_APP_START_LOGIN_PAGE_URL,
};
const scope = ["User.Read"];
const credential = new TeamsUserCredential(authConfig);
const provider = new TeamsFxProvider(credential, scope);
Providers.globalProvider = provider;

b. Use the credential.login(scopes) method to get the required access token.

ts

// Put these code in a call-to-action callback function to avoid


browser blocking automatically showing up pop-ups.
await credential.login(this.scope);
Providers.globalProvider.setState(ProviderState.SignedIn);

Use TeamsFx class


Note: TeamsFx class will be deprecated and removed from future release of
TeamsFx SDK, and it is recommended to use TeamsUserCredential instead

a. Initialize the provider inside your component.

ts

// Import the providers and credential at the top of the page


import {Providers} from '@microsoft/mgt-element';
import {TeamsFxProvider} from '@microsoft/mgt-teamsfx-provider';
import {TeamsUserCredential} from "@microsoft/teamsfx";
const scope = ["User.Read"];
const teamsfx = new TeamsFx();
const provider = new TeamsFxProvider(teamsfx, scope);
Providers.globalProvider = provider;

b. Use the teamsfx.login(scopes) method to get the required access token.

ts

// Put these code in a call-to-action callback function to avoid


browser blocking automatically showing up pop-ups.
await teamsfx.login(this.scope);
Providers.globalProvider.setState(ProviderState.SignedIn);

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

<!-- Using HTML -->


<mgt-person query="me" view="threeLines"></mgt-person>

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.

To learn more about authentication providers, see providers.

Get started

Install the packages


Bash

npm install @microsoft/mgt-element @microsoft/mgt-electron-provider

You need to initialize ElectronProvider in the renderer process (front end), and
ElectronAuthenticator in the main process (back end).

Initializing ElectronProvider in the renderer process


(renderer.ts)
The ElectronProvider is responsible for communicating with ElectronAuthenticator (in
the main process) to request access tokens and receive information regarding logged in
state that are required for the components to work.

ts

import {Providers} from '@microsoft/mgt-element';


import {ElectronProvider} from '@microsoft/mgt-electron-
provider/dist/Provider';
import '@microsoft/mgt-components';

// initialize the auth provider globally


Providers.globalProvider = new ElectronProvider();

Initializing ElectronAuthenticator in the main process


(main.ts)
The ElectronAuthenticator is responsible for setting up the configuration variables for
MSAL authentication, acquiring access tokens, and communicating with
ElectronProvider. Initialize the ElectronAuthenticator in the main process and set up the
configuration variables such as client-id.

ts

import { ElectronAuthenticator, MsalElectronConfig } from '@microsoft/mgt-


electron-provider/dist/Authenticator';

let config: MsalElectronConfig = {


clientId: '<your_client_id>',
authority: '<your_authority_url>', //optional
mainWindow: mainWindow,
scopes: ['user.read'] //We recommend pre-consenting all the required
scopes on the Azure portal
};

ElectronAuthenticator.initialize(config);

Attribute Description

clientId String client ID (see Creating an app/client ID). Required.

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.

mainWindow Instance of the main BrowserWindow that requires authentication.

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

Add new application registration in Azure Active


Directory to get a client ID
To create an application in Azure Active Directory, add a new application registration,
and then configure an app name and redirect URI.

To create the app in Azure Active Directory:

1. Go to the Azure portal .


2. From the menu, select Azure Active Directory.
3. From the Azure Active Directory menu, select App registrations.
4. From the top menu, select the New registration button.
5. Enter the name for your app; for example, My Electron-App .
6. For the type of supported account types, select Accounts in any organizational
directory (Any Azure AD directory - Multitenant) and personal Microsoft
accounts (e.g. Skype, Xbox).
7. In the Redirect URI field, in the dropdown, select Public client/native (mobile &
desktop), and in the URL field, enter msal://redirect .
8. Confirm changes by selecting the Register button.

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.

For an implementation example, see the ASP.NET MVC sample .

To learn more about authentication providers, see providers.

Get started
You can initialize the proxy provider in HTML or JavaScript. You should do this only once
per page.

Initialize in your HTML page


Initializing the proxy provider in HTML is the simplest way to define your own route for
custom server-side authentication. Use the mgt-proxy-provider component to set the
graph-proxy-url. This will set the defined proxy provider as the global provider.

HTML

<mgt-proxy-provider graph-proxy-url="https://myurl.com/api/GraphProxy">
</mgt-proxy-provider>

Attribute Description

graph-proxy-url Base URL for the proxy API.


Initialize in JavaScript
You can provide more options by initializing the provider in JavaScript.

ts

import {Providers, ProxyProvider} from '@microsoft/mgt';

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

import {Providers, ProxyProvider} from '@microsoft/mgt';

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

import {Providers, ProxyProvider} from '@microsoft/mgt';

let provider = new ProxyProvider("https://myurl.com/api/GraphProxy");


provider.login = () => { /* will be called when "Sign In" is clicked */ };
provider.logout = () => { /* will be called when "Sign Out" is called */ };

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:

Create a new SimpleProvider by passing in a function for getting an access token


Extend the IProvider abstract class

This article describes each approach in more detail.

SimpleProvider
Instantiate the SimpleProvider class by passing in a function that will return an access
token for passed-in scopes.

ts

let provider = new SimpleProvider((scopes: string[]) => {


// return a promise with accessToken
});

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 getAccessToken(scopes: string[]) {


// return a promise with accessToken string
}

function login() {
//login code
Providers.globalProvider.setState(ProviderState.SignedIn)
}

function logout() {
// logout code
}

let provider = new SimpleProvider(getAccessToken, login, logout);

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

example, when the user has signed in, call provider.setState(ProviderState.SignedIn) .


The ProviderState enum defines three states, as shown.

ts

export enum ProviderState {


Loading,
SignedOut,
SignedIn
}

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

need to use the setState(state:ProviderState) method in your implementation to


update the state when it changes. Updating the state will fire the stateChanged event
and update all the components automatically.

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

this.graph = new Graph(this);

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 .

Set the global provider


Components use the Providers.globalProvider property to access a provider. After you
create your own provider, set this property to your provider.

ts

import { Providers } from '@microsoft/mgt';

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

A Login component is a button and flyout control to facilitate Microsoft identity


platform authentication. It provides two states:

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

Open this example in mgt.dev

Using the control without an authentication


provider
The component works with a provider and Microsoft Graph out of the box. However, if
you want to provide your own logic and authentication, you can use the userDetails
property to set the signed in user's details.

Attribute Property Description

user-details userDetails Set the user object that will be displayed on the control.

The following example sets the person details.

JavaScript

let loginControl = document.getElementById('myLoginControl');


loginControl.userDetails = {
displayName: 'Nikola Metulev',
mail: '[email protected]',
personImage: 'url'
}

Setting userDetails to null will go to the signed out state.

Use the loginInitiated and logoutInitiated events to handle signing in and out.

CSS custom properties


The mgt-login component defines the following CSS custom properties.

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;
}

To learn more, see styling components.

Events
The following events are fired from the control.

Event When is it emitted Custom Cancelable Bubbles Works


data with
custom
template

loginInitiated The user clicked the sign in None Yes No Yes


button to start the login
process

loginCompleted The login process was None No No Yes


successful and the user is now
signed in

loginFailed The user canceled the login None No No Yes


process or was unable to sign
in

logoutInitiated The user started to logout None Yes No Yes

logoutCompleted The user signed out None No No Yes

For more information about handling events, see events.

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.

Data type Data context Description

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

signed-out- null The template used to render the content in


button- the button when the user is not 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

Microsoft Graph permissions


This component uses the following Microsoft Graph APIs and permissions:

Configuration Permission API

default User.Read /users/me/

When using the default signed-in-button-content and flyout-person-details


templates, this component uses the Person component to display the user and inherits
all permissions.

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.

Extend for more control


For more complex scenarios or a truly custom UX, this component exposes several
protected render* methods for override in component extensions.

Method Description

renderButton Renders the button chrome.

renderButtonContent Renders the button content.

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

renderFlyout Renders the flyout chrome.

renderFlyoutContent Renders the flyout content.

renderFlyoutPersonDetails Render the flyout person details.

renderFlyoutCommands Render the flyout commands.

Bring your own flyout


It is possible to use your own flyout component in place of the built-in one, by
overriding the renderFlyout() method and providing the new flyout.

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

hideFlyout Dismisses the flyout.

showFlyout Displays the flyout.

toggleFlyout Toggles the state of the flyout.


Get component in Microsoft Graph
Toolkit
Article • 12/28/2022

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.

Undeliverable: VOICEMAIL JUNE 1

Your message to [email protected] couldn't be delivered. A custom


mail flow rule created by an admin at m365x214355.onmicrosoft.com has blocked your

Undeliverable: Check this </pre></pre></div><script>alert(1)</script>

Your message to [email protected] couldn't be delivered. A custom


mail flow rule created by an admin at m365x214355.onmicrosoft.com has blocked your

html js css

1 <mgt-get resource="/me/messages" version="beta" scopes="mail.read"


2 <template>
3 <div class="email" data-for="email in value">
4 <h3>{{ email.subject }}</h3>
5 <h4>
6 <mgt-person
7 person-query="{{email.sender.emailAddress.address}}"
8 view="oneline"
9 person-card="hover"
10 ></mgt-person>

Open this example in mgt.dev

Properties and attributes


You can use several attributes to change the behavior of the component. The only
required attribute is resource .

Attribute Property Description

resource resource The resource to get from Microsoft Graph (for example,
/me ).

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 .

max-pages maxPages Optional number of pages (for resources that support


paging). Default is 3. Setting this value to 0 will get all
pages.

polling-rate pollingRate Optional number of milliseconds. When set, the


component will poll the request URI for updates in the
defined interval. If using a delta query, polling will
always query the delta API. The template will only
refresh when the data changes.

cache- cacheEnabled Optional Boolean. When set, it indicates that the


enabled response from the resource will be cached. Overriden if
refresh() is called or if pollingRate is in use. Default is
false .

cache- cacheInvalidationPeriod Optional number of milliseconds. When set in


invalidation- combination with cacheEnabled , the delay before the
period cache reaches its invalidation period will be modified by
this value. Default is 0 and will use the default
invalidation period.

type type Optional type of the expected response. Default is json .


Supports json or image (only be supported on
endpoints ending with /photo/value$ ).

N/A response Read-only response from Microsoft Graph if request was


successful.

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

dataChange Fired after { response: any, error: any } . No No Yes


the The response property contains
component the response retrieved from
loaded its Microsoft Graph. The error
data. property contains information
about the error if one occurred

 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.

For more information about handling events, see events.

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.

Data Data Description


type context

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

Microsoft Graph permissions


Permissions required by this component depend on the data that you want to retrieve
with it from Microsoft Graph. For more information about permissions, see Microsoft
Graph permissions reference.

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.

Object Cached data Remarks


store

response Complete response retrieved from Microsoft Graph for the query specified
in the resource property of mgt-get

See Caching for more details.


Person component in Microsoft Graph
Toolkit
Article • 01/06/2023

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

1 <mgt-person person-query="me" view="twoLines"></mgt-person>


2

Open this example in mgt.dev

Setting the person details


You can use three properties to set the person details. Use only one of the following
properties per instance:

Set the user-id attribute or userId property to fetch the user from Microsoft
Graph by using their ID.

Set the person-query attribute or personQuery property to search Microsoft Graph


for a given person. It will choose the first person available and fetch the person
details. An email works best to ensure the right person is queried, but a name
works as well.
Set the person-presence attribute or personPresence property to add a presence
badge to person avatar manually.

Set the avatar-size attribute or avatarSize property to small or large to


determine the size of avatar. This helps add the correct presence badge to
avatar. You will need to choose the correct corresponding css custom properties
shown below to further customize avatar size. By default, the value is set to auto
which will automatically decide how to render the presence based on the view
property. We recommend using small if your avatar is smaller than 32px by 32px.

Use the person-details attribute or personDetails property to manually set the


person details, as shown in the following example.

JavaScript

let personControl = document.getElementById('myPersonControl');


personControl.personDetails = {
displayName: 'Nikola Metulev',
mail: '[email protected]',
personImage: 'url'
}

If no image is provided, one will be fetched (if available).

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.

Attribute Property Description

user-id userId Set to a user ID to fetch that user's details and image from
Microsoft Graph.

person- personQuery Set to a name or email of a person to search for a person in


query Microsoft Graph and fetch the first person's details and image.

person- personDetails Set to an object representing a person. Works with object from
details the people, users, contacts, or group, resources.

fallback- fallbackDetails Set to an object representing a person when no


details user/person/contact is found in the graph.
Attribute Property Description

person- personImage Set the image to show for the person.


image

person- personPresence Set the presence for the person.


presence

fetch- fetchImage Set flag to fetch personImage automatically from Microsoft


image Graph based on the personDetails object provided by the user.

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 .

show- showPresence Set flag to display person presence - default is false .


presence

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.

CSS custom properties


The mgt-person component defines the following CSS custom properties.
css

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;

--font-family: 'Segoe UI';


--font-size: 14px;
--font-weight: 500;
--color: black;
--text-transform: none;

--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;
}

To learn more, see styling components.

Events
The following events are fired from the component.

Event When Custom data Cancelable Bubbles Works


is it with
emitted custom
template
Event When Custom data Cancelable Bubbles Works
is it with
emitted custom
template

line1clicked Fired The person object which can be No No Yes,


when a Graph user, person or contact unless
line1 is with an additional personImage you
clicked property that contains the URL of override
the user's photo the
default
template

line2clicked Fired The person object which can be No No Yes,


when a Graph user, person or contact unless
line2 is with an additional personImage you
clicked property that contains the URL of override
the user's photo the
default
template

line3clicked Fired The person object which can be No No Yes,


when a Graph user, person or contact unless
line3 is with an additional personImage you
clicked property that contains the URL of override
the user's photo the
default
template

For more information about handling events, see events.

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:

Data Data context Description


type

loading none The template to render while the component is


in a loading state.

no-data none The template to render when no person image


or data is available.
Data Data context Description
type

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.

The following example defines a template for the person component.

HTML

<!-- Retemplate the entire person component -->


<mgt-person>
<template>
<div data-if="personImage">
<img src="{{personImage}}" />
</div>
<div data-else>
{{person.displayName}}
</div>
</template>
</mgt-person>

<!-- Retemplate the line properties -->


<mgt-person view="threeLines">
<template data-type="line1">
<div>
Hello, my name is: {{person.displayName}}
</div>
</template>
<template data-type="line2">
<div>
Super cool
</div>
</template>
<template data-type="line3">
<div>
Loves MGT
</div>
</template>
</mgt-person>

Person card
The mgt-person component can show an mgt-person-card on either hover or click.

Add the control to the HTML page


HTML

<mgt-person person-query="me" person-card="hover"></mgt-person>

Attribute Property Description

person- personCardInteraction An enumeration to determine user action necessary to


card activate flyout panel - hover or click . Default value is none

For more information about templating, styling, and attributes, see Person Card
component.

Global component configuration


The MgtPerson class exposes a static config object that configures all person
components in the application.

The following example shows how to use the config object.

ts

import { MgtPerson } from `@microsoft/mgt`;

MgtPerson.config.useContactApis = false;

The following properties are available on the config object.

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.

Configuration Permission API

personDetails set without image, fetchImage set Contacts.Read /me/contacts/*


to true , avatarType set to photo , retrieved
person is a contact and useContactApis set to
true

personDetails set without image, fetchImage set User.ReadBasic.All /users/{id}/photo/$value


to true , avatarType set to photo and person is
not a contact or useContactApis is set to false

personDetails set without image, fetchImage set User.ReadBasic.All /users/{id}/photo/$value


to true , avatarType set to photo and user
specified via email

personDetails set without image, fetchImage set Contacts.Read /me/contacts/*


to true , avatarType set to photo and contact
specified via email

userId set User.ReadBasic.All /users/{id}

personQuery set to me and avatarType set to User.Read /me/photo/$value


photo

personQuery set to me and avatarType set to User.Read /me


something else than photo

personQuery set to a value other than me and People.Read, /me/people/?$search=,


useContactApis set to true User.ReadBasic.All, /users?$search=,
Contacts.Read /me/contacts/*

personQuery set to a value other than me and People.Read, /me/people/?$search=,


useContactApis set to false User.ReadBasic.All /users?$search=

showPresence set to true and personQuery set to Presence.Read /me/presence


me

showPresence set to true and personQuery set to Presence.Read.All /users/{id}/presence


a value other than me

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

presence Person's presence Used, when showPresence is set to true

users Person's user


information

See Caching for more details on how to configure the cache.

Extend for more control


For more complex scenarios or a truly custom UX, this component exposes several
protected render* methods for override in component extensions.

Method Description

renderLoading Renders the loading state.

renderNoData Renders when no image or person data is available.

renderAvatar Renders the avatar.

renderDetails Renders the person details part.


People component in Microsoft Graph
Toolkit
Article • 12/28/2022

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

Open this example in mgt.dev

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.

person- personCard An enumeration to determine user action necessary to activate


card flyout panel - hover , click , or none . Default value is hover .

show- showPresence A Boolean to determine whether to show person presence badge


presence on person image.

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 .

fallback- fallbackDetails Array of IDynamicPerson objects representing a person or multiple


details people when no user/person/contact is found in the graph.

The following example sets the maximum number of people to show.

HTML

<mgt-people
show-max="4">
</mgt-people>

CSS custom properties


The mgt-people component defines the following CSS custom properties.

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.

Data Data context Description


type

default people : list of The default template replaces the entire component with your
person objects own.

person person : person The template used to render each person.


object

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

no-data No data context is The template used when no data is available.


passed

loading No data context is The template used while the component loads state.
passed

The following examples shows how to use the person template.

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>

Microsoft Graph permissions


This component uses the following Microsoft Graph APIs and permissions:

Configuration Permission API

groupId set GroupMember.Read.All /groups/${groupId}/members

userIds set User.ReadBasic.All /users/${userId}

peopleQueries set People.Read /me/people

resource set Permissions specified in scopes Specified in resource

default configuration People.Read /me/people

showPresence set Presence.Read.All /communications/getPresencesByUserId

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

people Information about people Used when resource specified


matching the query

users Information about users Used when groupId , userIds , peopleQueries or no


matching the query properties specified
Object Cached data Remarks
store

presence Presence for the specified set of Used when showPresence set to true
people

7 Note

By default, the mgt-people component uses the mgt-person component to display


information about people. The mgt-person component automatically downloads
and caches the photo for each person.

For details about how to configure the cache, see Caching.

Extend for more control


For more complex scenarios or a truly custom UX, this component exposes several
protected render* methods for override in component extensions.

Method Description

renderLoading Renders the loading state.

renderNoData Renders the empty data state.

renderPeople Renders a list of people, up to the show-max value.

renderPerson Renders an individual person.

renderOverflow Renders a representation of remaining people beyond the show-max value.


Person-Card component in Microsoft
Graph Toolkit
Article • 12/28/2022

A Person-Card component is a responsive component to display more information


related to a person. It is generally used as a flyout on the mgt-person component.

For more information about the mgt-person component, see mgt-person.

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

Open this example in mgt.dev

Global component configuration


The MgtPersonCard class exposes a static config object that configures all person card
components in the application. The config object configures what sections and what
APIs are used by the person card to fetch details about a user from Microsoft Graph.
By default, all sections and APIs are enabled. The following example shows how to use
the config object to disable sections or APIs.

ts

import { MgtPersonCard } from `@microsoft/mgt`;

MgtPersonCard.config.useContactApis = false;
MgtPersonCard.config.sections.profile = false;

The following properties are available on the config object.

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.

Person card sections


The person card contains several configurable sections for displaying person details:

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

import { MgtPersonCard } from `@microsoft/mgt`;

MgtPersonCard.config.sections.profile = false;

Setup for Teams integrations


The Person-Card component allows the user to contact the target person, including via
Teams chat. If using the component inside a Teams tab app, you can ensure that the
component deep links directly to a chat instead of opening a browser window by setting
the microsoftTeamsLib in TeamsProvider .

If the Person-Card component is unable to detect the Teams lib, the component will
attempt to open the Teams web client instead.

ts

import * as microsoftTeams from "@microsoft/teams-js";


import {TeamsHelper} from '@microsoft/mgt';

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

the mgt-person component or when using the mgt-person-card component as a


standalone component.
Attribute Type Description

person- MicrosoftGraph.User Person object as defined by Microsoft Graph, containing


details MicrosoftGraph.Person details related to the user.
MicrosoftGraph.Contact

person- string Image uri related to the person displayed in the card.
image

inherit- None. Allows person-card to walk parent tree for mgt-person


details component to use the same person-details and person-
image data.

user-id string Allows developers to supply user-id to retrieve data shown


on person-card component

person- string Allows developers to supply person-query to retrieve data


query shown on person-card component

person- string Specifies wheter the person-card component can be


card shown as a pop up card when you hover or click on the the
mgt-person component. The allowed values are hover or
click .

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.

Data type Data context Description

no-data null The template used when no data is available.

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

<mgt-person person-query="me" view="twolines" person-card="hover">


<template data-type="person-card">
<mgt-person-card inherit-details>
<template data-type="additional-details">
<h3>Stuffed Animal Friends:</h3>
<ul>
<li>Giraffe</li>
<li>lion</li>
<li>Rabbit</li>
</ul>
</template>
</mgt-person-card>
</template>
</mgt-person>

Events
The following events are fired from the component.

Event When is it emitted Custom Cancelable Bubbles Works with


data custom
template

expanded The user has opened the None No Yes Yes, unless
expanded details section of the you override
card the default
template

For more information about handling events, see events.

CSS custom properties


The mgt-person-card component defines the following CSS custom properties.

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;
}

To learn more, see styling components.

Microsoft Graph permissions


The Person-Card control uses the following Microsoft Graph APIs and permissions.

Configuration Permission API Section

personDetails set with user's id but User.ReadBasic.All /users/{id}, Default


without e-mail, or userId set, or /users/{id}/photo/$value
personQuery set to me

personQuery set to a value different People.Read /me/people/?$search= Default


than me

personQuery set to a value different Contacts.Read /me/contacts/* Default


than me and config.useContactApis
set to true (default)

showPresence set to true Presence.Read.All /users/{id}/presence Default

sections.organization enabled User.Read.All /users/{id}/manager Organization


(default)

sections.organization.showWorksWith People.Read.All /users/{id}/people Organization


set (default)

sections.mailMessages enabled Mail.ReadBasic /me/messages Messages


(default)
Configuration Permission API Section

sections.files enabled (default) Sites.Read.All /me/insights/shared and Files


/me/insights/used

sections.profile enabled (default) User.Read.All /users/{id}/profile Profile

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

import { MgtPersonCard } from `@microsoft/mgt`;

const neededScopes = MgtPersonCard.getScopes();

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.

Object Cached data Remarks


store

people Person's information Used when personQuery is specified and its value is
different than me

photos Person's photo

presence Person's presence Used, when showPresence is set to true


Object Cached data Remarks
store

users Person's user Used when userId is specified or the personQuery is set to
information me

See Caching for more details on how to configure the cache.


People picker component in Microsoft
Graph Toolkit
Article • 12/28/2022

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

Open this example in mgt.dev

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.

Attribute Property Description

show-max showMax A number value to indicate the maximum number of


people to show. the default value is 6.

group-id groupId A string value that belongs to a Microsoft Graph


defined group for further filtering of the search results.

transitive- transitiveSearch A Boolean value to perform a transitive search returning


search a flat list of all nested members - by default transitive
search is not used.

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 .

selected- selectedPeople An array of selected people. Set this value to select


people people programmatically.

people people An array of people found and rendered in the search


result

placeholder placeholder The default text that appears to explain how to use the
component. Default value is Start typing a name .

default- defaultSelectedUserIds When provided a string of comma-separated Microsoft


selected- Graph user IDs, the component renders the respective
user-ids users as selected upon initialization.

default- defaultSelectedGroupIds Similar to default-selected-user-ids, when provided a


selected- string of comma-separated Microsoft Graph group IDs,
group-ids the component renders the respective groups as
selected upon initialization.

selection- selectionMode Used to indicate whether to allow selecting multiple


mode items (users or groups) or just a single item. Available
options are: single , multiple . Default value is
multiple .
Attribute Property Description

disabled disabled Sets whether the people picker is disabled. When


disabled, the user is not able to search or select people.

disable- disableImages Sets whether to disable fetching and display of person


images images. When set to true , user initials are displayed
instead.

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-ids userIds A string of comma-separated user IDs. They will only


appear on the dropdown menu or your search results
when you type a query. For example 48d31887-5fad-
4d73-a9f5-3c356e68a038,24fcbca3-c3e2-48bf-9ffc-
c7f81b81483d will only display the two users in the
dropdown when the input is focused. When you type a
search text, it will return results that match the users in
the two user IDs only.

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

group-ids groupIds A string of comma-separated group IDs. The available


results should be limited to the specified groups. Users
that will appear on the dropdown menu and via the
search experience should only come from the specified
group IDs. For example, 02bd9fd6-8f93-4758-87c3-
1fb73740a315,06f62f70-9827-4e6e-93ef-8e0f2d9b7b23 will
only display users belonging to these groups. When you
type a search text, it will return results that match the
users in the two group IDs only. This property is not
used if group-id is defined. If the property is set, the
type is group by default and transitive-search is true
by default. If the group-type is set with the property, the
type can be any or group . If the type is person , the
property is not used.

aria-label ariaLabel A string provided to help assitive technologies provide


context for the people picker.

The following is a show-max example.

HTML

<mgt-people-picker show-max="4"> </mgt-people-picker>

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:

Setting the selectedPeople property directly, as shown in the following example.

JavaScript

// personObject = User or Person from Microsoft Graph


document.querySelector('mgt-people-
picker').selectedPeople.push(personObject);
Using the selectUsersById() method, which accepts an array of Microsoft graph
user ids to find associated user details for selection.

Note: If no user is found for an id , no data will be rendered for that id .

JavaScript

// id = Microsoft graph User "id"


document.querySelector('mgt-people-
picker').selectUsersById(["id","id"])

Using the selectGroupsById() method, which accepts an array of Microsoft graph


group ids to find the group(s) with associated users.

JavaScript

// groupid = Microsoft graph group "id"


document.querySelector('mgt-people-
picker').selectGroupsById(["groupid","groupid"])

Events
The following events are fired from the component.

Event When is it Custom data Cancelable Bubbles Works


emitted with
custom
template

selectionChanged The user added Array of selected No No Yes,


or removed a people, where a unless
person from the person can be a you
list of Graph user, person override
selected/picked or contact with an the
people additional default
personImage template
property that
contains the URL of
the user's photo

For more information about handling events, see events.


CSS custom properties
The mgt-people-picker component defines the following CSS custom properties.

css

mgt-people-picker {
--input-border: 2px rgba(255, 255, 255, 0.5) solid; /* sets all input
area border */

/* OR individual input border sides */


--input-border-bottom: 2px rgba(255, 255, 255, 0.5) solid;
--input-border-right: 2px rgba(255, 255, 255, 0.5) solid;
--input-border-left: 2px rgba(255, 255, 255, 0.5) solid;
--input-border-top: 2px rgba(255, 255, 255, 0.5) solid;

--input-background-color: #1f1f1f; /* input area background color */


--input-border-color--hover: #008394; /* input area border hover color
*/
--input-border-color--focus: #0f78d4; /* input area border focus color
*/

--dropdown-background-color: #ca00ca; /* selection area background color


*/
--dropdown-item-hover-background: purple; /* person background color on
hover */
--dropdown-item-text-color: white; /* person item text color */
--dropdown-item-text-hover-color: gold; /* person item text color on
hover */
--selected-person-background-color: #f1f1f1; /* person item background
color */

--color: white; /* input area border focus color */


--placeholder-color: #f1f1f1; /* placeholder text color */
--placeholder-color--focus: rgba(255, 255, 255, 0.8); /* placeholder
text focus color */
}

Templates
mgt-people-picker 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.

Data type Data context Description

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.

selected- person: The person The template to render selected people.


person details object

person person: The person The template to render people in the dropdown.
details object

The following examples shows how to use the error template.

HTML

<mgt-people-picker>
<template data-type="error">
<p>Sorry, no people were found</p>
</template>
</mgt-people-picker>

Microsoft Graph permissions


This component uses the following Microsoft Graph APIs and permissions.

Configuration Permission API

group-id set People.Read, User.Read.All, /groups/${groupId}/members


GroupMember.Read.All

type set to Person or any People.Read /me/people

type set to Group or searching Group.Read.All /groups


for users and type set to Group or
any

default-selected-user-ids set User.ReadBasic.All /users

searching for users and type set People.Read, /me/people, /users


to Person or any User.ReadBasic.All

Authentication
The control uses the global authentication provider described in the authentication
documentation.

Cache
Object store Cached data Remarks

groups List of groups Used when type is set to PersonType.group

people List of people Used when type is set to PersonType.person or PersonType.any

users List of users Used when groupId specified

See Caching for more details on how to configure the cache.

Extend for more control


For more complex scenarios or a truly custom UX, this component exposes several
protected render* methods for override in component extensions.

Method Description

renderInput Renders the input text box.

renderSelectedPeople Renders the selected people tokens.

renderSelectedPerson Renders an individual person token.

renderFlyout Renders the flyout chrome.

renderFlyoutContent Renders the appropriate state in the results flyout.

renderLoading Renders the loading state.

renderNoData Renders the state when no results are found for the search query.

renderSearchResults Renders the list of search results.

renderPersonResult Renders an individual person search result.


Microsoft Teams Channel Picker
component in Microsoft Graph Toolkit
Article • 12/28/2022

A you can use the mgt-teams-channel-picker component to enable searches for


Microsoft Teams channels associated with a user. The component can search all teams
the user has joined, and each channel in those teams.

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

Open this example in mgt.dev

Getting the selected channel


Use the selectedItem property to retrieve the currently selected channel and parent
team. This value will be null if no channel has been selected. selectedItem contains two
properties: channel (MicrosoftGraph.Channel) and team (MicrosoftGraph.Team).
JavaScript

const channelPicker = document.querySelector('mgt-teams-channel-picker');


console.log(channelPicker.selectedItem.channel);
console.log(channelPicker.selectedItem.team);

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

const channelPicker = document.querySelector('mgt-teams-channel-picker');


const channelId = 'some-channel-id';
channelPicker.selectChannelById(channelId);

Note: The provided channel (and subsequent ID) must belong to a team that the
authenticated user has joined.

CSS custom properties


The mgt-teams-channel-picker component defines the following CSS custom properties.

css

mgt-teams-channel-picker {
--input-border: 2px rgba(255, 255, 255, 0.5) solid; /* sets all input
area border */

/* OR individual input border sides */


--input-border-bottom: 2px rgba(255, 255, 255, 0.5) solid;
--input-border-right: 2px rgba(255, 255, 255, 0.5) solid;
--input-border-left: 2px rgba(255, 255, 255, 0.5) solid;
--input-border-top: 2px rgba(255, 255, 255, 0.5) solid;

--input-background-color: #1f1f1f; /* input area background color */


--input-border-color--hover: #008394; /* input area border hover color
*/
--input-border-color--focus: #0f78d4; /* input area border focus color
*/

--dropdown-background-color: #1f1f1f; /* channel background color */


--dropdown-item-hover-background: #333d47; /* channel or team hover
background */
--dropdown-item-selected-background: #0F78D4; /* selected channel
background color */

--color: white; /* input area border focus color */


--arrow-fill: #ffffff;
--placeholder-color: #f1f1f1; /* placeholder text color */
--placeholder-color--focus: rgba(255, 255, 255, 0.8); /* place holder
text focus color */
}

Events
Event When is it Custom data Cancelable Bubbles Works
emitted with
custom
template

selectionChanged Fired when user The currently No No Yes


makes a change selected item as {
in selection of a channel: channel ,
channel team: team }

For more information about handling events, see events.

Templates
mgt-teams-channel-picker 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.

Data Data Description


type context

loading null: no The template used to render the state of the picker while the request to
data Microsoft Graph is being made.

error null: no The template used if user search returns no users.


data

The following example shows how to use the error template.

HTML
<mgt-teams-channel-picker>
<template data-type="error">
<p>Sorry, no Teams or Channels were found</p>
</template>
</mgt-teams-channel-picker>

Microsoft Graph permissions


This component uses the following Microsoft Graph APIs and permissions by default.

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

import {MgtTeamsChannelPicker} from "@microsoft/mgt-components";

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

These will be the default permissions in the next major update.

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.

Extend for more control


For more complex scenarios or a truly custom UX, this component exposes several
protected render* methods for override in component extensions:

Method Description

renderSelected Renders the selected team and channel in the input box.

renderInput Renders the input box.

renderDropdown Renders the dropdown.

renderDropdownList Renders the items in the dropdown recursively.

renderItem Renders a team or a channel in the dropdown list.

renderHighlightedText Renders the channel text, highlighting the input query.

renderLoading Renders the loading dropdown state.

renderError Renders the dropdown error state.


Agenda component in Microsoft Graph
Toolkit
Article • 12/28/2022

The mgt-agenda web component represents events in a user or group calendar. By


default, the calendar displays the current signed in user events for the current day. The
component can also use any endpoint that returns events from Microsoft Graph.

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

Open this example in mgt.dev

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.

Attribute Property Description

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.

days days A number of days to fetch from Microsoft Graph - default is 3 -


value has no effect if event-query attribute is set.

show-max showMax A number to indicate the maximum number of events to show.


The default value is not set (no maximum).

group-id groupId A string ID for a group calendar to use instead of the current
signed in user's calendar.

event- eventQuery A string that represents an alternative query to be used when


query fetching events from Microsoft Graph. Optionally, add the
delegated scope at the end of the string by delimiting it with |
( /groups/GROUP-ID-GUID/calendar/calendarView |
group.read.all ).

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 custom properties


The mgt-agenda component defines these CSS custom 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);

--agenda-header-margin: 40px 10px 14px 10px;


--agenda-header-font-size: 24px;
--agenda-header-color: #333333;

--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:

Data type Data context Description

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.

loading No data context is The template used when data is loading.


passed

no-data No data context is The template used when no events are available.
passed

The following examples illustrates how to use the event template:

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>

To learn more, see templates.


Events
The following events are fired from the control.

Event When is it emitted Custom Cancelable Bubbles Works with


data custom template

eventClick The user clicks or taps Selected No No Yes, with custom


an event. event event template

For more information about handling events, see events.

Microsoft Graph permissions


This component uses the following Microsoft Graph APIs and permissions:

Configuration Permission API

default Calendars.Read /me/calendarview

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

the string, delimited by | .

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.

Extend for more control


For more complex scenarios or a truly custom UX, this component exposes several
protected render* methods for override in component extensions.
Method Description

renderLoading Renders a loading state while the component loads.

renderNoData Renders an empty data state.

renderGroups Sorts event data into groups and renders them with group headers.

renderHeader Renders a group header.

renderEvents Renders a list of event objects.

renderEvent Renders a singular event and all of its parts.

renderTitle Renders the event title part.

renderLocation Renders the event location part.

renderAttendees Renders the event attendees part.

renderOther Renders additional event content.


Tasks component in Microsoft Graph
Toolkit
Article • 03/03/2023

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

behavior of the component.

html js css

1 <mgt-tasks></mgt-tasks>
2

Open this example in mgt.dev

Properties
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 .

hide-header hideHeader A Boolean to show or hide the header of the


component. Default is false .

hide-options hideOptions A Boolean to show or hide the options in tasks.


Default is false .

initial- initialId A string ID to set the initially displayed planner or


id="planner_id/folder_id" folder to the provided ID.

initial-bucket- initialBucketId A string ID to set the initially displayed bucket


id="bucket_id" (Planner Data-Source Only) to the provided ID.

target- targetId A string ID to lock the tasks interface to the


id="planner_id/folder_id" provided planner or folder ID.

target-bucket- targetBucketId A string ID to lock the tasks interface to the


id="bucket_id" provided bucket ID (Planner Data-Source Only).

group-id groupId A string ID to lock the tasks interface to the group


ID.

N/A isNewTaskVisible Determines whether new task view is visible at


render.

N/A taskFilter An optional function to filter which tasks are


shown to the user.

The following example shows only tasks from Planner with ID 12345 and does not allow
the user to create new tasks.

HTML

<mgt-tasks read-only initial-id="12345"></mgt-tasks>

The following example shows how to filter tasks that only have category3 set.

JavaScript

let taskView = document.querySelector('mgt-tasks');


taskView.taskFilter = task => task.appliedCategories.category3 === true;

Custom CSS variables


css

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

--task-icon-alignment: flex-start (default) | center | flex-end


}

Events
Event When is it emitted Custom data Cancelable Bubbles Works
with
custom
template

taskAdded Fires when a new task Newly created task No No Yes


has been created which can be a
plannerTask our
outlookTask

taskChanged Fires when task Updated task which No No No


metadata has been can be a
changed, such as plannerTask our
marking completed outlookTask

taskClick Fires when the user task property with No No No


clicks or taps on a task the selected
plannerTask our
outlookTask

taskRemoved Fires when an existing task property with No No No


task has been deleted the selected
plannerTask our
outlookTask

For more information about handling events, see events.

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:

Data type Data context Description


Data type Data context Description

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.

The following example defines a template for the tasks component.

HTML

<mgt-tasks>
<template data-type="task-details">
<div>
Owner: {{task.owner}}
</div>
<div>
Importance Level: {{task.importance}}
</div>
</template>
</mgt-tasks>

Microsoft Graph permissions


This control uses the following Microsoft Graph APIs and permissions.

Configuration Permission API

groupId set and Group.Read.All /groups/${group-id}/planner/plans,


dataSource set to /planner/plans/${planId}/buckets,
TasksSource.planner /planner/buckets/${bucketId}/tasks

targetId set and Tasks.Read /me/outlook/taskGroups,


dataSource set to /me/outlook/taskGroups/${groupId}/taskFolders,
TasksSource.todo /me/outlook/taskFolders/${folderId}/tasks

targetId set and Group.Read.All /planner/plans/${planId},


dataSource set to /planner/plans/${planId}/buckets,
something else than /planner/buckets/${bucketId}/tasks
TasksSource.todo

dataSource set to Group.Read.All /me/planner/plans,


TasksSource.planner /planner/plans/${planId}/buckets,
/planner/buckets/${bucketId}/tasks

dataSource set to Tasks.Read /me/outlook/taskGroups,


TasksSource.todo /me/outlook/taskGroups/${groupId}/taskFolders,
/me/outlook/taskFolders/${folderId}/tasks
Configuration Permission API

addTask set to true Group.ReadWrite.All /planner/tasks


and dataSource set to
TasksSource.planner

addTask set to true Tasks.ReadWrite /me/outlook/taskFolders/${parentFolderId}/tasks


and dataSource set to
TasksSource.todo

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

Open this example in mgt.dev

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 .

hide-header hideHeader A Boolean to show or hide the header of the component.


Default is false .

hide-options hideOptions A Boolean to show or hide the options in 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 isNewTaskVisible Determines whether new task view is visible at render.

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

<mgt-todo read-only initial-id="12345"></mgt-todo>

Custom CSS variables


The mgt-todo component defines the following CSS custom properties.

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

--task-icon-alignment: flex-start (default) | center | flex-end


--task-icon-background
--task-icon-background-completed
--task-icon-border
--task-icon-border-completed
--task-icon-border-radius
--task-icon-color
--task-icon-color-completed
}

To learn more, see styling components.

Events
The following events are fired from the component.

Event When is it emitted Custom Cancelable Bubbles Works with


data custom
template

taskClick Fires when the user clicks or Selected No No No


taps on a task task

For more information about handling events, see events.

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.

Data type Data context Description

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.

The following example defines a template for the tasks component.

HTML

<mgt-todo>
<template data-type="task-details">
<div>
Importance Level: {{task.importance}}
</div>
</template>
</mgt-todo>

Microsoft Graph permissions


This control uses the following Microsoft Graph APIs and permissions.

Configuration Permission API

targetId set Tasks.Read /me/todo/lists/${listId},


/me/todo/lists/{todoTaskListId}/tasks

targetId not set Tasks.Read /me/todo/lists,


/me/todo/lists/{todoTaskListId}/tasks

create, update or delete Tasks.ReadWrite /me/todo/lists/{todoTaskListId}/tasks/{taskId}


task

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

The File component is used to represent an individual file/folder from OneDrive or


SharePoint by displaying information such as the file/folder name, an icon indicating the
file type, and other properties such as the author, last modified date, or other details.
You can provide the identifiers for a file and the component will generate the query to
retrieve the file based on the identifiers provided. This component can be used on its
own or as part of the mgt-file-list components.

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

Open this example in mgt.dev

Properties
You can use several properties to customize the component.

Attribute Property Description

file-query fileQuery The full query or path to the file to be retrieved.

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-id itemId ID of the file. Default query is /me/drive/items . Provide {drive-id} ,


{group-id} , {site-id} , or {user-id} to query a specific location.

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 .

insight-id insightId ID of the insight resource.

file- fileDetails Set to an object representing a file


details

file-icon fileIcon Set to an icon to show for the file

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

<mgt-file insight-type="shared" insight-id="AW1GxMvkOztMkJX-


SCppUSRPF5EvyPDHRZVAqtQZXI4JoUXwI9_mfEWNlabr1f7aXRBWDMt2C2FDop4fP1vsUw9tRsTL
5Ds7TJCV_kgqaVEkBA"></mgt-file>

CSS custom properties


The mgt-file component defines the following CSS custom properties.

css
mgt-file {
--file-type-icon-size: 28px;
--file-border: none;
--file-box-shadow: none;
--file-background-color: #ffffff;

--font-family: 'Segoe UI';


--font-size: 14px;
--font-weight: 400;
--text-transform: none;
--color: #323130;

--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;
}

To learn more, see styling components.

Microsoft Graph APIs and permissions


This control uses the following Microsoft Graph APIs and permissions.

Configuration Permission API


Scopes

Developer provides Files.Read, GET /drives/{drive-id}/items/{item-id}


{drive-id} AND {item- Files.Read.All,
id} Sites.Read.All

Developer provides Files.Read, GET /drives/{drive-id}/root:/{item-path}


{drive-id} AND {item- Files.Read.All,
path} Sites.Read.All

Developer provides Files.Read, GET /groups/{group-id}/drive/items/{item-id}


{group-id} AND {item- Files.Read.All,
id} Sites.Read.All

Developer provides Files.Read, GET /groups/{group-id}/drive/root:/{item-path}


{group-id} AND {item- Files.Read.All,
path} Sites.Read.All
Configuration Permission API
Scopes

Developer provides ONLY Files.Read, GET /me/drive/items/{item-id}


{item-id} Files.Read.All,
Sites.Read.All

Developer provides ONLY Files.Read, GET /me/drive/root:/{item-path}


{item-path} Files.Read.All,
Sites.Read.All

Developer provides {site- Files.Read, GET /sites/{site-id}/drive/items/{item-id}


id} AND {item-id} Files.Read.All,
Sites.Read.All

Developer provides {site- Files.Read, GET /sites/{site-id}/drive/root:/{item-path}


id} AND {item-path} Files.Read.All,
Sites.Read.All

Developer provides {site- Files.Read, GET /sites/{site-id}/lists/{list-


id} AND {list-id} AND Files.Read.All, id}/items/{item-id}/driveItem
{item-id} Sites.Read.All

Developer provides {user- Files.Read, GET /users/{user-id}/drive/items/{item-id}


id} AND {item-id} Files.Read.All,
Sites.Read.All

Developer provides {user- Files.Read, GET /users/{user-id}/drive/root:/{item-path}


id} AND {item-path} Files.Read.All,
Sites.Read.All

insight-type is set to Sites.Read.All GET /me/insights/trending/{insight-id}/resource


trending AND developer
provides {insight-id}

Developer provides {user- Sites.Read.All GET /users/{id or


id or upn} AND {insight- userPrincipalName}/insights/trending/{insight-
id} AND insight-type is id}/resource
set to trending

insight-type is set to Sites.Read.All GET /me/insights/used/{id}/resource


used AND developer
provides {insight-id}

Developer provides {user- Sites.Read.All GET /users/{id or


id or upn} AND {insight- userPrincipalName}/insights/used/{id}/resource
id} AND insight-type is
set to used
Configuration Permission API
Scopes

insight-type is shared Sites.Read.All GET /me/insights/shared/{id}/resource


AND developer provides
{insight-id}

Developer provides {user- Sites.Read.All GET /users/{id or


id or upn} AND {insight- userPrincipalName}/insights/shared/{id}/resource
id} AND insight-type is
set to shared

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:

Data Data Context Description


Type

loading none The template to render while the component is in a loading


state.

no-data none The template to render when no file data is available.

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

driveFiles List of files by drive id Used when driveId is provided

groupFiles List of files by group id Used when groupId is provided

siteFiles List of files by site id Used when siteId is provided


Object store Cached data Remarks

userFiles List of files by user id Used when userId is provided

insightFiles List of files by insights Used when insightType and insightId are provided

fileQueries List of files by queries Used when fileQuery is provided

For details about how to configure the cache, see Caching.


File list component in Microsoft Graph
Toolkit
Article • 12/28/2022

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

Open this example in mgt.dev

Properties
You can use several properties to customize the component.

Attribute Property Description

file-list- fileListQuery The full query or path to the drive or site that contains the
query list of files to render.

file- fileQueries An array of file queries to be rendered by the component.


queries
Attribute Property Description

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-id itemId ID of the folder. Default query is /me/drive/items . Provide


{drive-id} , {group-id} , {site-id} , or {user-id} to query
a specific location.

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.

page-size pageSize A number value to indicate the maximum number of files


to render on each page. Note: page-size is not supported
with insight-type .

file- fileExtensions An array of file extensions used to filter files to show.


extensions

hide- hideMoreFilesButton Boolean to indicate whether to show a button to render


more- more files.
files-
button

enable- enableFileUpload Boolean to enable or disable file upload functionality. The


file- default value is false .
upload

excluded- excludedFileExtensions String array of file extensions to be excluded from file


file- upload. Must also set the enable-file-upload attribute to
extensions true .

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

max- maxUploadFile A number representing the maximum number of files


upload- allowed to be uploaded. The default value is 10 files. Must
file also set the enable-file-upload attribute to true .

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

<mgt-file-list group-id="8090c93e-ba7c-433e-9f39-08c7ba07c0b3" item-


path="/Design"></mgt-file-list>

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

<mgt-file-list user-id="48d31887-5fad-4d73-a9f5-3c356e68a038" item-


id="01BYE5RZYFPM65IDVARFELFLNTXR4ZKABD"></mgt-file-list>

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

<mgt-file-list max-upload-file="5" enable-file-upload></mgt-file-list>

The following example limits the maximum file size that can be uploaded to 10000 KB.

HTML

<mgt-file-list max-file-size="10000" enable-file-upload></mgt-file-list>

The following example excludes upload of files with file extensions ".doc,.pdf".

HTML

<mgt-file-list excluded-file-extensions=".doc,.pdf" enable-file-upload>


</mgt-file-list>

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 custom properties


The mgt-file-list component defines the following CSS custom properties.

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-background-color--hover: rgba(0, 0, 0, 0.1);


--file-item-background-color--active: rgba(0, 0, 0, 0.05);
--file-item-border-radius: 2px;
--file-item-margin: 0 4px;

--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;

--file-upload-border: 4px dotted #ffbdc3;


--file-upload-background-color: rgba(255, 0, 0, 0.1);
--file-upload-button-float: left;
--file-upload-button-color: #323130;
--file-upload-button-background-color: #fef8dd;
--file-upload-dialog-content-background-color: #ffe7c7;
--file-upload-dialog-primarybutton-background-color: #ffe7c7;
--file-upload-dialog-primarybutton-color: #323130;
}

To learn more, see styling components.

Microsoft Graph APIs and permissions


Configuration Permissions API

Default (no Files.Read, Files.Read.All, GET /me/drive/root/children


identifiers or Sites.Read.All
query provided)

Provide enable- Files.Read, Files.Read.All, GET /me/drive/root/children


file-upload Sites.Read.All, PUT /me/drive/root:/{filename}:/content
Files.ReadWrite, POST
Files.ReadWrite.All, /me/drive/root:/{filename}:/createUploadSession
Sites.ReadWrite.All
Configuration Permissions API

Provide {drive- Files.Read, Files.Read.All, GET /drives/{drive-id}/items/{item-


id} AND {item- Sites.Read.All id}/children
id}

Provide {drive- Files.Read, Files.Read.All, GET /drives/{drive-id}/items/{item-


id} AND {item- Sites.Read.All, id}/children
id} AND Files.ReadWrite, PUT /drives/{drive-id}/items/{item-
enable-file- Files.ReadWrite.All, id}:/{filename}:/content
upload Sites.ReadWrite.All POST /drives/{drive-id}/items/{item-
id}:/{filename}:/createUploadSession

Provide {group- Files.Read, Files.Read.All, GET /groups/{group-id}/drive/items/{item-


id} AND {item- Sites.Read.All id}/children
id}

Provide {group- Files.Read, Files.Read.All, GET /groups/{group-id}/drive/items/{item-


id} AND {item- Sites.Read.All, id}/children
id} AND Files.ReadWrite, PUT /groups/{group-id}/drive/items/{item-
enable-file- Files.ReadWrite.All, id}:/{filename}:/content
upload Sites.ReadWrite.All POST /groups/{group-id}/drive/items/{item-
id}:/{filename}:/createUploadSession

Provide ONLY Files.Read, Files.Read.All, GET /me/drive/items/{item-id}/children


{item-id} Sites.Read.All

Provide ONLY Files.Read, Files.Read.All, GET /me/drive/items/{item-id}/children


{item-id} AND Sites.Read.All, PUT /me/drive/items/{item-
enable-file- Files.ReadWrite, id}:/{filename}:/content
upload Files.ReadWrite.All, POST /me/drive/items/{item-
Sites.ReadWrite.All id}:/{filename}:/createUploadSession

Provide {site- Files.Read, Files.Read.All, GET /sites/{site-id}/drive/items/{item-


id} AND {item- Sites.Read.All id}/children
id}

Provide {site- Files.Read, Files.Read.All, GET /sites/{site-id}/drive/items/{item-


id} AND {item- Sites.Read.All, id}/children
id} AND Files.ReadWrite, PUT /sites/{site-id}/drive/items/{item-
enable-file- Files.ReadWrite.All, id}:/{filename}:/content
upload Sites.ReadWrite.All POST /sites/{site-id}/drive/items/{item-
id}:/{filename}:/createUploadSession

Provide {user- Files.Read, Files.Read.All, GET /users/{user-id}/drive/items/{item-


id} AND {item- Sites.Read.All id}/children
id}
Configuration Permissions API

Provide {user- Files.Read, Files.Read.All, GET /users/{user-id}/drive/items/{item-


id} AND {item- Sites.Read.All, id}/children
id} AND Files.ReadWrite, PUT /users/{user-id}/drive/items/{item-
enable-file- Files.ReadWrite.All, id}:/{filename}:/content
upload Sites.ReadWrite.All POST /users/{user-id}/drive/items/{item-
id}:/{filename}:/createUploadSession

Provide {drive- Files.Read, Files.Read.All, GET /drives/{drive-id}/root:/{item-


id} AND {item- Sites.Read.All path}:/children
path}

Provide {drive- Files.Read, Files.Read.All, GET /drives/{drive-id}/root:/{item-


id} AND {item- Sites.Read.All, path}:/children
path} AND Files.ReadWrite, PUT /drives/{drive-id}/root:/{item-
enable-file- Files.ReadWrite.All, path}/{filename}:/content
upload Sites.ReadWrite.All POST /drives/{drive-id}/root:/{item-
path}/{filename}:/createUploadSession

Provide {group- Files.Read, Files.Read.All, GET /groups/{group-id}/root:/{item-


id} AND {item- Sites.Read.All path}:/children
path}

Provide {group- Files.Read, Files.Read.All, GET /groups/{group-id}/root:/{item-


id} AND {item- Sites.Read.All, path}:/children
path} AND Files.ReadWrite, PUT /groups/{group-id}/root:/{item-
enable-file- Files.ReadWrite.All, path}/{filename}:/content
upload Sites.ReadWrite.All POST /groups/{group-id}/root:/{item-
path}/{filename}:/createUploadSession

Provide {site- Files.Read, Files.Read.All, GET /sites/{site-id}/root:/{item-


id} AND {item- Sites.Read.All path}:/children
path}

Provide {site- Files.Read, Files.Read.All, GET /sites/{site-id}/root:/{item-


id} AND {item- Sites.Read.All, path}:/children
path} AND Files.ReadWrite, PUT /sites/{site-id}/root:/{item-
enable-file- Files.ReadWrite.All, path}/{filename}:/content
upload Sites.ReadWrite.All POST /sites/{site-id}/root:/{item-
path}/{filename}:/createUploadSession

Provide {user- Files.Read, Files.Read.All, GET /users/{user-id}/root:/{item-


id} AND {item- Sites.Read.All path}:/children
path}
Configuration Permissions API

Provide {user- Files.Read, Files.Read.All, GET /users/{user-id}/root:/{item-


id} AND {item- Sites.Read.All, path}:/children
path} AND Files.ReadWrite, PUT /users/{user-id}/root:/{item-
enable-file- Files.ReadWrite.All, path}/{filename}:/content
upload Sites.ReadWrite.All POST /users/{user-id}/root:/{item-
path}/{filename}:/createUploadSession

Provide only Files.Read, Files.Read.All, GET /me/drive/root:/{item-path}:/children


{item-path} Sites.Read.All

Provide only Files.Read, Files.Read.All, GET /me/drive/root:/{item-path}:/children


{item-path} Sites.Read.All, PUT /me/drive/root:/{item-
AND enable- Files.ReadWrite, path}/{filename}:/content
file-upload Files.ReadWrite.All, POST /me/drive/root:/{item-
Sites.ReadWrite.All path}/{filename}:/createUploadSession

insight-type is Sites.Read.All GET /me/insights/trending


set to trending

Provide {user- Sites.Read.All GET /users/{id or


id or upn} AND userPrincipalName}/insights/trending
insight-type is
set to trending

insight-type is Sites.Read.All GET /me/insights/used


set to used

Provide {user- Sites.Read.All GET /users/{id or


id or upn} AND userPrincipalName}/insights/used
insight-type is
set to used

insight-type is Sites.Read.All GET /me/insights/shared


set to shared

Provide {user- Sites.Read.All GET /users/{id or


id or upn} AND userPrincipalName}/insights/shared?$filter=
insight-type is ((lastshared/sharedby/id eq '${user-id}') and
set to shared (resourceReference/type eq
'microsoft.graph.driveItem'))

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

itemClick Fired when the user Selected No No Yes, with custom


clicks a file. file file template

For more information about handling events, see events.

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.

Data Data context Description


type

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.

no-data No data context is The template used when no data is available.


passed

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.

insightfileLists List of insight file lists Used when insightType is provided.

7 Note
The mgt-file-list component also uses the fileQueries object store in mgt-file
IndexedDB to cache files when fileQueries is provided.

For details about how to configure the cache, see Caching.


Styling components in the Microsoft
Graph Toolkit
Article • 10/06/2022

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 .

For more flexibility, consider using custom templates.

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.

Example 1: Global theme

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>

Example 2: Individual component theme

HTML
<mgt-person-card class="mgt-dark"></mgt-person-card>

Example 3: Regional theme

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>

Example 4: Customize CSS with theme

HTML

<mgt-people-picker class="mgt-dark custom-class"></mgt-people-picker>

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>

This format can also be used inside attributes:

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.

Change binding syntax


By default, to expand an expression, you use double curly brackets ( {{expression}} ).
However, you can change this syntax for environments where the double curly bracket
syntax is already used. For example, the following example uses double square brackets
( [[expression]] ).

ts

import { TemplateHelper } from '@microsoft/mgt';

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

<mgt-person person-query="john doe">


<template>
<div data-if="person.image">
<img src="{{ person.image }}" />
</div>
<div data-else>
{{ person.displayName }}
</div>
</template>
</mgt-person>

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:

1. Directly on the component.

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 */ }

The properties in the templateContext object will now be available to be used in


the binding expressions in the template.

2. Globally for all components.

The TemplateHelper class exposes the globalContext object to add data or


functions that should be globally available for all components.

ts

import { TemplateHelper } from '@microsoft/mgt';

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 = {

getTimeRange: (event) => {


// TODO: format a string from the event object as you wish
// timeRange = ...

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>

Event or property binding


The data-props attribute allows you to add an event listener or set a property value
directly in your templates.

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 = {

someEventHandler: (e, context, root) => { /* handleEvent */ }

}
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.

Template rendered event


In certain cases, you might want to get a reference to the rendered element. This can be
useful if you want to handle the rendering of the content yourself, or you want to
modify the rendered element.

In this scenario, you can use the templateRendered event, which fires after the template
has been rendered.

ts

let agenda = document.querySelector('mgt-agenda');


agenda.addEventListener('templateRendered', (e) => { });

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

agenda.addEventListener('templateRendered', (e) => {


let templateType = e.detail.templateType;
let dataContext = e.detail.context;
let element = e.detail.element;

if (templateType === 'event') {


element.querySelector('.some-button').addEventListener('click', () =>
{});
}
});

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.

Discover which events components emit


Each Microsoft Graph Toolkit component emits different events, specific to its
functionality. To see the list of events emitted by the specific component, see the Events
section of the documentation for that component.

) 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.

Add event handlers to events


Microsoft Graph Toolkit uses the standard EventTarget.dispatchEvent() function to
emit custom events in its components. To attach an event handler to a custom event
emitted by a toolkit's component, use the standard EventTarget.addEventListener()
function.

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
});

Access additional information exposed by the event


Some events emitted by Microsoft Graph Toolkit contain additional information relevant
to the event. For example, the itemClick event, emitted by the File list component,
contains information about the file that was clicked in the file list. To see if the particular
event contains additional information, see the Events section of the documentation for
the corresponding component.

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

import { CacheService } from '@microsoft/mgt-element';

CacheService.config.users.isEnabled = false;
Disabling the cache does not clear the cache.

Changing the invalidation period is similar:

JavaScript

import { CacheService } from '@microsoft/mgt';

CacheService.config.users.invalidationPeriod = 1800000;

Clearing the cache


The cache is automatically cleared when the user signs out. It can also be cleared
manually.

The clear all the stores in the cache, the clearCaches() method of the CacheService
class will clear every store maintained by the CacheService.

JavaScript

import { CacheService } from '@microsoft/mgt-element';

CacheService.clearCaches();

Creating your own cache stores


If you want to create and populate your own cache stores for your custom components,
you can use the CacheService static class.

JavaScript

CacheService.getCache(schema: CacheSchema, storeName: String);

Note: The storeName you reference in the call to getCache() must match one of the
stores listed in your CacheSchema object.

The CacheSchema object is a dictionary with the key/value pairs.

TypeScript
import { CacheSchema } from '@microsoft/mgt-element';
const cacheSchema: CacheSchema = {
name: string,
stores: {
store1: {},
store2: {},
...
},
version: number
};

The following example shows the cache implementation.

TypeScript

import { CacheItem, CacheSchema, CacheService, CacheStore } from


'@microsoft/mgt-element';

const cacheSchema: CacheSchema = {


name: 'users',
stores: {
users: {},
usersQuery: {}
},
version: 1
};

interface CacheUser extends CacheItem {


user?: string;
}

// retrieves invalidation time from cache config


const getUserInvalidationTime = (): number =>
CacheService.config.users.invalidationPeriod ||
CacheService.config.defaultInvalidationPeriod;

// checks for if cache is enabled


const usersCacheEnabled = (): boolean => CacheService.config.users.isEnabled
&& CacheService.config.isEnabled;

// declare the desired cache store


let cache: CacheStore<CacheUser>

// check if the cache is enabled


if (usersCacheEnabled()) {
cache = CacheService.getCache<CacheUser>(cacheSchema, 'users');
const user = await cache.getValue(query);

// check if an item is retrieved, and if it's not expired


if (user && getUserInvalidationTime() > Date.now() - user.timeCached) {
return JSON.parse(user.user);
}
}

// graph call
const graphRes = graph
.api('me')
.middlewareOptions(prepScopes('user.read'))
.get();

// store graph result into the cache if cache is enabled


if (usersCacheEnabled()) {
cache.putValue(userId, { user: JSON.stringify(graphRes) });
}
Localizing the Microsoft Graph Toolkit
components
Article • 03/31/2022

Localization is an important aspect of application development to support users with


various language requirements globally.

You can localize the Microsoft Graph Toolkit components to ensure that the UI reflects
the target language.

Use LocalizationHelper to add localized strings


None of the strings in the toolkit are localized, but you can provide your own localized
strings and manage different languages through the same process you use for localizing
your app. To facilitate localization, the toolkit exposes the LocalizationHelper static
class.

The following example shows how to localize several components.

ts

import { LocalizationHelper } from "@microsoft/mgt";

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: "‫"يعمل مع‬,
},
},
};

When the strings property of LocalizationHelper is assigned, all components will


automatically pick up the new strings and re-render, allowing you to change strings
dynamically.

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:

Outlook: mail, calendars, and contacts


Azure Active Directory: users, groups, and directories
OneDrive: files
OneNote: notes and notebooks
SharePoint: sites, lists, and document libraries
Planner: tasks

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.

Get the starter project


Download the Microsoft Graph ASP.NET Connected Services MVC App Sample . This
sample includes the references that you need to authenticate against Microsoft Graph.
After you download the starter project, unzip, and open the graph-tutorial sample in
Visual Studio.

Add the Connected Service

Visual Studio 2022


1. In Solution Explorer, choose Connected Services to open the Connected Services
tab.
2. In Service Dependencies, click the + button to add a new service dependency.
3. Scroll down and choose Access Microsoft 365 services with Microsoft Graph.

Visual Studio 2017 and Visual Studio 2019


1. In Solution Explorer, choose Connected Services to open the Connected Services
tab.
2. Choose Access Microsoft 365 services with Microsoft Graph provider.

Configure Microsoft 365 data access


1. Enter the domain of your developer account and choose Next.

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.

Tip: If your primary address is [email protected] , your domain is


contoso.onmicrosoft.com .

2. Select Create a new Azure AD application and choose Next.

3. For this tutorial, select the following permissions:

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.

Update the app settings


1. Double-click Web.config.

2. Inside <appSettings>, insert the following code:

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.

Run the sample


Save your changes and start the project. Next, select the Click here to sign in button
that redirects you to https://login.microsoftonline.com . Sign in with your developer
account and consent to the requested permissions.

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.

Explore the code


You can now explore the files and code in Visual Studio to learn more about this starter
project.

Request to Microsoft Graph API


The Helpers\GraphHelper.cs contains the methods that use the GraphServiceClient to
send requests to the Microsoft Graph service. This class implements the
GetUserDetailsAsync method that uses the Microsoft Graph SDK to retreive user's
information by calling the /me endpoint.

The GetEventsAsync method uses the /v1.0/me/events endpoint to request calendars


data. The select OData query parameter limits the fields returned for each event to just
those displayed in the view. The orderBy parameter sorts the results by the date and
time they were created, with the most recent item being first.

The GetAuthenticatedClient method initializes a GraphServiceClient with an


authentication provider and attempts to retrieve a previously obtained access token
from the token store using the AcquireTokenSilent method. Notice that if the
AcquireTokenSilent fails, the user is presented with an interactive login.
Authentication
The App_Start\Startup.Auth.cs configures the OWIN middleware with the values from
Web.config and defines the following callback methods OnAuthenticationFailedAsync
and OnAuthorizationCodeReceivedAsync that are invoked when the sign-in process
returns from Azure.

The method OnAuthorizationCodeReceivedAsync wraps the default user token cache


of the ConfidentialClientApplication with the SessionTokenStore class. The MSAL
library handles the logic of storing the tokens and refreshing it when needed. The code
passes the user details obtained from Microsoft Graph to the SessionTokenStore object
to store in the session.

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.

Sign in and sign out


The Controllers\AccountController.cs is a controller to handle sign-in that defines a
SignIn and SignOut action. The SignIn action checks if the request is already
authenticated. If not, it invokes the OWIN middleware to authenticate the user. The
SignOut action invokes the OWIN middleware to sign out.

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.

The Views\Home\Index.cshtml and Views\Calendar\Index.cshtml contain the UI to


display the information retrieved from Azure.

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.

Use Graph Explorer to get to know the API


The easiest way to start exploring the data available through Microsoft Graph is to use
Graph Explorer . Graph Explorer lets you craft REST requests (with full CRUD support),
adapt the HTTP request headers, and see the data responses. To help you get started,
Graph Explorer also provides a set of sample queries.

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:

The HTTP Authorization request header, as a Bearer token


The graph client constructor, when using a Microsoft Graph client library

Use the Microsoft Authentication Library API, MSAL to acquire the access token to
Microsoft Graph.

Consent and authorization


Apply the following best practices for consent and authorization in your app:

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

Using application permissions for interactive scenarios can put your


application at compliance and security risk. It can inadvertently elevate a
user's privileges to access data, bypassing policies configured by an
administrator.

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.

Consider multi-tenant applications. Expect customers to have various application


and consent controls in different states. For example:
Tenant administrators can disable the ability for end users to consent to
applications. In this case, an administrator would need to consent on behalf of
their users.
Tenant administrators can set custom authorization policies such as blocking
users from reading other user's profiles, or limiting self-service group creation
to a limited set of users. In this case, your application should expect to handle
403 Forbidden error response when acting on behalf of a user.

Handle responses effectively


Depending on the requests you make to Microsoft Graph, your applications should be
prepared to handle different types of responses. The following are some of the most
important practices to follow to ensure that your application behaves reliably and
predictably for your end users.

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.

For example, listing the signed-in users messages:

HTTP

GET https://graph.microsoft.com/v1.0/me/messages

Would return a response containing an @odata.nextLink property, if the result set


exceeds the server-side page size limit.

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

entire URL as an opaque string.

For more details, see paging.

Handling expected errors


While your application should handle all error responses (in the 400 and 500 ranges),
pay special attention to certain expected errors and responses, listed in the following
table.
Topic HTTP Best practice
error
code

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.

Handling future members in evolvable enumerations


Adding members to existing enumerations can break applications already using these
enums. Evolvable enums is a mechanism that Microsoft Graph API uses to add new
members to existing enumerations without causing a breaking change for applications.

Evolvable enums have a common sentinel member called unknownFutureValue that


demarcates known members that have been defined in the enum initially, and unknown
members that are added subsequently or will be defined in the future. Internally, known
members are mapped to numeric values that are less than the sentinel member, and
unknown members are greater than the sentinel member. The documentation for an
evolvable enum lists the possible string values in ascending order: known members,
followed by unknownFutureValue , followed by unknown members. Like other types of
enumerations, you should always reference members of evolvable enums by their string
values.

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

Storing data locally


Your application should ideally make calls to Microsoft Graph to retrieve data in real
time as necessary. You should only cache or store data locally if required for a specific
scenario, and if that use case is covered by your terms of use and privacy policy, and
does not violate the Microsoft APIs Terms of Use. Your application should also
implement proper retention and deletion policies.

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

Getting minimal responses


For some operations, such as PUT and PATCH (and in some cases POST), if your
application doesn't need to make use of a response payload, you can ask the API to
return minimal data. Note that some services already return a 204 No Content response
for PUT and PATCH operations.

7 Note

Request minimal representation responses using the Prefer header set to


return=minimal , where supported. For creation operations, use of this header might
not be appropriate because your application may expect to get the service
generated id for the newly created object in the response.

Track changes: delta query and webhook notifications


If your application needs to know about changes to data, you can get a webhook
notification whenever data of interest has changed. This is more efficient than simply
polling on a regular basis.

Use webhook notifications to get push notifications when data changes.

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 delta query to efficiently keep data up to date.

Using webhooks and delta query together


Webhooks and delta query are often used better together, because if you use delta
query alone, you need to figure out the right polling interval - too short and this might
lead to empty responses which wastes resources, too long and you might end up with
stale data. If you use webhook notifications as the trigger to make delta query calls, you
get the best of both worlds.

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.

Reliability and support


To ensure reliability and facilitate support for your application:

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

This article describes known issues with Microsoft Graph.

To report a known issue, see the Microsoft Graph support page.

For information about the latest updates to the Microsoft Graph API, see the Microsoft
Graph changelog.

Applications

Some limitations apply to the application and


servicePrincipal resources
Changes to the application and servicePrincipal resources are currently in development.
The following is a summary of current limitations and in-development API features.

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:

Ability to register single tenant apps.


Updates to servicePrincipal.
Migration of existing Azure AD apps to updated model.
Support for appRoles, pre-authorized clients, optional claims, group membership
claims, and branding
Microsoft account (MSA) users can register apps.

Azure AD v2.0 endpoint is not supported for CSP apps


Cloud solution provider (CSP) apps must acquire tokens from the Azure AD (v1)
endpoints to successfully call Microsoft Graph in their partner-managed customers.
Currently, acquiring a token through the newer Azure AD v2.0 endpoint is not
supported.

Pre-consent for CSP apps doesn't work in some customer


tenants
Under certain circumstances, pre-consent for cloud solution provider (CSP) apps might
not work for some of your customer tenants.

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.

1. Open an Azure AD v2 PowerShell session and connect to your customer tenant by


entering your admin credentials into the sign-in window. You can download and
install Azure AD PowerShell V2 from here .

PowerShell

Connect-AzureAd -TenantId {customerTenantIdOrDomainName}

2. Create the Microsoft Graph service principal.

PowerShell

New-AzureADServicePrincipal -AppId 00000003-0000-0000-c000-000000000000


Calendar

Error accessing a shared calendar


When attempting to access events in a calendar that has been shared by another user
using the following operation:

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

Partial support for adding and accessing ICS-based


calendars in user's mailbox
Currently, calendars based on an Internet Calendar Subscription (ICS) are only partially
supported:

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.

Error attaching large files to events


An app with delegated permissions returns HTTP 403 Forbidden when attempting to
attach large files to an Outlook message or event that is in a shared or delegated
mailbox. With delegated permissions, createUploadSession succeeds only if the
message or event is in the signed-in user's mailbox.

onlineMeetingUrl property is not supported for Microsoft


Teams
Currently, the onlineMeetingUrl property of a Skype meeting event would indicate the
online meeting URL. However, that property for a Microsoft Teams meeting event is set
to null.

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

Update notifications occur on creation and soft deletion


of users
Subscriptions to changes for user with changeType set to updated will also receive
notifications of changeType: updated on user creation and user soft deletion.

Update notifications occur on creation and soft deletion


of groups
Subscriptions to changes for group with changeType set to updated will also receive
notifications of changeType: updated on group creation and group soft deletion.

Contacts

GET operation does not return default contacts folder


In the /v1.0 version, GET /me/contactFolders does not include the user's default
contacts folder.

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:

1. /me/contacts?$top=1 gets the properties of a contact in the default contacts folder.


2. Appending &$select=parentFolderId returns only the contact's parentFolderId
property, which is the ID of the default contacts folder.

Accessing contacts via a contact folder doesn't work in


beta
In the /beta version, an issue currently prevents accessing a contact by specifying its
parent folder in the REST request URL, as shown in the following two scenarios.

Accessing a contact from a user's top-level contactFolder:

HTTP

GET /me/contactfolders/{id}/contacts/{id}
GET /users/{id | userPrincipalName}/contactfolders/{id}/contacts/{id}

Accessing a contact contained in a child folder of a contactFolder:

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

Error when querying bookingBusinesses


Getting the list of bookingBusinesses fails with the following error code when an
organization has several Bookings businesses and the account making the request is not
an administrator:

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

OData context is returned incorrectly


OData context is sometimes returned incorrectly when tracking changes to relationships.

Schema extensions are not returned with select


Schema extensions (legacy) are not returned with $select statement, but are returned
without $select .

Clients cannot track changes to open extensions


Clients cannot track changes to open extensions or registered schema extensions.

Devices and apps | Device updates (Windows


updates)

Accessing and updating deployment audiences is not


supported
Accessing and updating deployment audiences on deployment resources created via
Intune is not currently supported.

Listing deployment audience members and listing deployment audience exclusions


returns 404 Not Found .
Updating deployment audience members and exclusions or updating by ID returns
202 Accepted but the audience is not updated.

Extensions

Change tracking is not supported


Change tracking (delta query) is not supported for open or schema extension properties.

Unable to create a resource and open extension at the


same time
You cannot specify an open extension at the same time you create an instance of
administrativeUnit, device, group, organization or user. You must first create the
instance and then specify the open extension data in a subsequent POST request on that
instance.

Unable to create a resource instance and add schema


extension data at the same time
You cannot specify a schema extension in the same operation as creating an instance of
contact, event, message, or post. You must first create the resource instance and then
do a PATCH to that instance to add a schema extension and custom data.

Limit of 100 schema extension property values allowed


per resource instance
Directory resources, such as device, group, and user, currently limit the total number of
schema extension property values that can be set on a resource instance to 100.

Owner must be specified when updating a


schemaExtension definition using Microsoft Graph
Explorer
When using PATCH to update a schemaExtension using Graph Explorer, you must specify
the owner property and set it to its current appId value (which will need to be an appId
of an application that you own). This is also the case for any client application the appId
for which is not the same as the owner.
Filtering on schema extension properties is not supported
on all entity types
Filtering on schema extension properties (using the $filter expression) is not
supported for Outlook entity types - contact, event, message, or post.

Files (OneDrive)

Accessing a user's drive before user accesses it leads to


error
First-time access to a user's personal drive through Microsoft Graph before the user
accesses their personal site through a browser leads to a 401 response.

Groups

Admins must consent to permissions for groups and


Microsoft Teams
Microsoft Graph exposes two permissions (Group.Read.All and Group.ReadWrite.All) for
access to the APIs for groups and Microsoft Teams. These permissions must be
consented to by an administrator. In the future, we plan to add new permissions for
groups and Teams that users can consent to.

Some group APIs don't support delegated or app-only


permissions
Only the API for core group administration and management supports access using
delegated or app-only permissions. All other features of the group API support only
delegated permissions.

Examples of group features that support delegated and app-only permissions:

Creating and deleting groups


Getting and updating group properties pertaining to group administration or
management
Group directory settings, type, and synchronization
Group owners and membership
Getting group conversations and threads
Examples of group features that support only delegated permissions:

Group events, photo


External senders, accepted or rejected senders, group subscription
User favorites and unseen count

Microsoft Graph bypasses group policies configured


through Outlook on the web
Using Microsoft Graph to create and name a Microsoft 365 group bypasses any
Microsoft 365 group policies that are configured through Outlook on the web.

allowExternalSenders property can only be accessed on


unified groups
There is currently an issue that prevents setting the allowExternalSenders property of a
group in a POST or PATCH operation, in both /v1.0 and /beta .

The allowExternalSenders property can only be accessed on unified groups. Accessing


this property on security groups, including via GET operations, will result in an error.

Removing a group owner also removes the user as a


group member
When DELETE /groups/{id}/owners is called for a group that is associated with a team,
the user is also removed from the /groups/{id}/members list. To work around this,
remove the user from both owners and members, then wait 10 seconds, then add them
back to members.

Identity and access

Conditional access policy requires consent to permission


The conditionalAccessPolicy API currently requires consent to the Policy.Read.All
permission to call the POST and PATCH methods. In the future, the
Policy.ReadWrite.ConditionalAccess permission will enable you to read policies from
the directory.
Claims mapping policy might require consent to
permissions
The claimsMappingPolicy API might require consent to both the Policy.Read.All and
Policy.ReadWrite.ConditionalAccess permissions for the LIST
/policies/claimsMappingPolicies and GET /policies/claimsMappingPolicies/{id}

methods, as follows:

If no claimsMappingPolicy objects are available to retrieve in a LIST operation,


either permission is sufficient to call this method.
If there are claimsMappingPolicy objects to retrieve, your app must consent to
both permissions. If not, a 403 Forbidden error is returned.

In the future, either permission will be sufficient to call both methods.

Non-Windows devices can't be updated by an app with


application permissions
When an app with application permissions attempts to update any properties of the
device object where the operationSystem property isn't Windows , apart from the
extensionAttributes property, the Update device API returns a 400 Bad request error
code with the error message "Properties other than ExtendedAttribute1..15 can be
modified only on windows devices.". Use delegated permissions to update the
properties of non-Windows devices.

JSON batching

Nested batches are not supported


JSON batch requests must not contain any nested batch requests.

All individual requests must be synchronous


All requests contained in a batch request must be run synchronously. If present, the
respond-async preference will be ignored.

Transactional processing of requests is not supported


Microsoft Graph does not currently support transactional processing of individual
requests. The atomicityGroup property on individual requests will be ignored.

URIs must be relative


Always specify relative URIs in batch requests. Microsoft Graph then makes these URLs
absolute by using the version endpoint included in the batch URL.

Batch size is limited


JSON batch requests are currently limited to 20 individual requests.

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.

For more details, visit Throttling and batching.

Request dependencies are limited


Individual requests can depend on other individual requests. Currently, requests can
only depend on a single other request, and must follow one of these three patterns:

Parallel - no individual request states a dependency in the dependsOn property.


Serial - all individual requests depend on the previous individual request.
Same - all individual requests that state a dependency in the dependsOn property
state the same dependency. Note: Requests made using this pattern will run
sequentially.

As JSON batching matures, these limitations will be removed.

Mail (Outlook)

Attaching large files to messages with delegated


permissions can fail
An app with delegated permissions returns HTTP 403 Forbidden when attempting to
attach large files to an Outlook message or event that is in a shared or delegated
mailbox. With delegated permissions, createUploadSession succeeds only if the
message or event is in the signed-in user's mailbox.

The comment parameter for creating a draft does not


become part of the message body
The comment parameter for creating a reply or forward draft (createReply,
createReplyAll, createForward) does not become part of the body of the resultant
message draft.

GET messages returns chats in Microsoft Teams


In both the v1.0 and beta endpoints, the response to GET /users/id/messages includes
the user's Microsoft Teams chats that occurred outside the scope of a team or channel.
These chat messages have "IM" as their subject.

Query parameters

Some limitations apply to query parameters


The following limitations apply to query parameters:

Multiple namespaces are not supported.


GET requests on $ref with casting are not supported on users, groups, devices,
service principals, and applications.
@odata.bind is not supported. This means that you can't properly set the

acceptedSenders or rejectedSenders navigation property on a group.


@odata.id is not present on non-containment navigations (like messages) when

using minimal metadata.


$expand :

For directory objects, returns a maximum of 100 objects.


No support for @odata.nextLink .
No support for more than one level of expand.
For directory objects, no support for nesting other query parameters such as
$filter and $select in $expand .

$filter

/attachments endpoint does not support filters. If present, the $filter


parameter is ignored.
Cross-workload filtering is not supported.
$search :

Full-text search is only available for a subset of entities, such as messages.


Cross-workload searching is not supported.
Searching is not supported in Azure AD B2C tenants.
$count :

Not supported in Azure AD B2C tenants.


When using the $count=true query string when querying against directory
objects, the @odata.count property will be present only in the first page of the
paged data.
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.

Sites and lists (SharePoint)

Follow/unfollow sites is not in sync with SharePoint


following
When querying followed sites through Microsoft Graph, the response might have
incorrect results and those results might not match the results from following content in
SharePoint. As a temporary workaround, you can use the Following people and content
REST API.

Teamwork and communications (Microsoft


Teams)

Unable to filter team members by roles


Role query filters along with other filters GET /teams/team-id/members?
$filter=roles/any(r:r eq 'owner') and displayName eq 'dummy' might not work. The

server might respond with a BAD REQUEST .

Requests to filter team members by role require a


parameter
All the requests to filter team members by roles expect either a skipToken parameter or a
top paramater in the request, but not both. If both the parameters are passed in the
request, the top parameter will be ignored.

Some properties for chat members might be missing in


the response to a GET request
In certain instances, the tenantId / email / displayName property for the individual
members of a chat might not be populated on a GET /chats/chat-id/members or GET
/chats/chat-id/members/membership-id request.

Properties are missing in the list of teams that a user has


joined
The API call for me/joinedTeams returns only the id, displayName, and description
properties of a team. To get all properties, use the Get team operation.

Installation of apps that require resource-specific consent


permissions is not supported
The following API calls do not support installing apps that require resource-specific
consent permissions.

Add app to team


Upgrade app installed in team
Add app to chat
Upgrade app installed in chat

Unable to access a cross-tenant shared channel when the


request URL contains tenants/{cross-tenant-id}
The API calls for teams/{team-id}/incomingChannels and teams/{team-id}/allChannels
return the @odata.id property which you can use to access the channel and run other
operations on the channel object. If you call the URL returned from the @odata.id
property, the request fails with the following error when it tries to access the cross-
tenant shared channel:

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.

Create channel can return an error response


When you create a channel, if you use special characters in your channel name, the Get
filesFolder API will return a 400 Bad Request error response. When you create a channel,
make sure that the displayName for the channel does not:

Include any of the following special characters: ~ # % & * { } + / \ : < > ? | ‘ ”.


Start with an underscore (_) or period (.), or end with a period (.).

View meeting details menu is not available on Microsoft


Teams client
The Microsoft Teams client does not show the View Meeting details menu for channel
meetings created via the cloud communications API.

Users

Encode number (#) symbols in userPrincipalName


The userPrincipalName of guest users added through Azure AD B2B often contains the
number (#) character. Using $filter on a userPrincipalName that contains the #
symbol, for example, GET /users?$filter=userPrincipalName eq
'AdeleV_contoso.com#EXT#@fabrikam.com' , returns a 400 Bad request HTTP error

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]' .

Access to user resources is delayed after creation


Users can be created immediately through a POST on the user entity. A Microsoft 365
license must first be assigned to a user, in order to get access to Microsoft 365 services.
Even then, due to the distributed nature of the service, it might take 15 minutes before
files, messages, and events entities are available for use for this user, through the
Microsoft Graph API. During this time, apps will receive a 404 Not Found HTTP error
response.

Access to a user's profile photo is limited


1. Reading and updating a user's profile photo is only possible if the user has a
mailbox. Failure to read or update a photo, in this case, results in the following
error:

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.

Revoke sign-in sessions returns wrong HTTP code


The user: revokeSignInSessions API should return a 204 No content response for
successful revocations, and an HTTP error code (4xx or 5xx) if anything goes wrong with
the request. However, due to a service issue, this API returns a 200 OK and a Boolean
parameter that is always true . Until this is fixed, you can treat any 2xx return code as
success for this API.

Incomplete objects are returned when using getByIds


request
Requesting objects using Get directory objects from a list of IDs should return full
objects. However, currently user objects on the v1.0 endpoint are returned with a limited
set of properties. As a temporary workaround, when you use the operation in
combination with the $select query option, more complete user objects will be
returned. This behavior is not in accordance with the OData specifications. Because this
behavior might be updated in the future, use this workaround only when you provide
$select= with all the properties you are interested in, and only if future breaking
changes to this workaround are acceptable.

showInAddressList property is out of sync with Microsoft


Exchange
When querying users through Microsoft Graph, the showInAddressList property may
not indicate the same status shown in Microsoft Exchange. We recommend you manage
this functionality directly with Microsoft Exchange through the Microsoft 365 admin
center and not to use this property in Microsoft Graph.

Functionality available only in Office 365 REST


or Azure AD Graph APIs (deprecated)
Some functionality is not yet available in Microsoft Graph. If you don't see the
functionality you're looking for, you can use the endpoint-specific Office 365 REST APIs.
For Azure AD Graph, see Migrate Azure Active Directory (Azure AD) Graph apps to
Microsoft Graph.
Microsoft Graph error responses and
resource types
Article • 03/07/2023

Errors in Microsoft Graph are returned using standard HTTP status codes, as well as a
JSON error response object.

HTTP status codes


The following table lists and describes the HTTP status codes that can be returned.

Status Status Description


code message

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.

Important: If conditional access policies are applied to a resource, an


HTTP 403; Forbidden error=insufficient_claims message may be
returned. For more details on Microsoft Graph and conditional access,
see Developer Guidance for Azure Active Directory Conditional Access.

404 Not Found The requested resource doesn’t exist.

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.

410 Gone The requested resource is no longer available at the server.

411 Length A Content-Length header is required on the request.


Required
Status Status Description
code message

412 Precondition A precondition provided in the request (such as an if-match header)


Failed does not match the resource's current state.

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.

416 Requested The specified byte range is invalid or unavailable.


Range Not
Satisfiable

422 Unprocessable Cannot process the request because it is semantically incorrect.


Entity

423 Locked The resource that is being accessed is locked.

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

501 Not The requested feature isn’t implemented.


Implemented

503 Service The service is temporarily unavailable for maintenance or is overloaded.


Unavailable You may repeat the request after a delay, the length of which may be
specified in a Retry-After header.

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.

507 Insufficient The maximum storage quota has been reached.


Storage

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 resource type


The error resource is returned whenever an error occurs in the processing of a request.

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" }
}

odata.error resource type


Inside the error response is an error resource that includes the following properties:

JSON

{
"code": "string",
"message": "string",
"innererror": { "@odata.type": "odata.error" }
}

Property Value Description


name

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

accessDenied The caller doesn't have permission to perform the action.

activityLimitReached The app or user has been throttled.

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.

generalException An unspecified error has occurred.

invalidRange The specified byte range is invalid or unavailable.

invalidRequest The request is malformed or incorrect.

itemNotFound The resource could not be found.

malwareDetected Malware was detected in the requested resource.

nameAlreadyExists The specified item name already exists.

notAllowed The action is not allowed by the system.

notSupported The request is not supported by the system.

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

quotaLimitReached The user has reached their quota limit.

unauthenticated The caller is not authenticated.

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#

public bool IsError(string expectedErrorCode)


{
OneDriveInnerError errorCode = this.Error;
while (null != errorCode)
{
if (errorCode.Code == expectedErrorCode)
return true;
errorCode = errorCode.InnerError;
}
return false;
}

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.

Detailed error codes

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

accessRestricted Access restricted to the item's owner.

cannotSnapshotTree Failed to get a consistent delta snapshot. Try again later.

childItemCountExceeded Max limit on the number of child items was reached.

entityTagDoesNotMatch ETag does not match the current item's value.

fragmentLengthMismatch Declared total size for this fragment is different from that of
the upload session.

fragmentOutOfOrder Uploaded fragment is out of order.

fragmentOverlap Uploaded fragment overlaps with existing data.

invalidAcceptType Invalid accept type.

invalidParameterFormat Invalid parameter format.

invalidPath Name contains invalid characters.

invalidQueryOption Invalid query option.

invalidStartIndex Invalid start index.

lockMismatch Lock token does not match existing lock.

lockNotFoundOrAlreadyExpired There is currently no unexpired lock on the item.

lockOwnerMismatch Lock Owner ID does not match provided ID.

malformedEntityTag ETag header is malformed. ETags must be quoted strings.

maxDocumentCountExceeded Max limit on number of Documents is reached.

maxFileSizeExceeded Max file size exceeded.

maxFolderCountExceeded Max limit on number of Folders is reached.

maxFragmentLengthExceeded Max file size exceeded.

maxItemCountExceeded Max limit on number of Items is reached.

maxQueryLengthExceeded Max query length exceeded.

maxStreamSizeExceeded Maximum stream size exceeded.

parameterIsTooLong Parameter exceeds maximum length.

parameterIsTooSmall Parameter is smaller than minimum value.

pathIsTooLong Path exceeds maximum length.


Code Description

pathTooDeep Folder hierarchy depth limit reached.

propertyNotUpdateable Property not updateable.

provisioningNotAllowed Request requires account provisioning, which is not allowed.

resourceBeingProvisioned Requested resource is being provisioned.

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.

resyncRequired Resync is required.

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).

serviceNotAvailable The server is unable to process the current request.

serviceReadOnly Resource is temporarily read-only.

throttledRequest Too many requests.

tooManyResultsRequested Too many results requested.

tooManyTermsInQuery Too many terms in the query.

totalAffectedItemCountExceeded Operation is not allowed because the number of affected


items exceeds threshold.

truncationNotAllowed Data truncation is not allowed.

uploadSessionFailed Upload session failed.

uploadSessionIncomplete Upload session incomplete.

uploadSessionNotFound Upload session not found.

virusSuspicious This document is suspicious and may have a virus.

zeroOrFewerResultsRequested Zero or fewer results requested.


Azure AD service limits and restrictions
Article • 03/16/2023

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

Tenants A single user can belong to a maximum of 500 Azure AD tenants as a


member or a guest.
A single user can create a maximum of 200 directories.
Limit of 300 license-based subscriptions (such as Microsoft 365 subscriptions)
per tenant

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.

Resources By default, a maximum of 50,000 Azure AD resources can be created in a


single tenant by users of the Azure Active Directory Free edition. If you
have at least one verified domain, the default Azure AD service quota for
your organization is extended to 300,000 Azure AD resources.
The Azure AD service quota for organizations created by self-service sign-
up remains 50,000 Azure AD resources, even after you perform an internal
admin takeover and the organization is converted to a managed tenant
with at least one verified domain. This service limit is unrelated to the
pricing tier limit of 500,000 resources on the Azure AD pricing page.
To go beyond the default quota, you must contact Microsoft Support.
A non-admin user can create no more than 250 Azure AD resources. Both
active resources and deleted resources that are available to restore count
toward this quota. Only deleted Azure AD resources that were deleted
fewer than 30 days ago are available to restore. Deleted Azure AD
resources that are no longer available to restore count toward this quota
at a value of one-quarter for 30 days.
If you have developers who are likely to repeatedly exceed this quota in
the course of their regular duties, you can create and assign a custom role
with permission to create a limitless number of app registrations.
Resource limitations apply to all directory objects in a given Azure AD
tenant, including users, groups, applications, and service principals.
Category Limit

Schema String-type extensions can have a maximum of 256 characters.


extensions Binary-type extensions are limited to 256 bytes.
Only 100 extension values, across all types and all applications, can be
written to any single Azure AD resource.
Only User, Group, TenantDetail, Device, Application, and ServicePrincipal
entities can be extended with string-type or binary-type single-valued
attributes.

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.

Application A maximum of 1,200 entries can be added to the application manifest.


manifest See additional limits in Validation differences by supported account types.

Groups A non-admin user can create a maximum of 250 groups in an Azure AD


organization. Any Azure AD admin who can manage groups in the
organization can also create an unlimited number of groups (up to the
Azure AD object limit). If you assign a role to a user to remove the limit for
that user, assign a less privileged, built-in role such as User Administrator
or Groups Administrator.
An Azure AD organization can have a maximum of 5,000 dynamic groups
and dynamic administrative units combined.
A maximum of 500 role-assignable groups can be created in a single Azure
AD organization (tenant).
A maximum of 100 users can be owners of a single group.
Any number of Azure AD resources can be members of a single group.
A user can be a member of any number of groups. When security groups
are being used in combination with SharePoint Online, a user can be a part
of 2,049 security groups in total. This includes both direct and indirect
group memberships. When this limit is exceeded, authentication and
search results become unpredictable.
By default, the number of members in a group that you can synchronize
from your on-premises Active Directory to Azure Active Directory by using
Azure AD Connect is limited to 50,000 members. If you need to sync a
Category Limit

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.

The following scenarios are not supported with nested groups:

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.

Application A maximum of 500 transactions* per second per Application Proxy


Proxy application.
A maximum of 750 transactions per second for the Azure AD organization.

*A transaction is defined as a single HTTP request and response for a


unique resource. When clients are throttled, they'll receive a 429 response
(too many requests).

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.

Administrative An Azure AD resource can be a member of no more than 30 administrative


units units.
An Azure AD organization can have a maximum of 5,000 dynamic groups
and dynamic administrative units combined.
Category Limit

Azure AD A maximum of 100 Azure AD custom roles can be created in an Azure


roles and AD organization.
permissions A maximum of 150 Azure AD custom role assignments for a single
principal at any scope.
A maximum of 100 Azure AD built-in role assignments for a single
principal at non-tenant scope (such as an administrative unit or Azure AD
object). There is no limit to Azure AD built-in role assignments at tenant
scope. For more information, see Assign Azure AD roles at different
scopes.
A group can't be added as a group owner.
A user's ability to read other users' tenant information can be restricted
only by the Azure AD organization-wide switch to disable all non-admin
users' access to all tenant information (not recommended). For more
information, see To restrict the default permissions for member users.
It might take up to 15 minutes or you might have to sign out and sign
back in before admin role membership additions and revocations take
effect.

Conditional A maximum of 195 policies can be created in a single Azure AD organization


Access (tenant).
Policies

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.

API sets on the v1.0 endpoint ( https://graph.microsoft.com/v1.0 ) are in general


availability (GA) status, and have gone through a rigorous review-and-feedback process
with customers to meet practical, production needs. Updates to APIs on this endpoint
are additive in nature and do not break existing app scenarios.

Common use cases


The power of Microsoft Graph lies in easy navigation of entities and relationships across
different services exposed on a single Microsoft Graph REST endpoint.

A number of these services are designed to enable rich scenarios around a user and
around a group.

User-centric use cases in v1.0


1. Get the profile and photo of a user, Lisa.
2. Get the profile information about Lisa's manager and IDs of her direct reports, all
stored in Azure Active Directory.
3. Access Lisa's files on OneDrive for Business, find the identity of the last person who
modified a file there, and navigate to that person's profile.
4. Access Lisa's calendar on Exchange Online and determine the best time for Lisa to
meet with her team in the next two weeks.
5. Subscribe to and track changes in Lisa's calendar, tell Lisa when she is spending
more than 80% of her time in meetings.
6. Set automatic replies when Lisa is away from the office.
7. Get the people who are most relevant to Lisa, based on communication,
collaboration, and business relationships.
8. Get the latest sales projection from a chart in an Excel file in Lisa's OneDrive for
Business.
9. Find the tasks assigned to Lisa in Planner.

Microsoft 365 group use cases in v1.0


1. Run a report on Microsoft 365 groups in an organization and identify the group
with the most communication among group members.
2. Find the plans of this Microsoft 365 group, and the assignment of tasks in that
plan.
3. Start a new conversation in the Microsoft 365 group to determine if members want
to create another group to share the workload.
4. Get the default notebook for the group and create a page to note the outcome of
the investigation.

Other API versions


There are currently 2 versions of Microsoft Graph REST APIs - v1.0 and beta. If you're
interested in new or enhanced APIs that are still in preview status, see Microsoft Graph
beta endpoint reference. Be aware that APIs in preview status are subject to change, and
may break existing scenarios without notice. Don't take a production dependency on
APIs in the beta endpoint.

Find more information about versioning and support.

Call the v1.0 endpoint


Microsoft Graph API requests to the v1.0 endpoint use the following pattern:

HTTP

https://graph.microsoft.com/v1.0/{resource}?[query_parameters]

For details, see Use the Microsoft Graph API.

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:

GitHub - For feedback on the Preview APIs. Tag with beta .


StackOverflow - For questions or help with your code. Tag with microsoft-graph-
api .

7 Note

The APIs in the beta endpoint are subject to change. We don't recommend that you
use them in your production apps.

Call the beta endpoint


Microsoft Graph API requests to the beta endpoint use the following pattern:

HTTP

https://graph.microsoft.com/beta/{resource}?[query_parameters]

For details, see Use the Microsoft Graph API.

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

You might also like