100% found this document useful (1 vote)
2K views2,700 pages

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
100% found this document useful (1 vote)
2K views2,700 pages

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

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 poli