Graph
Graph
OVERVIEW REFERENCE
What is Microsoft Graph? Microsoft Graph REST API
OVERVIEW OVERVIEW
Microsoft Graph Data Connect Microsoft Graph connectors
Users Groups
e Access and manipulate user resources directly. e Enable user collaboration and integration
across services.
Resources
Microsoft Graph is the gateway to data and intelligence in Microsoft 365. It provides a
unified programmability model that you can use to access the tremendous amount of
data in Microsoft 365, Windows, and Enterprise Mobility + Security. Use the wealth of
data in Microsoft Graph to build apps for organizations and consumers that interact
with millions of users.
Together, the Microsoft Graph API, connectors, and Data Connect power the Microsoft
365 platform. With the ability to access Microsoft Graph data and other datasets, you
can derive insights and analytics, extend Microsoft 365 experiences, and build unique,
intelligent applications.
Microsoft 365 core services: Bookings, Calendar, Delve, Excel, Microsoft 365
compliance eDiscovery, Microsoft Search, OneDrive, OneNote, Outlook/Exchange,
People (Outlook contacts), Planner, SharePoint, Teams, To Do, Viva Insights
Enterprise Mobility + Security services: Advanced Threat Analytics, Advanced
Threat Protection, Azure Active Directory, Identity Manager, and Intune
Windows services: activities, devices, notifications, Universal Print
Dynamics 365 Business Central services
To find out more, see Major services and features in Microsoft Graph.
Use Microsoft Graph to build experiences around the user's unique context to help them
be more productive. Imagine an app that...
Looks at your next meeting and helps you prepare for it by providing profile
information for attendees, including their job titles and managers, as well as
information about the latest documents they're working on, and people they're
collaborating with.
Scans your calendar, and suggests the best times for the next team meeting.
Fetches the latest sales projection chart from an Excel file in your OneDrive and lets
you update the forecast in real time, all from your phone.
Subscribes to changes in your calendar, sends you an alert when you're spending
too much time in meetings, and provides recommendations for the ones you can
miss or delegate based on how relevant the attendees are to you.
Helps you sort out personal and work information on your phone; for example, by
categorizing pictures that should go to your personal OneDrive and business
receipts that should go to your OneDrive for Business.
Analyzes at-scale Microsoft 365 data so that decision makers can unlock valuable
insights into time allocation and collaboration patterns that improve business
productivity.
Brings custom business data into Microsoft Graph, indexing it to make it
searchable along with data from Microsoft 365 services.
Pick the first scenario about researching meeting attendees as an example. With the
Microsoft Graph API, you can:
Microsoft Graph continues to open up the Microsoft 365 platform for developers, and
always only with the appropriate permissions.
7 Note
When you use the Microsoft Graph API, you agree to the Microsoft APIs Terms of
Use and the Microsoft Privacy Statement .
Operation URL
GET my https://graph.microsoft.com/v1.0/me
profile
GET my https://graph.microsoft.com/v1.0/me/photo/$value
photo
GET my https://graph.microsoft.com/v1.0/me/events
calendar
events
GET my https://graph.microsoft.com/v1.0/me/manager
manager
GET https://graph.microsoft.com/v1.0/me/memberOf/$/microsoft.graph.group?
Microsoft $filter=groupTypes/any(a:a%20eq%20'unified')
365 groups
I'm a
member of
GET my https://graph.microsoft.com/v1.0/me/onenote/notebooks
notes
Microsoft Graph connectors create connections to external data sources, index the data,
and store it as external custom items and files. Once indexed, those items can show up
in Microsoft Search and for apps that use the Microsoft Search API.
Using Azure tools, you can then build intelligent apps that:
Data Data is protected while in Data protection is extended to the cache of data in
protection Microsoft 365 your Azure subscription
Next steps
Check out some partner solutions.
Try a sample request in the Graph Explorer.
Use the quick start to set up a ready-to-run sample app.
Look under Learn in the table of contents to read about services and features that
you can use in your scenarios.
Learn about metered APIs and services in Microsoft Graph.
Find out how to get an auth token in your app.
Start using the API.
Major services and features in Microsoft
Graph
Article • 03/14/2023
Microsoft Graph enables you to integrate with the best of Microsoft 365, Windows, and
Enterprise Mobility + Security services in Microsoft 365, using REST APIs and client
libraries. Additionally, it offers security and intelligence that can boost user productivity,
creativity, and team collaboration, and protect business resources and users' data.
A user in Microsoft Graph is one among the millions who use Microsoft 365 cloud
services. It is the focal point whose identity is protected and access is well-managed. The
user's data is what drives businesses. Microsoft Graph services make this data available
to businesses in rich contexts, real-time updates, and deep insights, and always only
with the appropriate permissions.
A Microsoft 365 group is the fundamental entity that lets users collaborate. It integrates
with other services, enabling richer scenarios in task planning, teamwork, education, and
more.
Users Azure Active Directory (Azure The user is a core focus of Microsoft Overview of
AD) and most productivity, Graph, around which many Microsoft users in
collaboration, intelligence, Graph services build user-centric Microsoft
and education services functionality. Graph
Groups Azure AD, OneDrive, A Microsoft 365 group provides the Overview of
OneNote, Outlook, Planner fundamental collaborative unit for Microsoft 365
users to share conversations, files, groups in
notes, calendar, plans, and more. Microsoft
Graph
by category.
Identity and Azure AD Creates and manages directory resources such as Azure AD
access users, groups, and applications. Manages access to identity and
management resources and data. Gives customers access to sign- access
in and account risk data in Azure AD. management
overview
Productivity
Feature Supporting Description More
services information
Calendar Outlook Lets users set up appointments and meetings on the Outlook
web and on mobile and desktop devices. It is part of calendar
the Outlook messaging communication hub in overview
Microsoft 365 that also lets users manage emails and
contacts.
Files OneDrive Manages and shares user files on OneDrive and OneDrive
and SharePoint. files storage
SharePoint overview
Notes OneNote Lets users plan and organize ideas and information. OneNote
notes
overview
Personal Outlook Contacts manager on the web and on mobile and Outlook
contacts desktop devices. It is part of the Outlook messaging personal
communication hub in Microsoft 365 that also lets contacts
users manage emails and schedule meetings. overview
To-do tasks To Do Lets users manage their personal tasks across work To Do tasks
and life. It is also integrated with Outlook, Teams, overview
Planner, and Cortana, which makes it the single
destination for user's personal tasks in Microsoft 365.
Calls and Microsoft Lets apps and services interact with users through Overview for
online Teams, various communications-related features; for using
meetings Skype example, enabling bots to handle calls, integrating Microsoft
online meetings in line of business scenarios, Teams,
showing users' presence status (preview), and Shifts, and
looking up records for calls and online meetings Viva
(preview). Learning to
foster
teamwork
Shift Microsoft Lets managers and frontline workers manage staff Overview for
management Shifts scheduling or capture data from workforce using
management systems to create optimized Microsoft
schedules for a business. Teams,
Shifts, and
Viva
Learning to
foster
teamwork
Sites and SharePoint Web-based platform for users and Microsoft 365 SharePoint
lists groups to share, organize, manage, and discover sites and
content (including lists, files, and notes). content
overview
Tasks and Planner Enables users in Microsoft 365 groups to create Planner
plans plans, assign tasks, and track progress. plans and
tasks
overview
Feature Supporting Description More
services information
Teamwork Microsoft Ultimate digital hub and chat-based workspace for Overview for
platform and Teams teams to share files, notes, calendar, and plans. using
messaging Microsoft
Teams,
Shifts, and
Viva
Learning to
foster
teamwork
People Azure AD, Gets information about persons as ordered by their People and
Outlook, relevance to a user, determined by the user's workplace
SharePoint, communication and collaboration patterns and intelligence
and more business relationships. in Microsoft
Graph
Profile Profile Provides a lightweight mechanism for storing and People and
(preview) retrieving information about people within a workplace
tenant. intelligence
in Microsoft
Graph
Profile card Profile card Provides a lightweight mechanism for an People and
customization administrator to customize the content that workplace
(preview) surfaces on the Microsoft 365 profile card within intelligence
an organization. in Microsoft
Graph
Document Delve, Uses advanced analytics and machine learning People and
insights OneDrive, techniques to get documents trending around, workplace
Outlook, viewed, modified, or shared by a user. intelligence
SharePoint in Microsoft
Graph
Browser Microsoft Microsoft Edge is one of the applications Using the Edge
management Edge that administrators manage through the API in Microsoft
Microsoft 365 admin center. As an Graph to
alternative to using the Microsoft 365 admin manage
center, apps can use the Microsoft Graph API browsers
to manage the same Edge settings
configured through the Microsoft 365 admin
center.
Cloud printing Universal Universal Print is a Microsoft 365 cloud- Cloud printing
Print based print infrastructure that enables a using Universal
simple, rich, and secure print experience for Print API
users and reduces administrative and
management effort for IT.
Corp Intune Enrolls and configures devices and manages Intune devices
management of mobile applications in your organization. and apps
devices and overview
apps
Service health Microsoft Provides access to the health status and Accessing
and 365 and message center posts about Microsoft cloud service health
communications Dynamics services. A notable example that uses the and
365 services service communications API is the Microsoft communications
365 admin center. in Microsoft
Graph
Security
Feature Supporting services Description More
information
Cross-device experiences
Feature Supporting Description More
services information
Cross- Activity Enables app experiences that transcend a single Overview for
device feed, device device, and instead move with the user from device cross-device
experiences relay to device regardless of its type and platform. experiences
) Important
The Microsoft Graph notifications API is deprecated and stopped returning data in
January 2022. For an alternative notification experience, see Microsoft Azure
Notification Hubs. For more information, see this blog post .
Usage reports
Feature Supporting services Description More
information
Reports Microsoft Teams, OneDrive, Outlook, Gets activity and usage Usage
SharePoint, Skype for Business, information of a supporting reports
Yammer service. overview
Education
Feature Supporting Description More
services information
Education Azure AD, Provides information relevant for education scenarios, Education
Education including schools, classes, students, teachers, and overview
assignment info. Enables ISVs to build applications for
the classroom that save teachers time and promote
teamwork and collaboration.
Business applications
Feature Supporting Description More
services information
Next steps
Look under Learn in the table of contents to read about services and features that
you can use in your scenarios.
Try a sample request in the Graph Explorer.
Use this quick start to set up a ready-to-run sample app.
What's new in Microsoft Graph
Article • 05/23/2023
See highlights of what's new in the recent two months in Microsoft Graph, what's added
earlier, and how you can share your ideas. For a detailed list of API-level updates, see
the API changelog.
) Important
Features, including APIs and tools, in preview status may change without notice,
and some may never be promoted to generally available (GA) status. Do not use
preview features in production apps.
Search | Index
Specify settings for the search experience of content in an external connection. For
example, a display template for search results, and a rule to select the display
template.
Collect configurable settings related to activities of connector content in an
external connection. These settings set rules to resolve the URL of an external item
to its ID , thereby identifying the external item.
Add instances of external activity on an external item. You can track the type of
external activity (such as viewed, modified, created, commented), the identity of
the user, group, or external group who performed the activity, and the result of
adding the activity.
Education
Get or update from class level assignment settings any grading category to weight
assignments differently when computing a class average grade.
The number of days that an attack simulation user is out of office during an attack
simulation and training campaign.
The last activity in a user's detailed online actions in an attack simulation and
training campaign.
Search | Query
Qualify a search query string with a query template, which supports KQL and query
variables.
Education
Teachers can activate an inactive assignment to signal that the assignment has
further action items for teachers or students.
Teachers can deactivate and mark an assignment as inactive to signal that the
assignment has no further action items for teachers and students.
Search | Index
Get or set the relative ranking importance of a property in a schema, to allow Microsoft
Search to determine the search relevance of the content.
Are there scenarios you'd like Microsoft Graph to support? Suggest and vote for
new features at Microsoft Feedback Portal . Some new features originate as
popular requests from the developer community. The Microsoft Graph team
regularly evaluates customer needs and releases new features in the following
order:
1. Debut in preview status. Any related REST API updates are in the beta
endpoint ( https://graph.microsoft.com/beta ).
Sign up for the Microsoft 365 developer program, get a free Microsoft 365
subscription, and start developing!
See also
Check out the Microsoft Graph developer blog periodically for release
announcements and helpful resources.
Browse details of Microsoft Graph API additions, and API behavior updates in the
changelog.
Find highlights of earlier releases.
Learn more about versioning, support, and breaking change policies for Microsoft
Graph.
Use Graph Explorer to try Microsoft
Graph APIs
Article • 11/03/2022
Graph Explorer is a developer tool that lets you learn about Microsoft Graph APIs. Use
Graph Explorer to try the APIs on the default sample tenant to explore capabilities, or
sign in to your own tenant and use it as a prototyping tool to fulfill your app scenarios.
This tool includes helpful features such as code snippets (C#, Java, JavaScript, Go and
PowerShell), Microsoft Graph Toolkit and adaptive cards integration, and more.
Graph Explorer handles the authentication process for you. Customize the experience by
collapsing the sidebar or changing the theme.
Get started
Graph Explorer is a web application hosted on the Microsoft Graph developer center. It's
an open-source project, and we welcome your contributions and feedback on GitHub .
Make requests
With Graph Explorer, you can make requests to the Microsoft Graph APIs to retrieve,
add, delete and update data. Your requests can send parameters, authorization details,
and any body data you require.
To create the request, you can either select a sample query from the menu at the left,
which fills in the query field, or you can choose to manually type your request in the
field. Once you run the request, you will get the HTTP response code and the response
will be displayed in the response preview area.
When you sign in to Graph Explorer and run the same query, the response is returned
with real data from the tenant that you signed in to.
) Important
For example, to run a POST request, select POST in the drop-down list for the HTTP
verb, and add a request body and request headers as appropriate.
Next steps
Try Graph Explorer.
Explore the different Graph Explorer features.
Contribute or provide feedback on GitHub .
Microsoft Graph tutorials
Article • 12/10/2022
Microsoft Graph tutorials are step-by-step training exercises that guide you through
creating a basic application that accesses data via Microsoft Graph. They are designed to
be completed within 30 minutes.
If you prefer to download a completed project, you can do so from one of the following
locations:
.NET microsoftgraph/msgraph-training-dotnet-core
Go microsoftgraph/msgraph-training-go
Java microsoftgraph/msgraph-training-java
JavaScript microsoftgraph/msgraph-training-javascript
PHP microsoftgraph/msgraph-training-php
PowerShell microsoftgraph/msgraph-training-powershell
Python microsoftgraph/msgraph-training-python
TypeScript microsoftgraph/msgraph-training-typescript
App-only authentication
In the app-only authentication tutorials, you create a basic command-line application
that has the following features:
If you prefer to download a completed project, you can do so from the project's
corresponding GitHub repository. Instructions for registering an application and
configuring the sample are located in each repository.
.NET microsoftgraph/msgraph-training-dotnet-core
Go microsoftgraph/msgraph-training-go
Java microsoftgraph/msgraph-training-java
JavaScript microsoftgraph/msgraph-training-javascript
PHP microsoftgraph/msgraph-training-php
PowerShell microsoftgraph/msgraph-training-powershell
Python microsoftgraph/msgraph-training-python
TypeScript microsoftgraph/msgraph-training-typescript
Next steps
After you complete a tutorial, you can learn more on Microsoft Learn or explore our
samples.
Microsoft Learn
For a deeper dive into Microsoft Graph, explore our Microsoft Graph learning paths:
Samples
If the tutorials aren't quite what you need, our Microsoft Graph samples cover more
scenarios and platforms, such as web apps and mobile apps.
Users you can reach with Microsoft
Graph
Article • 01/27/2023
Microsoft offers services and solutions that expand modern work and modern life.
As a developer, you can use the Microsoft Graph API to build applications that connect
to the millions of users that use Microsoft 365 products for work, school, and personal
productivity.
Microsoft 365
Enterprise Mobility + Security
Windows
With their consent, you can use Microsoft Graph to get access to users and
organizational data according to the services they are licensed to and the services and
features available in Microsoft Graph. To learn more, see Major services and features in
Microsoft Graph.
Next steps
Check out some partner solutions.
Try a sample request in the Graph Explorer.
Use the quick start to set up a ready-to-run sample app.
Look under Learn in the table of contents to read about services and features that
you can use in your scenarios.
Find out how to get an auth token in your app.
Start using the API.
National cloud deployments
Article • 03/08/2023
In addition to our global network of datacenters, Microsoft cloud services are available in
two separate national clouds. These national cloud versions are physical and logical
network-isolated instances of Microsoft enterprise cloud services that are confined
within the geographic borders of specific countries and operated by local personnel.
Each national cloud environment is unique and different than the Microsoft global
environment. It's important to be aware of some of these key differences when you
develop applications for national cloud environments; for example, registering
applications, acquiring tokens, and calling the Microsoft Graph API can be different.
This article provides information about the different Microsoft Graph national cloud
deployments and the capabilities that are available to developers within each.
7 Note
Microsoft Graph Data Connect does not support any of the national cloud
deployments.
https://www.youtube-nocookie.com/embed/R_3E0IVypRM
To learn more about access tokens and Microsoft Graph, see authentication basics. For
Azure AD authentication scenarios, see Azure AD authentication basics.
) Important
7 Note
Apps can only access organizational data through the national cloud endpoints.
This means that apps can only access data in tenants that are registered in the
specific national cloud. Apps that are trying to access consumer data associated
with Microsoft personal accounts through Microsoft Graph should use the global
service https://graph.microsoft.com . Access tokens acquired for a national cloud
deployment are not interchangeable with those acquired for the global service or
any other national cloud.
Supported features
The following Microsoft Graph features are generally available on the /v1.0 endpoint
across all national cloud deployments, except where noted.
Microsoft Graph features Microsoft Cloud for US Microsoft Cloud China operated
Government by 21Vianet
Access reviews ✔ ✔
Change notifications ✔ ✔
(subscriptions)
Directory extensions ✔ ✔
Excel ✔ ➖
Groups ✔ ✔
Microsoft Graph features Microsoft Cloud for US Microsoft Cloud China operated
Government by 21Vianet
OneDrive ✔ ✔*
Organizational contacts ✔ ✔
Outlook Calendar ✔ ✔
Outlook Mail ✔ ✔
Personal Contacts ✔ ✔
Privileged identity ✔ ✔
management
Planner ✔ ✔
Security ✔ ✔
SharePoint ✔ ✔
Teams ✔ ➖
To Do ✔ ➖
Users ✔ ✔
For more information about the availability of Microsoft 365 usage reports in national
clouds, see Working with Microsoft 365 usage reports in Microsoft Graph.
(*) Limited support for Exchange and OneDrive services only. Azure AD services aren't
supported.
) Important
Certain services and features that are in specific regions of the global service might
not be available in all of the national clouds. To find out what services are available,
see products available by region .
Explore samples for authenticating and working with Azure and Microsoft 365 in
National cloud deployments:
Microsoft Graph has always provided access to customer mailboxes in the cloud on
Exchange Online as part of Microsoft 365. Exchange 2016 Cumulative Update 3 (CU3),
released in September 2016 for Exchange on-premises servers, added support for REST
API integration with Microsoft 365.
Effective March 2023, the ability to use these REST APIs in hybrid deployments will no
longer be available.
API requests are not currently blocked, but Microsoft will block these requests
beginning in March 2023.
For more information, see The End of REST API Integration for Exchange on-premises -
Preview .
Overview of metered APIs and services
in Microsoft Graph
Article • 03/16/2023
Microsoft Graph includes APIs that are available at no additional cost with user
subscription licenses and APIs and services that are metered. Metered APIs and services
in Microsoft Graph incur costs based on usage. The costs might be incurred per API call
made, per object returned in an API call, or through other measures.
Whether metered or not, APIs in Microsoft Graph follow these two principles:
Customer data ownership: Customer data belongs to the customer. Learn more
about how Microsoft categorizes customer data .
Reasonable access: The service provides access to customer content, within
defined limits.
Metering some APIs helps to ensure the health of the current and future Microsoft
Graph ecosystem by balancing platform access and cost. In the event that a Microsoft
Graph API that is included with user subscription licenses becomes metered, that would
be a non-backward compatible change and the versioning, support, and breaking
change policies for Microsoft Graph would apply.
For the list of metered APIs and services, see Metered APIs and services.
Standard APIs
Most Microsoft Graph APIs are standard APIs. These APIs perform standard operations
(create, read, update, delete) on customer content and administrative endpoints.
Reasonable access limits for these APIs are defined based on documented usage
thresholds. This helps to ensure a positive customer experience and encourages efficient
API usage patterns. Access to standard APIs within the defined usage thresholds is
available as part of the user license without additional costs.
High-capacity APIs
High-capacity APIs ensure that customers and developers have access to data at scale.
This category includes purpose-built, bulk export or import endpoints and Microsoft
Graph services. These APIs may be metered and incur additional costs beyond user
subscription licenses.
Advanced APIs
Advanced APIs provide access to enriched or aggregated data, or advanced functionality
that extends from Microsoft 365. The assignSensitivityLabel API is an example of an
advanced API. These APIs may be metered and incur additional costs beyond user
subscription licenses.
Metered APIs can return errors related to your subscription status in addition to
other common errors. For details about Microsoft Graph errors, see Microsoft
Graph errors and resource types.
Metered APIs are billed according to API usage. Be sure to understand the
metering unit so that you can estimate the costs associated with a particular API.
Known limitations
The following limitations apply to metered APIs:
Metered APIs and services in Microsoft Graph are currently available only in the
Microsoft global environment and not in national cloud deployments, including
Microsoft 365 GCC deployments accessed through the worldwide Microsoft Graph
endpoint. For details about national clouds, see National cloud deployments.
The target application must be a confidential client application (for example, web
application, web API, or daemon/service). Public client applications (desktop and
mobile applications) are not supported.
See also
Metered APIs and services in Microsoft Graph
Enable metered APIs and services in Microsoft Graph
Payment models and licensing requirements for Microsoft Teams APIs
Metered APIs and services in Microsoft
Graph
Article • 03/16/2023
This article provides a list of metered APIs and services in Microsoft Graph. To call these
APIs and services, you must associate an active Azure subscription with the calling
application. For details, see Overview of metered APIs and services in Microsoft Graph.
Some metered APIs and services in Microsoft Graph are protected and require
additional validation beyond permissions and admin consent. Before you can use these
protected APIs, you must submit a request.
Teams chat export Teams API payment models and Microsoft Teams
licensing requirements request
Teams channel export Teams API payment models and Microsoft Teams
licensing requirements request
Teams chat / channel change Teams API payment models and Microsoft Teams
notifications licensing requirements request
Teams conversationMember change Teams API payment models and Microsoft Teams
notifications licensing requirements request
Teams chat / channel message Teams API payment models and Microsoft Teams
PATCH operations licensing requirements request
SharePoint and OneDrive for No charge while API is in preview SharePoint preview
Business assignSensitivityLabel enrollment form
See also
Overview of metered APIs and services in Microsoft Graph
Enable metered APIs and services in Microsoft Graph
Protected APIs in Microsoft Teams
Versioning, support, and breaking
change policies for Microsoft Graph
Article • 06/15/2022
This article describes the support and breaking change policies for Microsoft Graph and
the versions of the Microsoft Graph API that are currently available.
As new versions of the Microsoft Graph REST APIs and Microsoft Graph SDKs are
released, earlier versions will be retired. Microsoft declares a version as deprecated at
least 24 months in advance of retiring it. Similarly, for individual APIs that are generally
available (GA), Microsoft declares an API as deprecated at least 24 months in advance of
removing it from the GA version.
When we increment the major version of the API (for example, from v1.0 to v2.0), we are
announcing that the current version (in this example, v1.0) is immediately deprecated
and we will no longer support it 24 months after the announcement. We might make
exceptions to this policy for service security or health reliability issues.
When an API is marked as deprecated, we strongly recommend that you migrate to the
latest version as soon as possible. In some cases, we will announce that new applications
will have to start using the new APIs a short time after the original APIs are deprecated.
In those cases, only active applications that currently use the deprecated APIs can
continue to use them.
Note: Over time, we will update the list of backward compatible changes. If you
generate your own client proxies (like WCF clients), our guidance is that your client
applications should be prepared to receive properties and derived types not
previously defined by the Microsoft Graph API service. Microsoft Graph API follows
the guidance described in the Model Versioning section in the Microsoft REST API
guidelines .
Versions
The following versions of the Microsoft Graph API are currently available.
Beta version
In general, APIs debut in the beta version and are accessible in the
https://graph.microsoft.com/beta endpoint. For beta API documentation, see Microsoft
Graph beta endpoint reference. Expect breaking changes and deprecation of APIs in the
beta version from time to time. Do not take a production dependency on beta APIs.
We make no guarantees that a beta feature will be promoted to the current version.
When the Microsoft Graph API team believes that a beta feature is ready for general
availability, we will add that feature to the latest current version. If the promotion of the
feature would result in a breaking change to the current version, the version number will
be incremented, with the new version becoming the current version. Our developer
community can post feature requests on the Microsoft 365 Developer Platform ideas
forum , including requests for new features as well as requests to promote existing
beta APIs to the current version.
Current version
The current version of Microsoft Graph is v1.0. Exposed under
https://graph.microsoft.com/v1.0 , the Microsoft Graph API v1.0 version contains
features that are generally available and ready for production use. Browse the
documentation for the v1.0 APIs.
Preview status
An API or feature in Microsoft Graph is labelled as "(preview)" to indicate its behavior is
unique in the beta endpoint.
The behavior of most APIs and features in the v1.0 version is in parity with the beta
version. "preview" qualifies a minority of APIs and features in one of the following two
cases:
Like any other API in the beta endpoint, APIs marked in the documentation as "
(preview)" may experience breaking changes without notice. Do not access APIs from
the beta endpoint in production apps.
As an example, attack simulation training is a feature that has been generally available
for administrators in the Microsoft 365 Defender portal . When the REST API for attack
simulation training becomes available in Microsoft Graph in only the beta endpoint, the
REST API documentation is labelled as "(preview)". The "(preview)" label applies to the
REST API and its documentation in Microsoft Graph, even though the service itself is
generally available.
Terms of use
By using the Microsoft Graph APIs, you agree to the Microsoft APIs Terms of Use.
Your feedback is important to us. Connect with us on Microsoft Q&A. Tag your
questions with [microsoft-graph-*].
Microsoft APIs Terms of Use
Article • 09/26/2022
1. Defined Terms
a) "Customer(s)" means the licensee of a Microsoft online service ("Microsoft Offering")
and if the licensee is an organization, includes their administrators and end users.
b) "Microsoft APIs" means (i) any form of machine accessible application programming
interface that Microsoft makes available which provides access to a Microsoft Offering,
including all associated tools, elements, components and executables therein, (ii) any
Microsoft sample code that enables interactions with a Microsoft Offering, and (iii)
documentation that Microsoft makes available to help enable your access to the
Microsoft APIs.
c) "Microsoft email protocols and APIs" may include and means IMAP, POP, MAPI, RPC
over HTTP, Outlook REST API, Outlook APIs in Microsoft Graph API, Exchange Web
Services ("EWS"), Exchange Active Sync ("EAS"), Exchange Management Shell and any
Exchange online APIs in the Microsoft APIs, individually or in any combination, when
used to provide access to a Microsoft Offering.
1. if you have entered into another agreement with Microsoft that expressly
supersedes these API Terms and governs your use of specific Microsoft APIs, or
2. for any APIs other than the APIs listed in section 1.d) of these terms, if you access
APIs that present accompanying terms ("Accompanying Terms") and you have
accepted those Accompanying Terms, then those Accompanying Terms will apply
to your access of those APIs.
1. Use the Microsoft APIs in a way that could impair, harm or damage Microsoft, the
Microsoft APIs, any Microsoft Offering, or anyone's use of the Microsoft APIs or
any Microsoft Offerings;
2. Use the Microsoft APIs to disrupt, interfere with, or attempt to gain unauthorized
access to services, servers, devices, or networks connected to or which can be
accessed via the Microsoft APIs;
3. Use the Microsoft APIs, or any information accessed or obtained using the
Microsoft APIs, for the purpose of migrating Customers away from a Microsoft
Offering, except in connection with use of the Microsoft APIs by your Application
or unless expressly permitted by Microsoft pursuant to a duly executed written
agreement;
4. Scrape, build databases or otherwise create copies of any data accessed or
obtained using the Microsoft APIs, except as necessary to enable an intended
usage scenario for your Application;
5. Request from the Microsoft APIs more than the minimum amount of data, or more
than the minimum permissions to the types of data, that your Application needs
for Customers to use the intended functionality of your Application;
6. Use an unreasonable amount of bandwidth, or adversely impact the stability of the
Microsoft APIs or the behavior of other apps using the Microsoft APIs;
7. Attempt to circumvent the limitations Microsoft sets on your use of the Microsoft
APIs. Microsoft sets and enforces limits on your use of the Microsoft APIs (e.g.,
limiting the number of API requests that you may make or the number of users
you may serve), in its sole discretion;
8. Use Microsoft APIs in any manner that works around any technical limitations of
the Microsoft APIs or of the accessed Microsoft Offering, or reverse engineer,
decompile or disassemble the Microsoft APIs, except and only to the extent that
applicable law expressly permits, despite this limitation;
9. Use the Microsoft APIs, or any data obtained using the Microsoft APIs, to conduct
performance testing of a Microsoft Offering unless expressly permitted by
Microsoft pursuant to a duly executed written agreement;
10. Use the Microsoft APIs, or any data obtained using the Microsoft APIs, to identify,
exploit or publicly disclose any potential security vulnerabilities;
11. Request, use or make available any data obtained using the Microsoft APIs outside
any permissions expressly granted by Customers in connection with using your
Application;
12. Use or transfer any data accessed or obtained using the Microsoft APIs, including
any data aggregated, anonymized or derived from that data (collectively the
"Microsoft APIs Data") for advertising or marketing purposes including (i) targeting
ads, or (ii) serving ads. For purposes of clarity, this prohibition on using Microsoft
APIs Data for advertising or marketing purposes does not extend to using other
data, such as (i) the number of users of your Application, (ii) a user identifier you
independently receive from a user (e.g., an email address you receive when a user
enrolls to use your Application, a device identifier, or an advertising identifier), or
(iii) a product or service identifier that identifies a Microsoft Offering;
13. Make your Application available for use in a manner that circumvents the need for
users to obtain a valid license to the Microsoft application or service that is
accessed through the Microsoft APIs;
14. Redistribute or resell, or sublicense access to, the Microsoft APIs, any data
obtained using the Microsoft APIs, or any other Microsoft Offering accessed
through the Microsoft APIs; or
15. Misrepresent expressly, by omission, or implication, the need for users to obtain a
valid license to the Microsoft application or service that is accessed through the
Microsoft APIs;
16. Falsify or alter any unique referral identifier in, or assigned to an Application, or
otherwise obscure or alter the source of queries coming from an Application to
hide a violation of this agreement; or
17. Use the Microsoft APIs or allow any user to use the Application in a way that
violates applicable law, including:
a. Illegal activities, such as child pornography, gambling, piracy, violating
copyright, trademark or other intellectual property laws.
b. Intending to exploit minors in any way.
c. Accessing or authorizing anyone to access the Microsoft APIs from an
embargoed country as prohibited by the U.S. government.
d. Threatening, stalking, defaming, defrauding, degrading, victimizing or
intimidating anyone for any reason.
e. Violating applicable privacy laws and regulations.
18. Use the Microsoft APIs in a way that could create, in Microsoft's sole discretion and
judgment, an unreasonable risk to Customers from a security or privacy
perspective.
c) Accessing the Exchange and Outlook Services through Microsoft email protocols
and APIs
Unless you have use permissions expressly and specifically granted by Customers in
connection with using your Application, you may not use Microsoft email protocols and
APIs for any purpose other than:
When your Application or services access an Intune API in Microsoft Graph using a Post
command, for example, such as documented at https://learn.microsoft.com/graph, you
must include:
When your Application or services access a Microsoft API for Microsoft OneDrive, other
than the work files of a user or work files created on behalf of a user, you may not
enable storage of system data in Microsoft OneDrive, the systems data including (i)
computer system back-up data, (ii) team, organization, or departmental level data, or (iii)
data related to any assignment of a per user license to a team, organization,
department, or other non-human entity. Such systems data can be stored in Microsoft
SharePoint shared libraries, which is a solution for more advanced content management
and collaboration, including storing and managing files, communications, and intranet
sites across a team or organization.
f) Accessing the Microsoft Yammer Service through a Microsoft API
When your Application or services access a Microsoft API for Yammer, you must adhere
to the following requirements:
1. Contact and Cooperation. You (or the name of the contact you gave to Microsoft
when you applied for your application key if it's not you) must be reachable at all
times for privacy and security questions or concerns. You can change this name or
contact by signing up for a new application key, and providing the correct contact
information and using the new application key instead.
2. Reporting. In addition to the vulnerabilities and data breach requirements of
section 4. Security, you must promptly report any security deficiencies in or
intrusions to your Application or services systems that you discover to Microsoft in
writing via email to [email protected]. You will work with Microsoft to
immediately correct any security deficiency and will disconnect immediately any
intrusions or intruder. In the event of any such security deficiency or intrusion, you
will make no public statements (e.g., press, blogs, social media, bulletin boards,
etc.) without prior written and express permission from Microsoft in each instance.
3. Branding. If your product or service uses or is based upon accessing the Microsoft
Yammer service through a Microsoft API, and you wish to include Yammer
branding or logos, please contact us at [email protected]. Absent express
written permission from us, you may not use Yammer branding, except as outlined
in section 3. f) 4. below.
4. Attribution. The images provided to you through the accessing the Microsoft
Yammer service through a Microsoft API may contain the trade names, trademarks,
service marks, logos, domain names, and other distinctive brand features of
Microsoft and its partners. You may not delete or in any manner alter these trade
names, trademarks, service marks, logos, domain names, and other distinctive
brand features. You agree to maintain, and not to remove, modify, obscure or alter,
any link or notices appearing on any image provided through the Service.
4. Security
You warrant that your Application has been developed to operate with Microsoft API
content in a secure manner. Your network, operating system and the software of your
servers, databases, and computer systems (collectively, "Systems") must be properly
configured to securely operate your Application and store content collected through
your Application (including the Microsoft API content). Your Application must use
reasonable security measures to protect the private data of your users.
We may use technology to detect, prevent or limit the impact of any issues caused by
your Application (before, after, or instead of suspension of your access). This may
include, for example, (i) filtering to stop spam, (ii) performing security or privacy
monitoring regarding scraping, denial of service attacks, user impersonation, application
impersonation, or illicit consent grant(s), or (iii) limiting or terminating your access to the
Microsoft APIs.
You will permit Microsoft reasonable access to your Application for purposes of
monitoring compliance with these API Terms. You will respond to any questions by
Microsoft about your compliance with these API Terms.
Without limiting the foregoing, upon request by Microsoft, you will provide us (or an
independent auditor acting on our behalf) with up to two full-feature client account-
level instances to access your Application (and/or other materials relating to your use of
the API) as reasonably requested by us to verify your compliance with these API Terms
(including, in particular, your security and privacy obligations under these API Terms).
We may restrict or terminate access to the APIs or perform an audit (including by hiring
an independent auditor acting on our behalf) of your Application if you fail to provide
adequate information and materials (including up to two full-featured instances of your
Application) to verify your compliance with these Terms.
You must have a process to respond to any vulnerabilities in your Application, and in the
case of any vulnerabilities related to your Application's connection to the Microsoft APIs
discovered by you or reported to you by a third party, you agree that you will provide
vulnerability details to the Microsoft Security Response Center ([email protected]).
In the event of a data breach by you resulting from any aspect of the Microsoft APIs
involving your Application or any data collected through your Application, you will
promptly contact the Microsoft Security Response Center ([email protected]) and
provide details of the data breach. You agree to refrain from making public statements
(e.g., press, blogs, social media, bulletin boards, etc.) without prior written and express
permission from Microsoft in each instance as it relates to the Microsoft APIs.
The rights and requirements of this section -- 4. Security -- will survive for five (5) years
following any termination of these API Terms.
a) obtain all necessary consents before processing data and obtain additional consent if
the processing changes ("Data Access Consents"),
b) In the event you're storing data locally, ensure that data is kept up to date and
implement corrections, restrictions to data, or the deletion of data as reflected in the
data obtained through your use of the Microsoft APIs,
c) implement proper retention and deletion policies, including deleting all data when
your user abandons your Application, uninstalls your Application, closes its account with
you, or abandons the account,
d) maintain and comply with a written statement available to Customers and users that
describes your privacy practices regarding data and information you collect and use
("Your Privacy Statement"), and that statement must be as protective as the Microsoft
Privacy Statement , and
e) When your Application allows end users to sign in with a Microsoft account and
Microsoft is not providing the user interface for the sign in, your Privacy Statement must
provide a link to https://account.live.com/consent/Manage and/or
https://myapps.microsoft.com , or such other location(s) as we may specify from time
to time, with a clear indication that Customers and end users can go to the Microsoft
site(s) to revoke Data Access Consents at any time. If Customers or end users must take
additional steps to disable your Application's access to Customer or end user data, then
Your Privacy Statement must clearly indicate to Customers and end users the additional
steps required to disable access.
WE MAY MODIFY THESE API TERMS AT ANY TIME, WITH OR WITHOUT PRIOR
NOTICE TO YOU. YOUR CONTINUED USE OF THE MICROSOFT APIs FOLLOWING THE
RELEASE OF A SUBSEQUENT VERSION OF THESE API TERMS WILL BE DEEMED YOUR
ACCEPTANCE OF ANY MODIFICATIONS TO THESE API TERMS.
7. Feedback
If you give feedback about the Microsoft APIs to Microsoft, you give to Microsoft,
without charge, the right to use, share and commercialize your feedback in any way and
for any purpose. You will not give feedback that is subject to a license that requires
Microsoft to license its software or documentation to third parties because Microsoft
includes your feedback in them. These rights survive these API Terms.
8. Confidentiality
You may be given access to certain non-public information, software, and specifications
relating to the Microsoft APIs ("Confidential Information"), which is confidential and
proprietary to Microsoft. You may use Confidential Information only as necessary in
exercising your rights granted under these API Terms. You may not disclose any
Confidential Information to any third party without Microsoft's prior written consent.
You agree that you will protect any Confidential Information from unauthorized use,
access, or disclosure in the same manner that you would use to protect your own
confidential and proprietary information.
b) Limitation of Liability
c) Indemnification
You will defend, hold harmless, and indemnify Microsoft from any claim or action
brought by a third party, including all damages, liabilities, costs and expenses, and
reasonable attorney fees, to the extent resulting from, alleged to have resulted from, or
in connection with your breach of the obligations herein or infringement of Microsoft's
or third party's intellectual property.
d) No Injunctive Relief
In no event shall you seek or be entitled to rescission, injunctive or other equitable relief,
or to enjoin or restrain the operation of the Microsoft APIs, content or other material
used or displayed through the current Microsoft website or successor site.
e) No Third-Party Beneficiaries
There are no third-party beneficiaries to this Agreement.
10. Termination
a) We may suspend or immediately terminate these API Terms, any rights granted
herein, and/or your license to the Microsoft APIs, in our sole discretion at any time, for
any reason. You may terminate these API Terms at any time by ceasing your access to
the Microsoft APIs.
b) Upon termination, all licenses granted herein immediately expire and you must cease
use of the Microsoft APIs. You must also comply with Customer's instruction to return or
delete any data accessed or obtained through the Microsoft APIs, unless expressly
permitted by Microsoft or prohibited by law. Neither party will be liable to the other for
any damages resulting solely from termination of these API Terms.
1. United States. If you reside in the United States, Washington state law governs the
interpretation of these API Terms and applies to claims for breach of it, regardless
of conflict of laws principles. The laws of the state where you live govern all other
claims, including claims under state consumer protection laws, unfair competition
laws, and in tort.
2. Outside the United States. If you reside in any other country, the laws of that
country apply.
b) Support. Because the Microsoft APIs are provided "as is," we may not provide
support services for them. You are solely responsible for the quality of your Application
and providing support for your Application.
c) Assignment and Delegation. You may not assign or delegate any rights or obligations
under these API Terms, including in connection with a change of control. Any purported
assignment and delegation shall be ineffective. We may freely assign or delegate all
rights and obligations under these API Terms, fully or partially without notice to you.
d) Reservation of Rights. All rights not expressly granted herein are reserved by
Microsoft. You acknowledge that all intellectual property rights within the Microsoft APIs
remain the property of Microsoft and nothing within these API Terms will act to transfer
any of these intellectual property rights to you.
e) Microsoft and you are independent contractors. Nothing in this Agreement shall be
construed as creating an employer-employee relationship, processor-subprocessor
relationship, a partnership, or a joint venture between the parties.
f) No Waiver. Either party's failure to act with respect to a breach of these API Terms
does not waive either party's right to act with respect to that breach or subsequent
similar or other breaches.
g) Survival. Sections of these API Terms that, by their terms, require performance after
the termination or expiration of these API Terms will survive, such as, for example, the
rights and requirements of section 4. Security.
h) Modifications. We may modify these API Terms at any time with or without individual
notice to you. Any modifications will be effective upon your continued use of the
Microsoft APIs.
i) Entire Agreement. These API Terms and any documents incorporated into these API
Terms by reference, constitute the entire agreement between you and us regarding the
Microsoft APIs and supersede all prior agreements and understandings, whether written
or oral, or whether established by custom, practice, policy or precedent, with respect to
the subject matter of these API Terms. If any provision of these API Terms is found to be
illegal, void, or unenforceable, the unenforceable provision will be modified so as to
render it enforceable to the maximum extent possible.
Overview of users in Microsoft Graph
Article • 01/27/2023
Users are the representation of an Azure Active Directory (Azure AD) work or school user
account or a Microsoft account in Microsoft Graph. The user resource in Microsoft
Graph is a hub from which you can access the relationships and resources that are
relevant to your users.
https://www.youtube-nocookie.com/embed/TUMPipN3UFI
To access a user's information and data, you'll need to get access on their behalf.
Authenticating your application with admin consent enables you to work with and
update a wider range of entities associated with a user.
API reference
Looking for the API reference for this service?
Next steps
The user resource type.
Training module: Build your skills and learn how to work with users through
Microsoft Graph.
What are the default user permissions in
Azure Active Directory?
Article • 03/13/2023
In Azure Active Directory (Azure AD), all users are granted a set of default permissions. A
user's access consists of the type of user, their role assignments, and their ownership of
individual objects.
This article describes those default permissions and compares the member and guest
user defaults. The default user permissions can be changed only in user settings in Azure
AD.
Member users can register applications, manage their own profile photo and
mobile phone number, change their own password, and invite B2B guests. These
users can also read all directory information (with a few exceptions).
Guest users have restricted directory permissions. They can manage their own
profile, change their own password, and retrieve some information about other
users, groups, and apps. However, they can't read all directory information.
For example, guest users can't enumerate the list of all users, groups, and other
directory objects. Guests can be added to administrator roles, which grant them full
read and write permissions. Guests can also invite other guests.
Users and Enumerate the Read their own Read their own
contacts list of all users properties properties
and contacts Read display name, Change their
Read all public email, sign-in name, own password
properties of photo, user principal Manage their
users and name, and user type own mobile
contacts properties of other users phone number
Invite guests and contacts
Change their Change their own
own password password
Manage their Search for another user
own mobile by object ID (if allowed)
phone number Read manager and direct
Manage their report information of
own photo other users
Invalidate their
own refresh
tokens
Area Member user Default guest user Restricted guest user
permissions permissions permissions
U Caution
Register Setting this option to No prevents users from creating application registrations.
applications You can then grant the ability back to specific individuals, by adding them to
the application developer role.
Allow users to Setting this option to No prevents users from connecting their work or school
connect work account with their LinkedIn account. For more information, see LinkedIn
or school account connections data sharing and consent.
account with
LinkedIn
Create security Setting this option to No prevents users from creating security groups. Global
groups administrators and user administrators can still create security groups. To learn
how, see Azure Active Directory cmdlets for configuring group settings.
Create Setting this option to No prevents users from creating Microsoft 365 groups.
Microsoft 365 Setting this option to Some allows a set of users to create Microsoft 365
groups groups. Global administrators and user administrators can still create Microsoft
365 groups. To learn how, see Azure Active Directory cmdlets for configuring
group settings.
Permission Setting explanation
How do I grant only a specific non-administrator users the ability to use the
Azure AD administration portal?
Set this option to Yes, then assign them a role like global reader.
Restrict non- Users can create tenants in the Azure AD and Entra administration portal under
admin users Manage tenant. The creation of a tenant is recorded in the Audit log as
from creating category DirectoryManagement and activity Create Company. Anyone who
tenants creates a tenant becomes the Global Administrator of that tenant. The newly
created tenant doesn't inherit any settings or configurations.
Restrict non- Setting this option to Yes restricts users from being able to self-service recover
admin users BitLocker key(s) for their owned devices. Setting this option to No allows users
from reading to recover their BitLocker key(s).
BitLocker
key(s) for their
owned devices
Read other This setting is available in Microsoft Graph and PowerShell only. Setting this flag
users to $false prevents all non-admins from reading user information from the
directory. This flag doesn't prevent reading user information in other Microsoft
services like Exchange Online.
The Restrict non-admin users from creating tenants option is shown below
7 Note
The Guest user access restrictions setting replaced the Guest users permissions
are limited setting. For guidance on using this feature, see Restrict guest access
permissions in Azure Active Directory.
Guest user Setting this option to Guest users have the same access as members grants all
access member user permissions to guest users by default.
restrictions
Setting this option to Guest user access is restricted to properties and
memberships of their own directory objects restricts guest access to only their own
user profile by default. Access to other users is no longer allowed, even when
they're searching by user principal name, object ID, or display name. Access to
group information, including groups memberships, is also no longer allowed.
This setting doesn't prevent access to joined groups in some Microsoft 365 services
like Microsoft Teams. To learn more, see Microsoft Teams guest access.
Guest users can still be added to administrator roles regardless of this permission
setting.
Guests can Setting this option to Yes allows guests to invite other guests. To learn more, see
invite Configure external collaboration settings.
Object ownership
An owner can also add or remove other owners. Unlike global administrators, owners
can manage only the applications that they own.
An owner can also add or remove other owners. Unlike global administrators, owners
can manage only the applications that they own.
An owner can also add or remove other owners. Unlike global administrators and user
administrators, owners can manage only the groups that they own.
Ownership permissions
The following tables describe the specific permissions in Azure AD that member users
have over owned objects. Users have these permissions only on objects that they own.
Action Description
Action Description
Owned devices
Action Description
Owned groups
7 Note
Action Description
Next steps
To learn more about the Guest user access restrictions setting, see Restrict guest
access permissions in Azure Active Directory.
To learn more about how to assign Azure AD administrator roles, see Assign a user
to administrator roles in Azure Active Directory.
To learn more about how resource access is controlled in Microsoft Azure, see
Understanding resource access in Azure.
For more information on how Azure AD relates to your Azure subscription, see
How Azure subscriptions are associated with Azure Active Directory.
Manage users.
Working with groups in Microsoft Graph
Article • 03/02/2023
Groups are collections of principals with shared access to resources in Microsoft services
or in your app. Different principals such as users, other groups, devices, and applications
can be part of groups. Using groups helps you avoid working with individual principals
and simplifies management of access to your resources.
Microsoft Graph exposes the groups API to create and manage different types of groups
and group functionality.
7 Note
7 Note
Only Microsoft 365 and security groups can be managed through the Microsoft Graph
groups API. Mail-enabled and distribution groups are read-only through Microsoft
Graph.
In Microsoft Graph, the type of group can be identified by the settings of its groupType,
mailEnabled, and securityEnabled properties as indicated in the table below.
Type groupType mailEnabled securityEnabled Created and
managed via the
groups API
For more information about groups, see the sections below. For more information about
groups in Azure AD, see compare groups in Azure AD.
Outlook conversations
Outlook calendar
SharePoint files
OneNote notebook
SharePoint team site
Planner plans
Intune device management
The following JSON object shows a sample representation of a group when you call the
Microsoft Graph groups API.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
"id": "4c5ee71b-e6a5-4343-9e2c-4244bc7e0938",
"deletedDateTime": null,
"classification": "MBI",
"createdDateTime": "2016-08-23T14:46:56Z",
"description": "This is a group in Outlook",
"displayName": "OutlookGroup101",
"groupTypes": [
"Unified"
],
"mail": "[email protected]",
"mailEnabled": true,
"mailNickname": "outlookgroup101",
"preferredLanguage": null,
"proxyAddresses": [
"smtp:[email protected]",
"SMTP:[email protected]"
],
"securityEnabled": false,
"theme": null,
"visibility": "Public"
}
To learn more about Microsoft 365 groups, see Overview of Microsoft 365 groups in
Microsoft Graph.
Group expiration
Group settings such as whether the group can have guests as members, who is
allowed to create groups, allowed words in group names, and so on.
Mail-enabled security groups are used in the same way as security groups, but can be
used to send emails to group members. Mail-enabled security groups can't be created
or updated through the API; instead, they're read-only. Learn more in the Manage mail-
enabled security groups Exchange article.
The following JSON object shows a sample representation of a security group when you
call the Microsoft Graph groups API.
HTTP
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.type": "#microsoft.graph.group",
"id": "f87faa71-57a8-4c14-91f0-517f54645106",
"deletedDateTime": null,
"classification": null,
"createdDateTime": "2016-07-20T09:21:23Z",
"description": "This group is a Security Group",
"displayName": "SecurityGroup101",
"groupTypes": [],
"mail": null,
"mailEnabled": false,
"mailNickname": "",
"preferredLanguage": null,
"proxyAddresses": [],
"securityEnabled": true
}
Group membership
Not all object types can be members of both Microsoft 365 and security groups.
The following table shows the types of members that can be added to either security
groups or Microsoft 365 groups.
User
Security group
Device
Service principal
Organizational contact
Dynamic membership
Microsoft 365 and security groups can have dynamic membership rules that
automatically add or remove members from the group based on the principal's
properties. For example, a "Marketing employees" group can define a dynamic
membership rule that only users with their department property set to "Marketing" can
be members of the group. In this case, any user's who leave the department are
automatically removed from the group.
Only users and devices are supported as members in dynamic membership groups. You
can create a dynamic membership group for devices or users, but not both.
The dynamic membership rules are specified through the membershipRule property
during group creation. A single expression follows this syntax: Property Operator Value .
The rule syntax supports various operators. For more information, see Supported
expression operators.
A Value of type String must be enclosed in double quotes ("). You must use a
backslash to escape any double quotes inside double quotes. This requirement
doesn't apply when using the rule builder in the Azure portal because the
expression isn't enclosed in double quotes.
You can combine multiple expressions in a rule using the and , or , and not operators.
The groupType property must also include the "DynamicMembership" value in the
collection. The dynamic membership rule can be turned on or off through the
membershipRuleProcessingState property. You can update a group with assigned
membership to have dynamic membership.
The following example request creates a new Microsoft 365 group that can only include
employees in the Marketing department.
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/groups
Content-type: application/json
{
"description": "Marketing department folks",
"displayName": "Marketing department",
"groupTypes": [
"Unified",
"DynamicMembership"
],
"mailEnabled": true,
"mailNickname": "marketing",
"securityEnabled": false,
"membershipRule": "user.department -eq \"Marketing\"",
"membershipRuleProcessingState": "on"
}
The request returns a 201 Created response code and the newly created group object in
the response body.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
"id": "6f7cd676-5445-47c4-9c2b-c47da4671da2",
"createdDateTime": "2023-01-20T07:00:31Z",
"description": "Marketing department folks",
"displayName": "Marketing department",
"groupTypes": [
"Unified",
"DynamicMembership"
],
"mail": "[email protected]",
"mailEnabled": true,
"mailNickname": "marketing",
"membershipRule": "user.department -eq \"Marketing\"",
"membershipRuleProcessingState": "On"
}
To learn more about formulating membership rules, see Dynamic membership rules for
groups in Azure Active Directory.
7 Note
If the signed-in user is a guest user, depending on the permissions an app has been
granted, it can read the profile of a specific group (for example,
https://graph.microsoft.com/v1.0/group/fc06287e-d082-4aab-9d5e-d6fd0ed7c8bc );
however, it can't perform queries against the /groups resource that potentially returns
more than a single resource.
With the appropriate permissions, the app can read the profiles of groups that it obtains
by following links in navigation properties; for example, /groups/{id}/members .
For more information about what guest users can do with groups, see Compare
member and guest default permissions.
Group-based licensing
You can use group-based licensing to assign one or more product licenses to an Azure
AD group. Azure AD ensures that the licenses are assigned to all members of the group.
Any new members who join the group are assigned the appropriate licenses. When they
leave the group, those licenses are removed. The feature can only be used with security
groups and Microsoft 365 groups that have securityEnabled=TRUE . To learn more about
group-based licensing, see What is group-based licensing in Azure Active Directory?.
Create new groups, get existing groups, update the properties on group Create
groups, and delete groups. Currently, only security groups and new
groups in Outlook can be created through the API. groups
List
groups
Update
groups
Delete
groups
List the members of a group, and add or remove members. user List
group members
Add
member
Remove
member
Determine whether a user is a member of a group, get all the user Check
groups the user is a member of. group member
servicePrincipal groups
orgContact Get
member
groups
List the owners of a group, and add or remove owners. user List
group owners
Add
member
Remove
member
What's new
Find out about the latest new features and updates for this API set.
Overview of Microsoft 365 groups in
Microsoft Graph
Article • 05/20/2023
Microsoft 365 groups provide the foundational membership service for users to share
conversations, files, notes, calendars, plans, and many other assets.
https://www.youtube-nocookie.com/embed/WB9w6QM9xIU
Use the Create group API to provision a new group. The group is then made
available in a range of applications, such as Outlook, SharePoint, Microsoft Teams,
Planner, and even Microsoft Stream. Microsoft Graph synchronizes across these
connected services to seamlessly provide access to all group members.
Every Microsoft 365 group is integrated with a default set of Microsoft 365
services
Get information about the SharePoint site that's associated with a group, such as
the document library lists or subsites.
Create a plan in Planner that is owned by a group. The plan provides a visual way
to track teamwork by allowing you to create tasks that can be organized across
buckets.
Access the OneNote notebook associated with a group, which can be used for
collecting meeting notes and organizing ideas.
Delete groups. When a group is deleted, all associated content is also deleted,
which prevents orphaned sites, conversations, or plans.
Configure a broad range of group policy settings that help define behaviors, such
as automatically deleting groups unless they are renewed by an owner and
enforcing naming policies on Microsoft 365 groups.
Renew groups that are about to expire to allow team members to continue with
collaboration and accessing content. If the group is not renewed according to the
established expiration policy, the group is automatically deleted.
Restore deleted groups.
API reference
Looking for the API reference for this service?
Next steps
Try out some sample API requests in Graph Explorer.
Learn more about how to use the groups API in Microsoft Graph.
Set Microsoft 365 group behaviors and
provisioning options
Article • 01/27/2023
Using the group resource in Microsoft Graph, you can set specific group behaviors and
resources to provision when creating a Microsoft 365 group. Depending on the
resource, some can also be provisioned on group update.
Configure groups
resourceBehaviorOptions is a string collection that specifies group behaviors for a
Microsoft 365 group. These behaviors can be set only on group creation ( POST ).
Provision groups
resourceProvisioningOptions is a string collection that specifies group resources to be
provisioned as part of the Microsoft 365 group. These resources can be specified during
group creation or update.
See also
Overview of Microsoft 365 groups in Microsoft Graph
Microsoft Teams API overview
Overview of group settings
Article • 05/13/2023
Group settings (also called directory settings in beta ) are a collection of settings that
allow you to configure either tenant-wide or object-specific allowed behaviors for
specific Azure AD objects like Microsoft 365 groups.
There are eight groups of setting templates with each setting template including a
collection of individual settings.
Group.Unified
Group.Unified.Guest
Application
Custom Policy Settings
Consent Policy Settings
Password Rule Settings
Prohibited Names Restricted Settings
Prohibited Names Settings
The setting templates are available through the groupSettingTemplates resource type in
v1.0 and directorySettingTemplates resource type in beta . These setting templates are
Initially, Azure AD assigns the default configuration to the tenant and there are no
setting objects. To change the default settings, you must create a new settings object
from a settings template.
From the setting templates, you can configure tenant-wide settings or settings for
individual objects. Use the groupSettings resource type in v1.0 or the directorySetting
resource type in beta and their associated APIs.
For groups, only settings for Microsoft 365 groups are available. The following article
describes only settings that are available for Microsoft 365 groups.
Group.Unified
The settings in this object specify whether guests can be added to all or specific
Microsoft 365 groups in the tenant.
Group.Unified.Guest
The settings in this object specify whether guests can be added to all or specific
Microsoft 365 groups in the tenant.
AllowToAddGuests Boolean Indicates whether guest users can be added to all or specific
Microsoft 365 groups. The default setting is true . This setting can
be overwritten when:
EnableMIPLabels is true and a guest policy is applied when a
sensitivity label is assigned to a group
AllowToAddGuests is false at the tenant-level, the group-
level setting is overwritten
Next steps
groupSettingTemplate resource type
groupSettings resource type
Applications API overview
Article • 01/27/2023
Application management
Application registration involves telling Azure AD about your application, including the
URL where it's located, the URL to send replies after authentication, the URI to identify
your application, and more. You can use the application APIs in Microsoft Graph to
manage applications programmatically.
https://www.youtube-nocookie.com/embed/93j0MmRruFo
Application model
Application and service principal objects in Azure Active Directory
Application types for Microsoft identity platform
For more information about application management, see the following articles:
For more information about on-premises publishing, see the following articles:
To learn about using the on-premises publishing APIs, see the following tutorial and its
associated APIs:
Automate the configuration of Application Proxy using the Microsoft Graph API
applicationTemplate
application
onPremisesPublishing
connector
connectorGroup
servicePrincipal
For more information about service principals, see Application and service principal
objects in Azure Active Directory.
Synchronization
You can use the synchronization APIs in Microsoft Graph to manage identity
synchronization programmatically, including:
To learn about using the synchronization APIs, see the following tutorials and their
associated APIs:
Next steps
Try the Microsoft Graph API in Graph Explorer.
Learn about how to add authentication and authorization to your web applications
and web APIs using these samples.
Manage an Azure AD application using
Microsoft Graph
Article • 03/02/2023
Your app must be registered in Azure AD before the Microsoft identity platform can
authorize it to access data stored in Azure Active Directory (Azure AD) or Microsoft 365
tenants. This condition applies to apps that you develop yourself, that are owned by
your organization, or that you access through an active subscription.
Many settings for apps are recorded as objects that can be accessed, updated, or
deleted using Microsoft Graph. In this article, you'll learn how to use Microsoft Graph to
manage app and service principal objects including the properties, permissions, and role
assignments.
Prerequisites
To complete this tutorial, you need the following resources and privileges:
Request
Least privilege delegated permission: Application.ReadWrite.All
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/applications
Content-type: application/json
{
"displayName": "My application"
}
Response
The following code is an example of the default response that includes all the properties
returned by default. The application is assigned an ID that's globally unique in the Azure
AD ecosystem.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#applications/$entity",
"id": "0d0021e2-eaab-4b9f-a5ad-38c55337d63e",
"deletedDateTime": null,
"appId": "5f0f8757-988d-474c-9f85-74a6bc70dfd0",
"applicationTemplateId": null,
"disabledByMicrosoftStatus": null,
"createdDateTime": "2022-02-08T08:58:36.7669085Z",
"displayName": "My application",
"description": null,
"groupMembershipClaims": null,
"identifierUris": [],
"isDeviceOnlyAuthSupported": null,
"isFallbackPublicClient": null,
"notes": null,
"publisherDomain": "M365x010717.onmicrosoft.com",
"serviceManagementReference": null,
"signInAudience": "AzureADandPersonalMicrosoftAccount",
"tags": [],
"tokenEncryptionKeyId": null,
"defaultRedirectUri": null,
"certification": null,
"optionalClaims": null,
"addIns": [],
"api": {
"acceptMappedClaims": null,
"knownClientApplications": [],
"requestedAccessTokenVersion": 2,
"oauth2PermissionScopes": [],
"preAuthorizedApplications": []
},
"appRoles": [],
"info": {
"logoUrl": null,
"marketingUrl": null,
"privacyStatementUrl": null,
"supportUrl": null,
"termsOfServiceUrl": null
},
"keyCredentials": [],
"parentalControlSettings": {
"countriesBlockedForMinors": [],
"legalAgeGroupRule": "Allow"
},
"passwordCredentials": [],
"publicClient": {
"redirectUris": []
},
"requiredResourceAccess": [],
"verifiedPublisher": {
"displayName": null,
"verifiedPublisherId": null,
"addedDateTime": null
},
"web": {
"homePageUrl": null,
"logoutUrl": null,
"redirectUris": [],
"implicitGrantSettings": {
"enableAccessTokenIssuance": false,
"enableIdTokenIssuance": false
}
},
"spa": {
"redirectUris": []
}
}
in with any account type, including Azure AD accounts, personal Microsoft accounts,
and social media credentials, can use your app. You can change the signInAudience to a
different scope.
If you created the application as a user with administrator privileges, you were
automatically assigned ownership to the application. You can confirm ownership by
retrieving the owners navigation property through GET
https://graph.microsoft.com/v1.0/applications/0d0021e2-eaab-4b9f-a5ad-
38c55337d63e/owners . You can also assign another user or app ownership of the
application.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/0d0021e2-eaab-4b9f-
a5ad-38c55337d63e/
Content-type: application/json
{
"tags": [
"HR",
"Payroll",
"HideApp"
],
"info": {
"logoUrl": "https://cdn.pixabay.com/photo/2016/03/21/23/25/link-
1271843_1280.png",
"marketingUrl": "https://www.contoso.com/app/marketing",
"privacyStatementUrl": "https://www.contoso.com/app/privacy",
"supportUrl": "https://www.contoso.com/app/support",
"termsOfServiceUrl":
"https://www.contoso.com/app/termsofservice"
},
"web": {
"homePageUrl": "https://www.contoso.com/",
"logoutUrl": "https://www.contoso.com/frontchannel_logout",
"redirectUris": [
"https://localhost"
]
},
"serviceManagementReference": "Owners aliases: Finance @
[email protected]; The Phone Company HR consulting @
[email protected];"
}
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/servicePrincipals/89473e09-0737-
41a1-a0c3-1418d6908bcd
{
"appRoleAssignmentRequired": true
}
Assigning permissions doesn't automatically grant them to the app. You must still grant
admin consent using the Azure portal. To grant permissions without interactive consent,
see Grant or revoke API permissions programmatically.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/581088ba-83c5-4975-
b8af-11d2d7a76e98
Content-Type: application/json
{
"requiredResourceAccess": [
{
"resourceAppId": "00000002-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "311a71cc-e848-46a1-bdf8-97ff7156d8e6",
"type": "Scope"
},
{
"id": "3afa6a7d-9b1a-42eb-948e-1650a849e176",
"type": "Role"
}
]
}
]
}
Create app roles
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/bbd46130-e957-4c38-
a116-d4d02afd1057
Content-Type: application/json
{
"appRoles": [
{
"allowedMemberTypes": [
"User",
"Application"
],
"description": "Survey.Read",
"displayName": "Survey.Read",
"id": "7a9ddfc4-cc8a-48ea-8275-8ecbffffd5a0",
"isEnabled": false,
"origin": "Application",
"value": "Survey.Read"
}
]
}
Manage owners
This request requires the ConsistencyLevel header set to eventual because $count is in
the request. For more information about the use of ConsistencyLevel and $count , see
Advanced query capabilities on Azure AD directory objects.
This request also returns the count of the apps that match the filter condition.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/servicePrincipals?
$filter=owners/$count eq 0 or owners/$count eq 1&$count=true
ConsistencyLevel: eventual
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/applications/7b45cf6d-9083-4eb2-
92c4-a7e090f1fc40/owners/$ref
Content-Type: application/json
{
"@odata.id":
"https://graph.microsoft.com/v1.0/directoryObjects/8afc02cb-4d62-4dba-
b536-9f6d73e9be26"
}
The following request references the service principal using its appId. 8afc02cb-4d62-
4dba-b536-9f6d73e9be26 is the object ID for a user or service principal.
HTTP
POST https://graph.microsoft.com/v1.0/servicePrincipals(appId='46e6adf4-
a9cf-4b60-9390-0ba6fb00bf6b')/owners/$ref
Content-Type: application/json
{
"@odata.id":
"https://graph.microsoft.com/v1.0/directoryObjects/8afc02cb-4d62-4dba-b536-
9f6d73e9be26"
}
See also
Properties of an enterprise application (service principal)
Add a certificate to an app using Microsoft Graph
Validation differences by supported
account types (signInAudience)
Article • 04/03/2023
When registering an application with the Microsoft identity platform for developers, you're
asked to select which account types your application supports. You can refer to the Help me
choose link under Supported account types during the registration process. The value you
select for this property has implications on other app object properties.
After the application has been registered, you can check or change the account type that the
application supports at any time. Under the Manage pane of your application, search for
Manifest and find the signInAudience value. The different account types, and the
corresponding signInAudience are shown in the following table:
If you change this property you may need to change other properties first.
Validation differences
See the following table for the validation differences of various properties for different
supported account types.
Certificates ( keyCredentials ) Symmetric signing Symmetric signing Encryption and asymmetric signing
key key key
Scopes defined by this API Maximum scope Maximum scope Maximum scope name length of 40
( oauth2Permissions ) name length of name length of 120 characters
120 characters characters
Maximum of 100 scopes defined
No limit* on the No limit* on the
number of scopes number of scopes
defined defined
http scheme isn't http scheme isn't http scheme isn't allowed
allowed allowed
Maximum length of 255 characters
Maximum length Maximum length of
of 255 characters 255 characters Wildcards aren't supported
Tags Individual tag size Individual tag size Individual tag size must be between
must be between must be between 1 1 and 256 characters (inclusive)
1 and 256 and 256 characters
characters (inclusive) No whitespaces or duplicate tags
(inclusive) allowed
No whitespaces or
No whitespaces or duplicate tags No limit* on number of tags
duplicate tags allowed
allowed
No limit* on number
No limit* on of tags
number of tags
* There's a global limit of about 1000 items across all the collection properties on the app
object.
Next steps
For more information about application registrations and their JSON manifest, see:
Application registration
Application manifest
Grant or revoke API permissions
programmatically
Article • 04/19/2023
When you grant API permissions to a client app in Azure Active Directory (Azure AD),
the permission grants are recorded as objects that can be accessed, updated, or deleted
like your data. Using Microsoft Graph to directly create permission grants is a
programmatic alternative to interactive consent and can be useful for automation
scenarios, bulk management, or other custom operations in your organization.
In this guide, you'll learn how to grant and revoke app roles for an app using Microsoft
Graph. App roles, also called application permissions, or direct access permissions, allow
an app to call an API with its own identity.
U Caution
Prerequisites
To complete these instructions, you need the following resources and privileges:
U Caution
Request
The following request retrieves the app roles defined by the Microsoft Graph service
principal in the tenant.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/servicePrincipals?
$filter=displayName eq 'Microsoft
Graph'&$select=id,displayName,appId,appRoles
Response
The following object is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#servicePrincipals(id,displayName
,appId,appRoles)",
"value": [
{
"id": "7ea9e944-71ce-443d-811c-71e8047b557a",
"displayName": "Microsoft Graph",
"appId": "00000003-0000-0000-c000-000000000000",
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "Allows the app to read user profiles
without a signed in user.",
"displayName": "Read all users' full profiles",
"id": "df021288-bdef-4463-88db-98f22de89214",
"isEnabled": true,
"origin": "Application",
"value": "User.Read.All"
}
]
}
]
}
Request
The following request grants your client app (the principal of ID b0d9b9e3-0ecf-4bfd-
8dab-9273dd055a94 ) an app role of ID df021288-bdef-4463-88db-98f22de89214 that's
exposed by a resource service principal of ID 7ea9e944-71ce-443d-811c-71e8047b557a .
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/servicePrincipals/7ea9e944-71ce-
443d-811c-71e8047b557a/appRoleAssignedTo
Content-Type: application/json
{
"principalId": "b0d9b9e3-0ecf-4bfd-8dab-9273dd055a94",
"resourceId": "7ea9e944-71ce-443d-811c-71e8047b557a",
"appRoleId": "df021288-bdef-4463-88db-98f22de89214"
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#servicePrincipals('7ea9e944-
71ce-443d-811c-71e8047b557a')/appRoleAssignedTo/$entity",
"id": "47nZsM8O_UuNq5Jz3QValCxBBiqJea9Drc9CMK4Ru_M",
"deletedDateTime": null,
"appRoleId": "df021288-bdef-4463-88db-98f22de89214",
"createdDateTime": "2022-05-18T15:37:21.8215423Z",
"principalDisplayName": "My application",
"principalId": "b0d9b9e3-0ecf-4bfd-8dab-9273dd055a94",
"principalType": "ServicePrincipal",
"resourceDisplayName": "Microsoft Graph",
"resourceId": "7ea9e944-71ce-443d-811c-71e8047b557a"
}
To confirm all principals with role assignments to the resource service principal, run the
following request.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/servicePrincipals/7ea9e944-71ce-
443d-811c-71e8047b557a/appRoleAssignedTo
Response
The response object includes a collection of app role assignments to your resource
service principal and includes the app role assignment you created using the POST
request.
HTTP
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#servicePrincipals('7ea9e944-
71ce-443d-811c-71e8047b557a')/appRoleAssignedTo",
"value": [
{
"id": "47nZsM8O_UuNq5Jz3QValCxBBiqJea9Drc9CMK4Ru_M",
"deletedDateTime": null,
"appRoleId": "df021288-bdef-4463-88db-98f22de89214",
"createdDateTime": "2022-05-18T15:37:21.8997216Z",
"principalDisplayName": "My application",
"principalId": "b0d9b9e3-0ecf-4bfd-8dab-9273dd055a94",
"principalType": "ServicePrincipal",
"resourceDisplayName": "Microsoft Graph",
"resourceId": "7ea9e944-71ce-443d-811c-71e8047b557a"
}
]
}
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/servicePrincipals/7ea9e944-71ce-
443d-811c-
71e8047b557a/appRoleAssignedTo/47nZsM8O_UuNq5Jz3QValCxBBiqJea9Drc9CMK4Ru
_M
Response
HTTP
See also
Tutorial: Grant app roles in Azure AD using Microsoft Graph PowerShell
appRoleAssignment resource type
Add a certificate to an app using
Microsoft Graph
Article • 03/02/2023
Azure Active Directory (Azure AD) supports three types of credentials to authenticate
apps and service principals: passwords (app secrets), certificates, and federated identity
credentials. If you can't use federated identity credentials for your app, we strongly
recommend that you use certificates instead of secrets.
You can add or remove certificates using the Azure portal. However, in automation
scenarios, you may need to automate the certificate rollover for your app or service
principal.
This article provides guidance for using Microsoft Graph and PowerShell scripts to
update certificate credentials programmatically for an app registration.
Prerequisites
To complete this tutorial, you need the following resources and privileges:
U Caution
Request
PowerShell
Response
The output that's saved in the .txt file can be similar to the following.
PowerShell
Thumbprint Subject
---------- -------
5A126608ED1A1366F714A4A62B7015F3262840F1 CN=20230112
Request
PowerShell
[convert]::ToBase64String((Get-Content C:\Users\admin\Desktop\20230112.cer -
Encoding byte)) | Out-File -FilePath
"C:\Users\admin\Desktop\20230112.key.txt" ## Replace the file path with the
location of your certificate
Response
The output that's saved in the .txt file can be similar to the following.
Note: The key shown here has been shortened for readability.
PowerShell
MIIDADCCAeigAwIBAgIQP6HEGDdZ65xJTcK4dCBvZzANBgkqhkiG9w0BAQsFADATMREwDwYDVQQD
DAgyMDIzMDExMjAeFw0yMzAxMTIwODExNTZaFw0yNDAxMTIwODMxNTZaMBMxETAPBgNVBAMMCDIw
MjMwMTEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAseKf1weEacJ67D6/...dG+7W
MIBsIUy0xz6MmyvfSohz3oNP4jHt7pJ9TyxnvDlaxQPUbuIL+DaXVkKRm1V3GgIpKTBqMzTf4tCp
y7rpUZbhcwAFw6h9A==
Request
The following request adds the certificate details to an app. The settings are as follows:
The startDateTime is the date when or after the certificate was created.
The endDateTime can be a maximum of one year from the startDateTime. If
unspecified, the system will automatically assign a date one year after the
startDateTime.
The type and usage must be AsymmetricX509Cert and Verify respectively.
Assign the certificate subject name to the displayName property.
The key is the Base64 encoded value that you generated in the previous step.
7 Note
If your app has an existing valid certificate that you want to continue using for
authentication, include both the current and new certificate details in the app's
keyCredentials object. Because this a PATCH call, which by protocol replaces the
contents of the property with the new values, including only the new certificate will
replace the existing certificates with the new one.
The following example adds a new certificate and replaces any existing certificates.
Note: The key shown here has been shortened for readability.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/bb77f42f-dacb-4ece-
b3e6-285e63c24d52
Content-type: application/json
{
"keyCredentials": [
{
"endDateTime": "2024-01-11T15:31:26Z",
"startDateTime": "2023-01-12T15:31:26Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"key":
"base64MIIDADCCAeigAwIBAgIQP6HEGDdZ65xJTcK4dCBvZzANBgkqhkiG9w0BAQsFADATM
REwDwYDVQQDDAgyMDIzMDExMjAeFw0yMzAxMTIwODExNTZaFw0yNDAxMTIwODMxNTZaMBMxE
TAPBgNVBAMMCDIwMjMwMTEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAseKf1
weEacJ67D6/...laxQPUbuIL+DaXVkKRm1V3GgIpKTBqMzTf4tCpy7rpUZbhcwAFw6h9A=="
,
"displayName": "CN=20230112"
}
]
}
The following example adds a new certificate without replacing the existing certificate
that's identified by thumbprint 52ED9B5038A47B9E2E2190715CC238359D4F8F73 .
Note: The key shown here has been shortened for readability.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/bb77f42f-dacb-4ece-
b3e6-285e63c24d52
Content-type: application/json
{
"keyCredentials": [
{
"endDateTime": "2024-01-11T15:31:26Z",
"startDateTime": "2023-01-12T09:31:26Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"key":
"base64MIIDADCCAeigAwIBAgIQejfrj3S974xI//npv7hFHTANBgkqhkiG9w0BAQsFADATM
REwDwYDVQQDDAgyMDIzMDExNDAeFw0yMzAxMTIwOTA4NThaFw0yNDAxMTIwOTI4NThaMBMxE
TAPBgNVBAMMCDIwMjMwMTE0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt5vEj
6j1l5wOVHR4eDGe77HWslaIVJ1NqxrXPm/...+R+U7sboj+kUvmFzXI+Ge73Liu8egL2NzOH
HpO43calWgq36a9YW1yhBQR1ioEchu6jmudW3rF6ktmVqQ==",
"displayName": "CN=20230114"
},
{
"customKeyIdentifier":
"52ED9B5038A47B9E2E2190715CC238359D4F8F73",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"key":
"base64MIIDADCCAeigAwIBAgIQfoIvchhpToxKEPI4iMrU1TANBgkqhkiG9w0BAQsFADATM
REwDwYDVQQDDAgyMDIzMDExMzAeFw0yMzAxMTIwODI3NTJaFw0yNDAxMTIwODQ3NTJaMBMxE
TAPBgNVBAMMCDIwMjMwMTEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+iqg
1nMjYmFcFJh/.../S5X6qoEOyJBgtfpSBANWAdA==",
"displayName": "CN=20230113"
}
]
}
Response
HTTP
Request
PowerShell
To confirm that you're running the Microsoft Graph PowerShell session without a
signed-in user, run the following request.
PowerShell
Get-MgContext
PowerShell
ClientId : cf34b10f-50fd-4167-acf6-4f08ddd4561b
TenantId : 38d49456-54d4-455d-a8d6-c383c71e0a6d
CertificateThumbprint :
Scopes :
AuthType : AppOnly
AuthProviderType : ClientCredentialProvider
CertificateName : CN=20230113
Account :
AppName : testApp
ContextScope : Process
Certificate :
PSHostVersion : 5.1.22621.963
ClientTimeout : 00:05:00
Conclusion
You've used Microsoft Graph to update certificate credentials for an app object. This
process is a programmatic alternative to using the Azure portal. You can also update
certificate credentials for a service principal by following a similar process and calling
the https://graph.microsoft.com/v1.0/servicePrincipals/ endpoint.
Configure SAML-based single sign-on
for your application using the Microsoft
Graph API
Article • 03/02/2023
In this article, you'll learn how to create and configure a SAML-based single sign-on
(SSO) for your application in Azure Active Directory (Azure AD) using the Microsoft
Graph API. The application configuration includes basic SAML URLs, a claims mapping
policy, and using a certificate to add a custom signing key. After the application is
created, you assign a user to it to be an administrator. You then can use a URL to obtain
Azure AD SAML metadata for additional configuration of the application.
This article uses an AWS Azure AD application template as an example, but you can use
the steps in this article for any SAML-based app in the Azure AD Gallery.
Prerequisites
Sign in to an API client such as Graph Explorer , Postman, or create your own
client app to call Microsoft Graph. To call Microsoft Graph APIs in this tutorial, you
need to use an account with the global administrator role.
Grant yourself the following delegated permissions: Application.ReadWrite.All ,
AppRoleAssignment.ReadWrite.All , Policy.Read.All ,
Policy.ReadWrite.ApplicationConfiguration , and User.ReadWrite.All .
To create the application from the gallery, you first get the identifier of the application
template and then use that identifier to create the application.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/applicationTemplates?
$filter=displayName eq 'AWS IAM Identity Center (successor to AWS Single
Sign-On)'
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#applicationTemplates",
"value": [
{
"id": "21ed01d2-ec13-4e9e-86c1-cd546719ebc4",
"displayName": "AWS IAM Identity Center (successor to AWS Single
Sign-On)",
"homePageUrl": "https://aws.amazon.com/",
"supportedSingleSignOnModes": [
"saml",
"external"
],
"supportedProvisioningTypes": [
"sync"
],
"logoUrl": "https://az495088.vo.msecnd.net/app-
logo/awssinglesignon_215.png",
"categories": [
"developerServices",
"itInfrastructure",
"security",
"New"
],
"publisher": "Amazon Web Services, Inc.",
"description": "Federate once to AWS IAM Identity Center
(successor to AWS Single Sign-On) & use it to centrally manage access to
multiple AWS accounts and IAM Identity Center enabled apps. Provision users
via SCIM."
}
]
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/applicationTemplates/21ed01d2-
ec13-4e9e-86c1-cd546719ebc4/instantiate
Content-type: application/json
{
"displayName": "AWS Contoso"
}
7 Note
Allow some time for the app to be provisioned into your Azure AD tenant. It is not
instant. One strategy is to do a GET query on the application or service principal
object every 5-10 seconds until the query is successful.
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.applicationServi
cePrincipal",
"application": {
"id": "a9be408a-6c31-4141-8cea-52fcd4a61be8",
"appId": "17cad0e7-cd2b-4e51-a75d-ba810f3e4045",
"applicationTemplateId": "21ed01d2-ec13-4e9e-86c1-cd546719ebc4",
"createdDateTime": "2021-05-10T20:12:03Z",
"deletedDateTime": null,
"displayName": "AWS Contoso",
"groupMembershipClaims": null,
"identifierUris": [],
"isFallbackPublicClient": false,
"signInAudience": "AzureADMyOrg",
"tags": [],
"tokenEncryptionKeyId": null,
"defaultRedirectUri": null,
"optionalClaims": null,
"verifiedPublisher": {
"displayName": null,
"verifiedPublisherId": null,
"addedDateTime": null
},
"addIns": [],
"api": {
"acceptMappedClaims": null,
"knownClientApplications": [],
"requestedAccessTokenVersion": null,
"oauth2PermissionScopes": [
{
"adminConsentDescription": "Allow the application to access AWS
Contoso on behalf of the signed-in user.",
"adminConsentDisplayName": "Access AWS Contoso",
"id": "6f891cd3-c132-4822-930b-f343b4515d19",
"isEnabled": true,
"type": "User",
"userConsentDescription": "Allow the application to access AWS
Contoso on your behalf.",
"userConsentDisplayName": "Access AWS Contoso",
"value": "user_impersonation"
}
],
"preAuthorizedApplications": []
},
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "User",
"id": "8774f594-1d59-4279-b9d9-59ef09a23530",
"isEnabled": true,
"description": "User",
"value": null,
"origin": "Application"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "msiam_access",
"id": "e7f1a7f3-9eda-48e0-9963-bd67bf531afd",
"isEnabled": true,
"description": "msiam_access",
"value": null,
"origin": "Application"
}
],
"info": {
"logoUrl": null,
"marketingUrl": null,
"privacyStatementUrl": null,
"supportUrl": null,
"termsOfServiceUrl": null
},
"keyCredentials": [],
"parentalControlSettings": {
"countriesBlockedForMinors": [],
"legalAgeGroupRule": "Allow"
},
"passwordCredentials": [],
"publicClient": {
"redirectUris": []
},
"requiredResourceAccess": [],
"web": {
"homePageUrl": "https://*.signin.aws.amazon.com/platform/saml/acs/*?
metadata=awssinglesignon|ISV9.1|primary|z",
"redirectUris": []
}
},
"servicePrincipal": {
"id": "a750f6cf-2319-464a-bcc3-456926736a91",
"deletedDateTime": null,
"accountEnabled": true,
"appId": "17cad0e7-cd2b-4e51-a75d-ba810f3e4045",
"applicationTemplateId": "21ed01d2-ec13-4e9e-86c1-cd546719ebc4",
"appDisplayName": "AWS Contoso",
"alternativeNames": [],
"appOwnerOrganizationId": "8500cad3-193d-48a6-8d00-c129b114dc10",
"displayName": "AWS Contoso",
"appRoleAssignmentRequired": true,
"loginUrl": null,
"logoutUrl": null,
"homepage": "https://*.signin.aws.amazon.com/platform/saml/acs/*?
metadata=awssinglesignon|ISV9.1|primary|z",
"notificationEmailAddresses": [],
"preferredSingleSignOnMode": null,
"preferredTokenSigningKeyThumbprint": null,
"replyUrls": [],
"servicePrincipalNames": [
"17cad0e7-cd2b-4e51-a75d-ba810f3e4045"
],
"servicePrincipalType": "Application",
"tags": [
"WindowsAzureActiveDirectoryIntegratedApp"
],
"tokenEncryptionKeyId": null,
"samlSingleSignOnSettings": null,
"verifiedPublisher": {
"displayName": null,
"verifiedPublisherId": null,
"addedDateTime": null
},
"addIns": [],
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "User",
"id": "8774f594-1d59-4279-b9d9-59ef09a23530",
"isEnabled": true,
"description": "User",
"value": null,
"origin": "Application"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "msiam_access",
"id": "e7f1a7f3-9eda-48e0-9963-bd67bf531afd",
"isEnabled": true,
"description": "msiam_access",
"value": null,
"origin": "Application"
}
],
"info": {
"logoUrl": null,
"marketingUrl": null,
"privacyStatementUrl": null,
"supportUrl": null,
"termsOfServiceUrl": null
},
"keyCredentials": [],
"oauth2PermissionScopes": [
{
"adminConsentDescription": "Allow the application to access AWS
Contoso on behalf of the signed-in user.",
"adminConsentDisplayName": "Access AWS Contoso",
"id": "6f891cd3-c132-4822-930b-f343b4515d19",
"isEnabled": true,
"type": "User",
"userConsentDescription": "Allow the application to access AWS
Contoso on your behalf.",
"userConsentDisplayName": "Access AWS Contoso",
"value": "user_impersonation"
}
],
"passwordCredentials": []
}
}
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/servicePrincipals/a750f6cf-2319-
464a-bcc3-456926736a91
Content-type: application/json
{
"preferredSingleSignOnMode": "saml"
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/a9be408a-6c31-4141-
8cea-52fcd4a61be8
Content-type: application/json
{
"web": {
"redirectUris": [
"https://signin.aws.amazon.com/saml"
]
},
"identifierUris": [
"https://signin.aws.amazon.com/saml"
]
}
Response
HTTP
7 Note
When adding app roles, don't modify the default app roles msiam_access .
Use the id for the service principal that you recorded earlier.
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/serviceprincipals/a750f6cf-2319-
464a-bcc3-456926736a91
Content-type: application/json
{
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "User",
"id": "8774f594-1d59-4279-b9d9-59ef09a23530",
"isEnabled": true,
"description": "User",
"value": null,
"origin": "Application"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "msiam_access",
"id": "e7f1a7f3-9eda-48e0-9963-bd67bf531afd",
"isEnabled": true,
"description": "msiam_access",
"value": null,
"origin": "Application"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Admin,WAAD",
"displayName": "Admin,WAAD",
"id": "3a84e31e-bffa-470f-b9e6-754a61e4dc63",
"isEnabled": true,
"value": "arn:aws:iam::212743507312:role/accountname-aws-
admin,arn:aws:iam::212743507312:saml-provider/WAAD"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Finance,WAAD",
"displayName": "Finance,WAAD",
"id": "7a960000-ded3-455b-8c04-4f2ace00319b",
"isEnabled": true,
"value": "arn:aws:iam::212743507312:role/accountname-aws-
finance,arn:aws:iam::212743507312:saml-provider/WAAD"
}
]
}
Response
HTTP
https://aws.amazon.com/SAML/Attributes/Role assignedroles
https://aws.amazon.com/SAML/Attributes/RoleSessionName userprincipalname
https://aws.amazon.com/SAML/Attributes/SessionDuration "900"
roles assignedroles
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier userprincipalname
7 Note
Some keys in the claims mapping policy are case sensitive (for example, "Version").
If you receive an error message such as "Property has an invalid value", it might be
a case sensitive issue.
Create the claims mapping policy and record the value of the id property to use later in
this tutorial.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/policies/claimsMappingPolicies
Content-type: application/json
{
"definition": [
"{\"ClaimsMappingPolicy\":
{\"Version\":1,\"IncludeBasicClaimSet\":\"true\", \"ClaimsSchema\":
[{\"Source\":\"user\",\"ID\":\"assignedroles\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/Role\"},
{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/RoleSessionName\"},
{\"Value\":\"900\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/SessionDuration\"},
{\"Source\":\"user\",\"ID\":\"assignedroles\",\"SamlClaimType\":
\"appRoles\"},
{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/nameidentifier\"}]}}"
],
"displayName": "AWS Claims Policy",
"isOrganizationDefault": false
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#policies/claimsMappingPolicies/$
entity",
"id": "4bce7ba7-466d-4239-94b8-cf4f21428ca7",
"deletedDateTime": null,
"definition": [
"{\"ClaimsMappingPolicy\":
{\"Version\":1,\"IncludeBasicClaimSet\":\"true\", \"ClaimsSchema\":
[{\"Source\":\"user\",\"ID\":\"assignedroles\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/Role\"},
{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/RoleSessionName\"},
{\"Value\":\"900\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/SessionDuration\"},
{\"Source\":\"user\",\"ID\":\"assignedroles\",\"SamlClaimType\":
\"appRoles\"},
{\"Source\":\"user\",\"ID\":\"userprincipalname\",\"SamlClaimType\":
\"https://aws.amazon.com/SAML/Attributes/nameidentifier\"}]}}"
],
"displayName": "AWS Claims Policy",
"isOrganizationDefault": false
}
Assign a claims mapping policy to a service principal
Use the id for the service principal that you recorded earlier to assign a claims mapping
policy to it. Use the value of the id property for the claims mapping policy in the body of
the request.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/servicePrincipals/a750f6cf-2319-
464a-bcc3-456926736a91/claimsMappingPolicies/$ref
Content-type: application/json
"@odata.id":"https://graph.microsoft.com/v1.0/policies/claimsMappingPoli
cies/a4b35718-fd5e-4ca8-8248-a3c9934b1b78"
}
Response
HTTP
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/servicePrincipals/a750f6cf-2319-
464a-bcc3-456926736a91/addTokenSigningCertificate
Content-type: application/json
{
"displayName":"CN=AWSContoso",
"endDateTime":"2024-01-25T00:00:00Z"
}
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.selfSignedCertif
icate",
"customKeyIdentifier": "p9PEYmuKhP2oaMzGfSdNQC/9ChA=",
"displayName": "CN=AWSContoso",
"endDateTime": "2024-01-25T00:00:00Z",
"key":
"MIICqjCCAZKgAwIBAgIId....4rnrk43wp75yqjRbOhAZ1ExAxVqW+o2JslhjUeltUMNQW+ynOf
s9oHu1ZdnGmxrE=",
"keyId": "70883316-50be-4016-ba80-19d9fbad873d",
"startDateTime": "2021-05-10T20:35:37.5754318Z",
"thumbprint": "A7D3C4626B8A84FDA868CCC67D274D402FFD0A10",
"type": "AsymmetricX509Cert",
"usage": "Verify"
}
PowerShell script
PowerShell
Param(
[Parameter(Mandatory=$true)]
[string]$fqdn,
[Parameter(Mandatory=$true)]
[string]$pwd,
[Parameter(Mandatory=$true)]
[string]$location
)
if (!$PSBoundParameters.ContainsKey('location'))
{
$location = "."
}
After running the previous code, extract the values for the following parameters from
the PFX file. You will add this information to the service principal:
Private key
Password
Public key
For more information about the properties, see keyCredential resource type.
Make sure that the keyId for the keyCredential used for "Sign" matches the keyId of the
passwordCredential. You can generate the customkeyIdentifier by getting the hash of
the cert's thumbprint. See the previous C# reference code.
Request
7 Note
The "key" value in the keyCredentials property is shortened for readability. The
value is base 64 encoded. For the private key the property usage is "Sign". For the
public key the property usage is "Verify".
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/servicePrincipals/f47a6776-bca7-
4f2e-bc6c-eec59d058e3e
Content-type: application/json
{
"keyCredentials":[
{
"customKeyIdentifier":
"lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
"endDateTime": "2021-04-22T22:10:13Z",
"keyId": "4c266507-3e74-4b91-aeba-18a25b450f6e",
"startDateTime": "2020-04-22T21:50:13Z",
"type": "X509CertAndPassword",
"usage": "Sign",
"key":"MIIKIAIBAz.....HBgUrDgMCERE20nuTptI9MEFCh2Ih2jaaLZBZGeZBRFVNXeZmA
AgIH0A==",
"displayName": "CN=awsAPI"
},
{
"customKeyIdentifier":
"lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
"endDateTime": "2021-04-22T22:10:13Z",
"keyId": "e35a7d11-fef0-49ad-9f3e-aacbe0a42c42",
"startDateTime": "2020-04-22T21:50:13Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"key":
"MIIDJzCCAg+gAw......CTxQvJ/zN3bafeesMSueR83hlCSyg==",
"displayName": "CN=awsAPI"
}
],
"passwordCredentials": [
{
"customKeyIdentifier":
"lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
"keyId": "4c266507-3e74-4b91-aeba-18a25b450f6e",
"endDateTime": "2022-01-27T19:40:33Z",
"startDateTime": "2020-04-20T19:40:33Z",
"secretText": "61891f4ee44d"
}
]
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/servicePrincipals/a750f6cf-2319-
464a-bcc3-456926736a91
Content-type: application/json
{
"preferredTokenSigningKeyThumbprint":
"A7D3C4626B8A84FDA868CCC67D274D402FFD0A10"
}
Response
HTTP
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
Content-type: application/json
{
"accountEnabled":true,
"displayName":"MyTestUser1",
"mailNickname":"MyTestUser1",
"userPrincipalName":"[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn":true,
"password":"Contoso1234"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"id": "040f9599-7c0f-4f94-aa75-8394c4c6ea9b",
"businessPhones": [],
"displayName": "MyTestUser1",
"userPrincipalName": "[email protected]"
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/servicePrincipals/a750f6cf-2319-
464a-bcc3-456926736a91/appRoleAssignments
Content-type: application/json
{
"principalId": "040f9599-7c0f-4f94-aa75-8394c4c6ea9b",
"principalType": "User",
"appRoleId":"3a84e31e-bffa-470f-b9e6-754a61e4dc63",
"resourceId":"a750f6cf-2319-464a-bcc3-456926736a91"
}
Response
HTTP
HTTP/1.1 201
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#servicePrincipals('a750f6cf-
2319-464a-bcc3-456926736a91')/appRoleAssignments/$entity",
"id": "mZUPBA98lE-qdYOUxMbqm2qY3odGRGdFtpYJkAfUC0Q",
"deletedDateTime": null,
"appRoleId": "3a84e31e-bffa-470f-b9e6-754a61e4dc63",
"createdDateTime": "2021-05-10T21:04:11.0480851Z",
"principalDisplayName": "MyTestUser1",
"principalId": "040f9599-7c0f-4f94-aa75-8394c4c6ea9b",
"principalType": "User",
"resourceDisplayName": "AWS Contoso",
"resourceId": "a750f6cf-2319-464a-bcc3-456926736a91"
}
Step 6: Get Azure AD SAML metadata
Use the following URL to get the Azure AD SAML metadata for the specific configured
application. The metadata contains information such as the signing certificate, Azure AD
entityID, and Azure AD SingleSignOnService, among others.
https://login.microsoftonline.com/{tenant-id}/federationmetadata/2007-
06/federationmetadata.xml?appid={app-id}
The following shows an example of what you might see for your application:
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
ID="_05fbbf53-e892-43c9-9300-1f6738ace02c"
entityID="https://sts.windows.net/2f82f566-5953-43f4-9251-79c6009bdf24/">
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
...
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-
Redirect" Location="https://login.microsoftonline.com/2f82f566-5953-43f4-
9251-79c6009bdf24/saml2"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-
Redirect" Location="https://login.microsoftonline.com/2f82f566-5953-43f4-
9251-79c6009bdf24/saml2"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-
POST" Location="https://login.microsoftonline.com/2f82f566-5953-43f4-9251-
79c6009bdf24/saml2"/>
</IDPSSODescriptor>
</EntityDescriptor>
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/applications/a9be408a-6c31-4141-
8cea-52fcd4a61be8
Response
HTTP
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/users/040f9599-7c0f-4f94-aa75-
8394c4c6ea9b
Response
HTTP
Request
HTTP
HTTP
DELETE
https://graph.microsoft.com/v1.0/policies/claimsMappingPolicies/a4b35718
-fd5e-4ca8-8248-a3c9934b1b78
Response
HTTP
See also
For AWS, you can enable user provisioning to fetch all the roles from that AWS
account. For more information, see Configure the role claim issued in the SAML
token.
Customize claims emitted in tokens for a specific app in a tenant.
You can use the applicationTemplate API to instantiate Non-Gallery apps. Use
applicationTemplateId 8adf8e6e-67b2-4cf2-a259-e3dc5476c621 .
applicationTemplate
appRoleAssignment
servicePrincipal
application
claimsMappingPolicy
keyCredential
addTokenSigningCertificate
Configure Application Proxy using the
Microsoft Graph API
Article • 03/02/2023
In this article, you'll learn how to configure Azure Active Directory (Azure AD)
Application Proxy for an application. Application Proxy provides secure remote access
and single sign-on to on-premises web applications. After configuring Application Proxy
for an application, users can access their on-premises applications through an external
URL, the My Apps portal, or other internal application portals.
Prerequisites
This tutorial assumes you have already installed a connector and completed the
prerequisites for Application Proxy so that connectors can communicate with
Azure AD services.
Sign in to an API client such as Graph Explorer , Postman, or create your own
client app to call Microsoft Graph. To call Microsoft Graph APIs in this tutorial, you
need to use an account with the global administrator role.
Grant yourself the following delegated permission: Directory.ReadWrite.All .
7 Note
Record the id, appId, servicePrincipalId of the application to use later in the tutorial.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/applicationTemplates/8adf8e6e-
67b2-4cf2-a259-e3dc5476c621/instantiate
Content-type: application/json
{
"displayName": "Contoso IWA App"
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#applications/$entity",
"id": "bf21f7e9-9d25-4da2-82ab-7fdd85049f83",
"deletedDateTime": null,
"addIns": [],
"appId": "d7fbfe28-c60e-46d2-8335-841923950d3b",
"applicationTemplateId": null,
"identifierUris": [],
"createdDateTime": "2020-08-11T21:07:47.5919755Z",
"description": null,
"displayName": "Contoso IWA App",
"isAuthorizationServiceEnabled": false,
"isDeviceOnlyAuthSupported": null,
"isFallbackPublicClient": null,
"groupMembershipClaims": null,
"notes": null,
"optionalClaims": null,
"orgRestrictions": [],
"publisherDomain": "f128.info",
"signInAudience": "AzureADandPersonalMicrosoftAccount",
"tags": [],
"tokenEncryptionKeyId": null,
"uniqueName": null,
"verifiedPublisher": {
"displayName": null,
"verifiedPublisherId": null,
"addedDateTime": null
},
}
Step 2: Configure Application Proxy
Insert the id that you recorded for the application into the URL to start the configuration
of Application Proxy. In this example, you're using an app with the internal URL:
https://contosoiwaapp.com . You also use the default domain for the external URL:
https://contosoiwaapp-contoso.msappproxy.net . Update the following properties in the
request body:
identifierUri, redirectUri, and homepageUrl - Set each to the same external URL.
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/applications/bf21f7e9-9d25-4da2-
82ab-7fdd85049f83
Content-type: application/json
{
"identifierUris": [
"https://contosoiwaapp-contoso.msappproxy.net"
],
"web": {
"redirectUris": [
"https://contosoiwaapp-contoso.msappproxy.net"
],
"homePageUrl": "https://contosoiwaapp-contoso.msappproxy.net"
}
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/beta/applications/bf21f7e9-9d25-4da2-
82ab-7fdd85049f83
Content-type: application/json
{
"onPremisesPublishing": {
"externalAuthenticationType": "aadPreAuthentication",
"internalUrl": "https://contosoiwaapp.com",
"externalUrl": "https://contosoiwaapp-contoso.msappproxy.net",
"isHttpOnlyCookieEnabled": true,
"isOnPremPublishingEnabled": true,
"isPersistentCookieEnabled": true,
"isSecureCookieEnabled": true,
"isStateSessionEnabled": true,
"isTranslateHostHeaderEnabled": true,
"isTranslateLinksInBodyEnabled": true
}
}
Response
HTTP
Get connectors
List the connectors that are available. Record the id of the connector that you want to
assign to a connector group.
Request
HTTP
HTTP
GET
https://graph.microsoft.com/beta/onPremisesPublishingProfiles/applicatio
nProxy/connectors
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#connectors",
"value": [
{
"id": "d2b1e8e8-8511-49d6-a4ba-323cb083fbb0",
"machineName": "connectorA.redmond.contoso.com"",
"externalIp": "131.137.147.164",
"status": "active"
},
{
"id": "f2cab422-a1c8-4d70-a47e-2cb297a2e051",
"machineName": "connectorB.contoso.com"",
"externalIp": "68.0.191.210",
"status": "active"
}
]
}
Create a connectorGroup
For this example, a new connectorGroup is created named IWA Demo Connector Group
that is used for the application. Record the id that is returned to use in the next step.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/beta/onPremisesPublishingProfiles/applicatio
nProxy/connectorGroups
Content-type: application/json
{
"name": "IWA Demo Connector Group"
}
Response
HTTP
HTTP/1.1 201
Content-type: connectorGroup/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#connectorGroups/$entity",
"id": "3e6f4c35-a04b-4d03-b98a-66fff89b72e6",
"name": "IWA Demo Connector Group",
"connectorGroupType": "applicationProxy",
"isDefault": false
}
Request
HTTP
HTTP
POST
https://graph.microsoft.com/beta/onPremisesPublishingProfiles/applicatio
nProxy/connectors/f2cab422-a1c8-4d70-a47e-2cb297a2e051/memberOf/$ref
Content-type: application/json
"@odata.id":"https://graph.microsoft.com/beta/onPremisesPublishingProfil
es/applicationProxy/connectorGroups/3e6f4c35-a04b-4d03-b98a-
66fff89b72e6"
}
Response
HTTP
Request
HTTP
HTTP
PUT https://graph.microsoft.com/beta/applications/bf21f7e9-9d25-4da2-
82ab-7fdd85049f83/connectorGroup/$ref
Content-type: application/json
{
"@odata.id":"https://graph.microsoft.com/onPremisesPublishingProfiles/ap
plicationproxy/connectorGroups/3e6f4c35-a04b-4d03-b98a-66fff89b72e6"
}
Response
HTTP
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/beta/applications/bf21f7e9-9d25-4da2-
82ab-7fdd85049f83
Content-type: appplication/json
{
"onPremisesPublishing": {
"singleSignOnSettings": {
"kerberosSignOnSettings": {
"kerberosServicePrincipalName": "HTTP/iwademo.contoso.com",
"kerberosSignOnMappingAttributeType": "userPrincipalName"
},
"singleSignOnMode": "onPremisesKerberos"
}
}
}
Response
HTTP
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/servicePrincipals/a8cac399-cde5-
4516-a674-819503c61313/appRoles
Response
HTTP
HTTP/1.1 200
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#servicePrincipals('a8cac399-
cde5-4516-a674-819503c61313')/appRoles",
"value": [
{
"allowedMemberTypes": [
"User"
],
"description": "User",
"displayName": "User",
"id": "18d14569-c3bd-439b-9a66-3a2aee01d14f",
"isEnabled": true,
"origin": "Application",
"value": null
},
]
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/users
Content-type: application/json
{
"accountEnabled":true,
"displayName":"MyTestUser1",
"mailNickname":"MyTestUser1",
"userPrincipalName":"[email protected]",
"passwordProfile": {
"forceChangePasswordNextSignIn":true,
"password":"Contoso1234"
}
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"id": "4628e7df-dff3-407c-a08f-75f08c0806dc",
"businessPhones": [],
"displayName": "MyTestUser1",
"givenName": null,
"jobTitle": null,
"mail": null,
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "[email protected]"
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/servicePrincipals/b00c693f-9658-
4c06-bd1b-c402c4653dea/appRoleAssignments
Content-type: appRoleAssignments/json
{
"principalId": "4628e7df-dff3-407c-a08f-75f08c0806dc",
"principalType": "User",
"appRoleId":"18d14569-c3bd-439b-9a66-3a2aee01d14f",
"resourceId":"a8cac399-cde5-4516-a674-819503c61313"
}
Response
HTTP
HTTP/1.1 200
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#appRoleAssignments/$entity",
"id": "I23pL8ZdNU-CIgQmqMEVyLJ0E6fx0ixEo92az8MnhtU",
"creationTimestamp": "2020-06-09T00:06:07.5129268Z",
"appRoleId": "18d14569-c3bd-439b-9a66-3a2aee01d14f",
"principalDisplayName": "MyTestUser1",
"principalId": "2fe96d23-5dc6-4f35-8222-0426a8c115c8",
"principalType": "User",
"resourceDisplayName": "Contoso IWA App",
"resourceId": "a8cac399-cde5-4516-a674-819503c61313"
}
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/users/4628e7df-dff3-407c-a08f-
75f08c0806dc
Response
HTTP
No Content - 204
Request
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/applications/bf21f7e9-9d25-4da2-
82ab-7fdd85049f83
Response
HTTP
No Content - 204
Request
HTTP
HTTP
DELETE
https://graph.microsoft.com/beta/onPremisesPublishingProfiles/applicatio
nProxy/connectorGroups/3e6f4c35-a04b-4d03-b98a-66fff89b72e6
Response
HTTP
No Content - 204
See also
Application Proxy
application
Configure provisioning using Microsoft
Graph APIs
Article • 10/12/2022
The Azure portal is a convenient way to configure provisioning for individual apps one
at a time. But if you're creating several—or even hundreds—of instances of an
application, it can be easier to automate app creation and configuration with the
Microsoft Graph APIs. This article outlines how to automate provisioning configuration
through APIs. This method is commonly used for applications like Amazon Web
Services.
Step Details
Step 2. Create provisioning job based on Retrieve the template for the provisioning
template connector
Create the provisioning job
Request
HTTP
GET https://graph.microsoft.com/beta/applicationTemplates?
$filter=displayName eq 'AWS Single-Account Access'
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"value": [
{
"id": "8b1025e4-1dd2-430b-a150-2ef79cd700f5",
"displayName": "AWS Single-Account Access",
"homePageUrl": "http://aws.amazon.com/",
"supportedSingleSignOnModes": [
"password",
"saml",
"external"
],
"supportedProvisioningTypes": [
"sync"
],
"logoUrl": "https://az495088.vo.msecnd.net/app-logo/aws_215.png",
"categories": [
"developerServices"
],
"publisher": "Amazon",
"description": "Federate to a single AWS account and use SAML
claims to authorize access to AWS IAM roles. If you have many AWS accounts,
consider using the AWS Single Sign-On gallery application instead."
}
Create the gallery application
Use the template ID retrieved for your application in the last step to create an instance
of the application and service principal in your tenant.
Request
HTTP
POST https://graph.microsoft.com/beta/applicationTemplates/{id}/instantiate
Content-type: application/json
{
"displayName": "AWS Contoso"
}
Response
HTTP
HTTP/1.1 201 OK
Content-type: application/json
{
"application": {
"objectId": "cbc071a6-0fa5-4859-8g55-e983ef63df63",
"appId": "92653dd4-aa3a-3323-80cf-e8cfefcc8d5d",
"applicationTemplateId": "8b1025e4-1dd2-430b-a150-2ef79cd700f5",
"displayName": "AWS Contoso",
"homepage": "https://signin.aws.amazon.com/saml?
metadata=aws|ISV9.1|primary|z",
"replyUrls": [
"https://signin.aws.amazon.com/saml"
],
"logoutUrl": null,
"samlMetadataUrl": null,
},
"servicePrincipal": {
"objectId": "f47a6776-bca7-4f2e-bc6c-eec59d058e3e",
"appDisplayName": "AWS Contoso",
"applicationTemplateId": "8b1025e4-1dd2-430b-a150-2ef79cd700f5",
"appRoleAssignmentRequired": true,
"displayName": "My custom name",
"homepage": "https://signin.aws.amazon.com/saml?
metadata=aws|ISV9.1|primary|z",
"replyUrls": [
"https://signin.aws.amazon.com/saml"
],
"servicePrincipalNames": [
"93653dd4-aa3a-4323-80cf-e8cfefcc8d7d"
],
"tags": [
"WindowsAzureActiveDirectoryIntegratedApp"
],
}
}
Request
HTTP
GET
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/temp
lates
Response
HTTP
HTTP/1.1 200 OK
{
"value": [
{
"id": "aws",
"factoryTag": "aws",
"schema": {
"directories": [],
"synchronizationRules": []
}
}
]
}
Create the provisioning job
To enable provisioning, you'll first need to create a job. Use the following request to
create a provisioning job. Use the templateId from the previous step when specifying
the template to be used for the job.
Request
HTTP
POST
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/jobs
Content-type: application/json
{
"templateId": "aws"
}
Response
HTTP
HTTP/1.1 201 OK
Content-type: application/json
{
"id": "{jobId}",
"templateId": "aws",
"schedule": {
"expiration": null,
"interval": "P10675199DT2H48M5.4775807S",
"state": "Disabled"
},
"status": {
"countSuccessiveCompleteFailures": 0,
"escrowsPruned": false,
"synchronizedEntryCountByType": [],
"code": "NotConfigured",
"lastExecution": null,
"lastSuccessfulExecution": null,
"lastSuccessfulExecutionWithExports": null,
"steadyStateFirstAchievedTime": "0001-01-01T00:00:00Z",
"steadyStateLastAchievedTime": "0001-01-01T00:00:00Z",
"quarantine": null,
"troubleshootingUrl": null
}
}
Step 3: Authorize access
Request
HTTP
POST
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/jobs
/{id}/validateCredentials
{
"credentials": [
{
"key": "ClientSecret", "value": "xxxxxxxxxxxxxxxxxxxxx"
},
{
"key": "SecretToken", "value": "xxxxxxxxxxxxxxxxxxxxx"
}
]
}
Response
HTTP
Request
HTTP
PUT
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/secr
ets
{
"value": [
{
"key": "ClientSecret", "value": "xxxxxxxxxxxxxxxxxxxxx"
},
{
"key": "SecretToken", "value": "xxxxxxxxxxxxxxxxxxxxx"
}
]
}
Response
HTTP
Request
HTTP
POST
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/jobs
/{jobId}/start
Response
HTTP
Request
HTTP
GET
https://graph.microsoft.com/beta/servicePrincipals/{id}/synchronization/jobs
/{jobId}/
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"id": "{jobId}",
"templateId": "aws",
"schedule": {
"expiration": null,
"interval": "P10675199DT2H48M5.4775807S",
"state": "Disabled"
},
"status": {
"countSuccessiveCompleteFailures": 0,
"escrowsPruned": false,
"synchronizedEntryCountByType": [],
"code": "Paused",
"lastExecution": null,
"lastSuccessfulExecution": null,
"progress": [],
"lastSuccessfulExecutionWithExports": null,
"steadyStateFirstAchievedTime": "0001-01-01T00:00:00Z",
"steadyStateLastAchievedTime": "0001-01-01T00:00:00Z",
"quarantine": null,
"troubleshootingUrl": null
},
"synchronizationJobSettings": [
{
"name": "QuarantineTooManyDeletesThreshold",
"value": "500"
}
]
}
Request
HTTP
GET https://graph.microsoft.com/beta/auditLogs/provisioning
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#auditLogs/provisioning",
"value": [
{
"id": "gc532ff9-r265-ec76-861e-42e2970a8218",
"activityDateTime": "2019-06-24T20:53:08Z",
"tenantId": "7928d5b5-7442-4a97-ne2d-66f9j9972ecn",
"cycleId": "44576n58-v14b-70fj-8404-3d22tt46ed93",
"changeId": "eaad2f8b-e6e3-409b-83bd-e4e2e57177d5",
"action": "Create",
"durationInMilliseconds": 2785,
"sourceSystem": {
"id": "0404601d-a9c0-4ec7-bbcd-02660120d8c9",
"displayName": "Azure Active Directory",
"details": {}
},
"targetSystem": {
"id": "cd22f60b-5f2d-1adg-adb4-76ef31db996b",
"displayName": "AWS Contoso",
"details": {
"ApplicationId": "f2764360-e0ec-5676-711e-cd6fc0d4dd61",
"ServicePrincipalId": "chc46a42-966b-47d7-9774-
576b1c8bd0b8",
"ServicePrincipalDisplayName": "AWS Contoso"
}
},
"initiatedBy": {
"id": "",
"displayName": "Azure AD Provisioning Service",
"initiatorType": "system"
}
]
}
]
}
See also
Review the synchronization Microsoft Graph documentation
Integrating a custom SCIM app with Azure AD
Generate proof of possession tokens for
rolling keys
Article • 05/25/2023
You can use the addKey and removeKey methods defined on the application and
servicePrincipal resources to roll expiring keys programmatically.
As part of the request validation for these methods, a proof of possession of an existing
key is verified before the methods can be invoked. The proof is represented by a self-
signed JWT token. This JWT token must be signed using the private key of one of the
application's existing valid certificates. The token lifespan should not exceed 10 minutes.
Note: Applications that don't have any existing valid certificates (no certificates have
been added yet, or all certificates have expired), can't use this service action. You can
use the Update application operation to perform an update instead.
the appId).
nbf - Not before time.
You can use the following code examples to generate this proof of possession token.
C#
C#
using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.JsonWebTokens;
namespace MicrosoftIdentityPlatformProofTokenGenerator
{
class Program
{
static void Main(string[] args)
{
// Configure the following
string pfxFilePath = "<Path to your certificate file";
string password = "<Certificate password>";
string objectId = "<id of the application or
servicePrincipal object>";
// audience
string aud = $"00000003-0000-0000-c000-000000000000";
You can also generate the proof using signature in Azure KeyVault. It is important to
note that padding character '=' must not be included in the JWT header and payload or
an Authentication_MissingOrMalformed error will be returned.
Next steps
Now that you have your proof of possession token, you can use it to:
Namespace: microsoft.graph
You can customize your synchronization schema to include custom attributes that are
defined in the target directory. This article describes how to customize a Salesforce
subscription by adding a new field called officeCode . You set up synchronization from
Azure Active Directory (Azure AD) to Salesforce, and for each user, you will populate the
officeCode field in Salesforce with the value from the extensionAttribute10 field in
Azure AD.
This article assumes that you have already added an application that supports
synchronization to your tenant through the Azure Portal , that you know the
application display name, and that you have an authorization token for Microsoft Graph.
For information about how to get the authorization token, see Get access tokens to call
Microsoft Graph.
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/servicePrincipals?
$select=id,appId,displayName&$filter=startswith(displayName,
'salesforce')
Authorization: Bearer {Token}
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#servicePrincipals(id,appId,displ
ayName)",
"value": [
{
"id": "167e33e9-f80e-490e-b4d8-698d4a80fb3e",
"appId": "cd3ed3de-93ee-400b-8b19-b61ef44a0f29",
"displayName": "Salesforce"
},
{
"id": "8cbbb70b-7290-42da-83ee-89fa3517a977",
"appId": "b0f2e3b1-fe31-4658-b216-44dcaeabb63a",
"displayName": "salesforce 1"
},
{
"id": "60443998-8cf7-4e61-b05c-a53b658cb5e1",
"appId": "79079396-c301-405d-900f-e2e0c2439a90",
"displayName": "Salesforce Sandbox"
}
]
}
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/servicePrincipals/60443998-8cf7-
4e61-b05c-a53b658cb5e1/synchronization/jobs
Authorization: Bearer {Token}
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#servicePrincipals('60443998-
8cf7-4e61-b05c-a53b658cb5e1')/synchronization/jobs",
"value": [
{
"id": "SfSandboxOutDelta.e4bbf44533ea4eabb17027f3a92e92aa",
"templateId": "SfSandboxOutDelta",
"schedule": {},
"status": {}
}
]
}
HTTP
HTTP
GET
https://graph.microsoft.com/beta/servicePrincipals/{servicePrincipalId}/
synchronization/jobs/{jobId}/schema
Authorization: Bearer {Token}
Note: The response object shown here might be shortened for readability. All the
properties will be returned in an actual call.
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"directories": [
{
"id": "66e4a8cc-1b7b-435e-95f8-f06cea133828",
"name": "Azure Active Directory",
"objects": [
{
"attributes": [
{
"anchor": true,
"caseExact": false,
"defaultValue": null,
"metadata": [],
"multivalued": false,
"mutability": "ReadWrite",
"name": "objectId",
"required": false,
"referencedObjects": [],
"type": "String"
},
{
"anchor": false,
"caseExact": false,
"defaultValue": null,
"metadata": [],
"multivalued": false,
"mutability": "ReadWrite",
"name": "streetAddress",
"required": false,
"referencedObjects": [],
"type": "String"
}
],
"name": "User"
}
]
},
{
"id": "8ffa6169-f354-4751-9b77-9c00765be92d",
"name": "salesforce.com",
"objects": []
}
],
"synchronizationRules": [
{
"editable": true,
"id": "4c5ecfa1-a072-4460-b1c3-4adde3479854",
"name": "USER_OUTBOUND_USER",
"objectMappings": [
{
"attributeMappings": [
{
"defaultValue": "True",
"exportMissingReferences": false,
"flowBehavior": "FlowWhenChanged",
"flowType": "Always",
"matchingPriority": 0,
"source": {
"expression": "Not([IsSoftDeleted])",
"name": "Not",
"parameters": [
{
"key": "source",
"value": {
"expression": "[IsSoftDeleted]",
"name": "IsSoftDeleted",
"parameters": [],
"type": "Attribute"
}
}
],
"type": "Function"
},
"targetAttributeName": "IsActive"
}
],
"enabled": true,
"flowTypes": "Add, Update, Delete",
"name": "Synchronize Azure Active Directory Users to
salesforce.com",
"scope": null,
"sourceObjectName": "User",
"targetObjectName": "User"
}
]
}
]
}
Under directories, find the directory with the name salesforce.com, and in the
object's array, find the one named User.
Add the new attribute to the list, specifying the name and type, as shown in
the following example.
JSON
{
"directories": [
{
"id": "8ffa6169-f354-4751-9b77-9c00765be92d",
"name": "salesforce.com",
"objects": [
{
"attributes": [
{
"name": "officeCode",
"type": "String"
}
],
"name":"User"
}]
}
],
"synchronizationRules": [
{
"editable": true,
"id": "4c5ecfa1-a072-4460-b1c3-4adde3479854",
"name": "USER_OUTBOUND_USER",
"objectMappings": [
{
"attributeMappings": [
{
"source": {
"name": "extensionAttribute10",
"type": "Attribute"
},
"targetAttributeName": "officeCode"
}
],
"name": "Synchronize Azure Active Directory Users to
salesforce.com",
"scope": null,
"sourceObjectName": "User",
"targetObjectName": "User"
}
],
"priority": 1,
"sourceDirectoryName": "Azure Active Directory",
"targetDirectoryName": "salesforce.com"
}
]
}
HTTP
HTTP
PUT
https://graph.microsoft.com/beta/servicePrincipals/{servicePrincipalId}/
synchronization/jobs/{jobId}/schema
Authorization: Bearer {Token}
{
"directories": [..],
"synchronizationRules": [..]
}
If the schema was saved successfully, the request returns a 204 No Content response
code. On the next iteration of the synchronization job, it will start re-processing all the
accounts in your Azure AD, and the new mappings will be applied to all provisioned
accounts.
Configure synchronization with
directory extension attributes
Article • 03/09/2023
Namespace: microsoft.graph
You can customize your synchronization schema to include Azure Active Directory
(Azure AD) directory extension attributes. This article describes how to use a directory
extension attribute (extension_9d98asdfl15980a_Nickname) to populate the value of
User.CommunityNickname in Salesforce. In this scenario, you have Azure AD Connect
set up to provision a number of directory extension attributes from Windows Server
Active Directory on-premises to Azure AD.
This article assumes that you have already added an application that supports
synchronization to your tenant through the Azure Portal , that you know the
application display name, and that you have an authorization token for Microsoft Graph.
For information about how to get the authorization token, see Get access tokens to call
Microsoft Graph.
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/servicePrincipals?
$select=id,appId,displayName&$filter=startswith(displayName,
'salesforce')
Authorization: Bearer {Token}
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#servicePrincipals(id,appId,displ
ayName)",
"value": [
{
"id": "167e33e9-f80e-490e-b4d8-698d4a80fb3e",
"appId": "cd3ed3de-93ee-400b-8b19-b61ef44a0f29",
"displayName": "Salesforce"
},
{
"id": "8cbbb70b-7290-42da-83ee-89fa3517a977",
"appId": "b0f2e3b1-fe31-4658-b216-44dcaeabb63a",
"displayName": "salesforce 1"
},
{
"id": "60443998-8cf7-4e61-b05c-a53b658cb5e1",
"appId": "79079396-c301-405d-900f-e2e0c2439a90",
"displayName": "Salesforce Sandbox"
}
]
}
Request
HTTP
HTTP
GET https://graph.microsoft.com/beta/servicePrincipals/60443998-8cf7-
4e61-b05c-a53b658cb5e1/synchronization/jobs
Authorization: Bearer {Token}
Response
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#servicePrincipals('60443998-
8cf7-4e61-b05c-a53b658cb5e1')/synchronization/jobs",
"value": [
{
"id": "SfSandboxOutDelta.e4bbf44533ea4eabb17027f3a92e92aa",
"templateId": "SfSandboxOutDelta",
"schedule": {},
"status": {}
}
]
}
HTTP
HTTP
GET
https://graph.microsoft.com/beta/servicePrincipals/{servicePrincipalId}/
synchronization/jobs/{jobId}/schema
Authorization: Bearer {Token}
Note: The response object shown here might be shortened for readability. All the
properties will be returned in an actual call.
HTTP
HTTP/1.1 200 OK
Content-Type: application/json
{
"directories": [
{
"id": "66e4a8cc-1b7b-435e-95f8-f06cea133828",
"name": "Azure Active Directory",
"objects": [
{
"attributes": [
{
"anchor": true,
"caseExact": false,
"defaultValue": null,
"metadata": [],
"multivalued": false,
"mutability": "ReadWrite",
"name": "objectId",
"required": false,
"referencedObjects": [],
"type": "String"
},
{
"anchor": false,
"caseExact": false,
"defaultValue": null,
"metadata": [],
"multivalued": false,
"mutability": "ReadWrite",
"name": "streetAddress",
"required": false,
"referencedObjects": [],
"type": "String"
}
],
"name": "User"
}
]
},
{
"id": "8ffa6169-f354-4751-9b77-9c00765be92d",
"name": "salesforce.com",
"objects": []
}
],
"synchronizationRules": [
{
"editable": true,
"id": "4c5ecfa1-a072-4460-b1c3-4adde3479854",
"name": "USER_OUTBOUND_USER",
"objectMappings": [
{
"attributeMappings": [
{
"defaultValue": "True",
"exportMissingReferences": false,
"flowBehavior": "FlowWhenChanged",
"flowType": "Always",
"matchingPriority": 0,
"source": {
"expression": "Not([IsSoftDeleted])",
"name": "Not",
"parameters": [
{
"key": "source",
"value": {
"expression": "[IsSoftDeleted]",
"name": "IsSoftDeleted",
"parameters": [],
"type": "Attribute"
}
}
],
"type": "Function"
},
"targetAttributeName": "IsActive"
}
],
"enabled": true,
"flowTypes": "Add, Update, Delete",
"name": "Synchronize Azure Active Directory Users to
salesforce.com",
"scope": null,
"sourceObjectName": "User",
"targetObjectName": "User"
}
]
}
]
}
Under directories, find the directory with the name "Azure Active Directory",
and in the object's array, find the one named User.
Add the new attribute to the list, specifying the name and type, as shown in
the following example.
JSON
{
"directories": [
{
"id": "66e4a8cc-1b7b-435e-95f8-f06cea133828",
"name": "Azure Active Directory",
"objects": [
{
"attributes": [
,{
"name":
"extension_9d98asdfl15980a_Nickname",
"type": "String"
}
],
"name":"User"
}]
}
],
"synchronizationRules": [
{
"editable": true,
"id": "4c5ecfa1-a072-4460-b1c3-4adde3479854",
"metadata": [..],
"name": "USER_OUTBOUND_USER",
"objectMappings": [
{
"attributeMappings": [
,{
"source": {
"name": "extension_9d98asdfl15980a_Nickname",
"type": "Attribute"
},
"targetAttributeName": "CommunityNickname"
}
],
"name": "Synchronize Azure Active Directory Users to
salesforce.com",
"scope": null,
"sourceObjectName": "User",
"targetObjectName": "User"
}
],
"priority": 1,
"sourceDirectoryName": "Azure Active Directory",
"targetDirectoryName": "salesforce.com"
},
]
}
HTTP
PUT
https://graph.microsoft.com/beta/servicePrincipals/{servicePrincipalId}/sync
hronization/jobs/{jobId}/schema
Authorization: Bearer {Token}
{
"directories": [],
"synchronizationRules": []
}
If the schema was saved successfully, the request returns a 204 No Content response
code. On the next iteration of the synchronization job, it will start re-processing all the
accounts in your Azure AD, and the new mappings will be applied to all provisioned
accounts.
Overview of Microsoft Graph Data
Connect
Article • 09/08/2022
Microsoft Graph Data Connect augments Microsoft Graph’s transactional model with an
intelligent way to access rich data at scale. The data covers how workers communicate,
collaborate, and manage their time across all the applications and services in Microsoft
365.
Ideal for big data and machine learning, Data Connect lets you develop applications for
analytics, intelligence, and business process optimization by extending Microsoft 365
data into Azure. By integrating in this way, you can take advantage of the vast suite of
compute and storage options in Azure while staying compliant with industry standards
and keeping your data secure.
Microsoft Graph Data Connect uses Azure Synapse or Azure Data Factory to copy
Microsoft 365 data to your application’s storage at configurable intervals. It also
provides a set of tools to streamline the delivery of this data to Microsoft Azure, letting
you access the most applicable development and hosting tools available.
Data Connect also grants a more granular control and consent model: you can manage
data, see who is accessing it, and request specific properties of an entity. This enhances
the Microsoft Graph model, which grants or denies applications access to entire entities.
You can use Data Connect to enable machine learning scenarios for your organization.
In these scenarios, you can create applications that provide valuable information to your
stakeholders, train machine learning models, and even perform forecasting based on
large amounts of acquired data.
https://www.microsoft.com/en-us/videoplayer/embed/RWEJsy?
autoplay=false&postJsllMsg=true
You can take advantage of Microsoft Graph Data Connect if you agree to the Microsoft
APIs Terms of Use and the Microsoft Privacy Statement , and you are:
Microsoft Graph Data Connect resolves this challenge by accessing data in bulk and
repeatedly copying Microsoft 365 data to your application by using Azure Synapse or
Azure Data Factory. Data Connect also lets you choose between accessing data from
everyone in your organization or just specific groups of people.
Microsoft Graph Data Connect enables more granular consent, allowing applications to
request access to specific properties in an entity or filter the data in those properties.
Administrators must give explicit approval before Microsoft Graph data can be accessed.
The request must specify the level of access requested, data policy enforcement, the
reason for the request, and the schema of the data requested. As a result, applications
can only use data that is essential to their function, and any unrelated content is
excluded. For example, an app might consume email metadata but exclude body
content and attachments.
To minimize compliance management overhead for apps that you build with Data
Connect, you can specify a set of detailed policies that you intend to comply with, which
Microsoft 365 administrators can then review. After consent is given for these policies,
Microsoft monitors the application’s adherence to policy. If an application violates (or
attempts to violate) a policy established by the organization, Microsoft stops the flow of
data to that application.
See also
Build your first Microsoft Graph Data Connect application (tutorial)
Data Connect frequently asked questions
Datasets, regions, and sinks
Datasets, regions, and sinks supported
by Microsoft Graph Data Connect
Article • 04/29/2023
Microsoft Graph Data Connect supports a variety of datasets, data regions, and storage
locations in Microsoft Azure. This article describes the supported datasets and how to
access the dataset schemas, the Microsoft 365 and Microsoft Azure regions that are
supported, and the storage locations that Microsoft Graph Data Connect utilizes
through Azure Synapse or Azure Data Factory.
Datasets
Microsoft Graph Data Connect currently supports the following datasets. To view the
schemas for each dataset, create a new dataset in Azure Synapse or Azure Data Factory
and use the Schema tab to view it.
Microsoft Teams
Microsoft Groups
Viva Insights
Regions
Microsoft Graph Data Connect supports extracting data from a variety of Microsoft 365
regions. To successfully move data from the Microsoft 365 datacenter into your
Microsoft Azure storage, the Azure Synapse or Azure Data Factory instance and the
Azure storage location must both map to a supported region for the location of the
Microsoft 365 data.
The following table indicates which Microsoft 365 regions are supported and the
corresponding Azure regions required for data movement.
When using Azure Storage Blob as the sink, you must ensure that your application
has Storage Blob Data Contributor access to the Azure Storage Blob location.
For copy activity, the output files are formatted as JSON. This format is fixed and
modifying the format is not supported. However, you can use Azure Synapse or
Azure Data Factory to copy the result of a Microsoft Graph Data Connect pipeline
into another storage mechanism (such as Azure SQL Database).
Mapping data flows: Copy and transform data from Microsoft 365 (Office 365) -
Azure Data Factory & Azure Synapse | Microsoft Learn |
Output can be in parquet format. For details about the supported data
transformations, see Flatten transformation in mapping data flow.
Microsoft Graph Data Connect on mapping data flows supports direct output of
the data into Azure SQL DB.
The following table indicates the areas that are supported for the corresponding copy
activity and mapping data flows.
Supported data sinks ADLS gen2, Azure Blob ADLS gen2, Azure
Blob, Azure SQL DB
See also
Azure Synapse and Azure Data Factory connector for Microsoft 365 data
Policies and billing
Microsoft Graph Data Connect policies
and billing
Article • 03/03/2023
Microsoft Graph Data Connect uses Azure managed applications to allow you to create
and deploy your solutions in your Azure environment. Managed applications let you
support certain Azure policies, giving customers greater confidence and comfortability
when using your applications.
Policies
The following Azure policies are supported for an Azure managed application built by
using Microsoft 365 data:
7 Note
Azure Data Lake Storage Gen1 and Gen2 use different policies because Azure Data
Lake Storage Gen2 implements Azure Storage.
When you select any of the policies during Azure Marketplace publishing, the policy
compliance status is checked and enforced for all installations of your application. All
selected policies that are compliant are shown to the data approvers as part of the data
request. Any policy compliance violation causes the pipeline run to fail and stop the
data extraction.
Billing
A bill is associated with the Azure subscription of the Azure Synapse or Azure Data
Factory you are using. The price in this new billing model is based on the number of
Microsoft Graph objects that you are accessing. For more information about billing, see
the Pricing page .
Microsoft Graph Data Connect consumption charges are billed monthly on a pay-as-
you-go basis. The Data Connect billing unit is in a multiple of 1000s of objects, where 1
object maps to 1 individual instance of an entity in Microsoft 365. For example, 1 email
== 1 object, 1 file == 1 object, 1 Teams chat message == 1 object, and so on.
We have some datasets available for free or are currently free in preview while other
datasets are charged. Microsoft Graph Data Connect offers datasets across multiple
different Microsoft 365 products and services. For more information on datasets that are
available through Microsoft Graph Data Connect, please refer to Dataset, regions and
sinks.
BasicDataSet_v0.User_v0
BasicDataSet_v0.User_v1
BasicDataSet_v0.MailboxSettings
BasicDataSet_v0.Manager
BasicDataSet_v0.DirectReport
BasicDataSet_v0.GroupDetails
BasicDataSet_v0.GroupMembers
BasicDataSet_v0.GroupOwners
See also
User selection and filtering
Data Connect frequently asked questions
Dataset, regions and sinks.
User selection and filtering capabilities
in Microsoft Graph Data Connect
Article • 09/08/2022
You can use Microsoft Graph Data Connect to select the users that you want to extract
data for and to include filters to limit the data returned. This article describes the user
selection options that Data Connect provides and the filtering that it supports.
User selection
You can run pipelines on a set of users. The following are the options for user selection:
Specify your user selection in the SourceDataSet of the Azure Synapse or Azure Data
Factory copy activity. To run on a list of groups, add a new field allowedGroups under
typeProperties and set this to a list of up to 10 groups' Object Ids separated by
commas. If no groups are specified by default, data is extracted for the entire
organization.
To specify a predicate to run on the entire tenant, add a new field userScopeFilterUri
under typeProperties and set this to the predicate. The predicate format should match
the query format of Microsoft Graph APIs. For example, if you want to limit the selection
to users who work in the Finance department, you can use
https://graph.microsoft.com/v1.0/users?$filter=Department eq 'Finance' . If you want
Your query only returns users within the Microsoft 365 organization that you're
querying. Guest users and non-user mailboxes are not returned.
Filtering
You can limit the results extracted for your query by using DateTime properties.
Depending on the type of data requested, a DateTime filter might be required. The
DateTime filter is provided by using properties in the SourceDataSet of the Azure
Synapse or Azure Data Factory copy activity. To specify a DateTime filter, add a new field
dateFilterColumn under typeProperties and set this to one of the properties that
support filtering in the following table. Next, add a startTime and endTime that
represent the DateTime values that the property is filtered upon.
BasicDataSet_v0.Event_v0 CreatedDateTime
BasicDataSet_v0.Event_v1 LastModifiedDateTime
BasicDataSet_v0.Message_v0 CreatedDateTime
BasicDataSet_v0.Message_v1 LastModifiedDateTime
ReceivedDateTime
SentDateTime
BasicDataSet_v0.SentItem_v0 CreatedDateTime
BasicDataSet_v0.SentItem_v1 LastModifiedDateTime
ReceivedDateTime
SentDateTime
7 Note
See also
Integrate with PAM
Data Connect frequently asked questions
Microsoft Graph Data Connect
integration with PAM
Article • 09/08/2022
Microsoft Graph Data Connect relies on Privileged Access Management (PAM) to allow
Microsoft 365 administrators to approve data movement requests. Data Connect
pipelines must be approved by a member of the data access request approver group
specified by the Microsoft 365 administrator during enablement. To set up the approver
group, see Set up your Microsoft 365 tenant and enable Microsoft Graph Data Connect.
Approval request emails are sent to each member of the approver group to notify them
when copy activities request access to extract Microsoft 365 data. Approvers can
approve or deny these requests, specify a user group that should be scrubbed out of
extracted data, or revoke a previously approved request. Approvals persist for six
months, and one approval is needed per copy activity in the Azure Synapse or Azure
Data Factory pipeline.
Each request always includes the following details about the dataset and the users
about whom data is being extracted:
The following fields in the request are available only in some cases:
Application Name and the Marketplace URI (available only for applications
installed from the Azure Marketplace).
Links to the application's privacy policy and terms of service (available only if the
application provides it).
The compliance policies that the application enforces, such as data encryption at
rest in the output storage location (available only if the application provides it and
if the application is installed from the Azure Marketplace).
Deny List: The user group that can be scrubbed out of the extracted data. This field
is empty as a part of the request for datasets that support privacy scrubbing of
extracted data. It can be populated by the member of the approver group who
approves the request at approval time.
Approving requests
Microsoft Graph Data Connect pipelines must be approved by a member of a data
access request approver group. Approvers can approve, deny, or revoke pipelines by
using the Exchange Online PowerShell module or the PAM user experience.
1. Install the Exchange Online PowerShell module. For installation instructions, see
Connect to Exchange Online PowerShell using multi-factor authentication.
7 Note
3. Sign in with your account. You must be part of the configured data access
approver group to be able to approve, deny, or revoke requests. Guest users
cannot approve requests, even if they are in the approver group.
PowerShell
Connect-EXOPSSession
7 Note
The value in the Identity property is used to identify and approve or deny the
request. Note this value and use it in the -RequestId parameter.
PowerShell
5. Take a closer look at the context field of the request that you are interested in.
7 Note
The context field of the data access request describes the parameters and
properties of the copy activity.
PowerShell
PowerShell
Key Value
--- -----
ApplicationName
ComplianceStatus [{"Timestamp":"2018-05-
02T18:29:21.5705664Z","RequirementName":"adlsEncryption","PolicyComplia
nceState":"Compliant","Violations":0},{"Timestamp":"2018-05-02T...
ApplicationMarketPlaceUri
OutputUri
adl://myadlserumvrroyspmq.azuredatalakestore.net/targetFolder/Event
ApplicationPrivacyPolicyUri http://www.wkw.com/privacy
ApplicationTermsOfServiceUri http://www.wkw.com/tos
InstallerIdentity a89885c3-4b0e-499e-86ed-
14d7ed9147c2@942229f8-4656-4fb0-828b-e938dad4019a
SourceTenantId 942229f8-4656-4fb0-828b-e938dad4019a
UserScopeQuery tenant in (942229f8-4656-4fb0-828b-
e938dad4019a)
ApplicationId
DataTable Calendar Events
DestinationTenantId 942229f8-4656-4fb0-828b-e938dad4019a
Columns Subject:string, HasAttachments:bool,
End:DateTime, Start:DateTime, ResponseStatus:string, Organizer:Object,
Attendees:string, Importance:string, Sensitivity:...
6. Approve/deny the request by using the value for Identity for the -RequestId
parameter.
PowerShell
You can also approve the request with a deny list to ensure data from certain users is
not included. To do so, you need to modify the context of the request to add the object
Id of the group that you want to omit, and then approve the request.
PowerShell
You can also revoke requests that were previously approved. Similar to approving
requests, the value for Identity is what is required in the -RequestId parameter.
PowerShell
PowerShell
AuthorizedBy : [email protected]
Type : Task
AuthorizedAccess : Data Access Request
StartTimeUtc : 7/24/2018 6:02:42 PM
EndTimeUtc : 10/22/2018 6:02:42 PM
Revoked : True
RevocationDateTimeUtc : 7/24/2018 9:12:55 PM
RevokedBy : NAMPR00A001.prod.outlook.com/Microsoft Exchange
Hosted Organizations/tenant.onmicrosoft.com/user
RevocationComment : Revoking this request!
Identity : bda75607-0d87-43cb-bdf1-284b18446b34
DateCreatedUtc : 1/1/0001 12:00:00 AM
DateUpdatedUtc : 7/24/2018 9:12:55 PM
1. Sign in to the Microsoft 365 admin portal by using admin credentials, and then go
to the Privileged Access Management approval user experience page. This page
shows you all the access requests (pending/approved/expired/denied).
2. On the resulting page, select the request that you're interested in. To select a deny
list for privacy scrubbing, select the DenyList dropdown, select the group that
needs to be scrubbed, and then select Approve.
3. To revoke a previously approved request, select the approved request that needs
to be revoked, and then choose Revoke. The next attempt to move data by using
that approval fails.
Approval behavior
Microsoft Graph Data Connect approval requests have particular characteristics that you
should be aware of:
Approval requests are based on the Azure Synapse or Azure Data Factory, pipeline,
and copy activity names. Every copy activity run verifies that the Microsoft 365
admin has approved the copy activity's request to access Office data, and validates
the important parameters of the copy activity run against the parameters of the
approval.
Under certain conditions, a new approval request is automatically triggered. A Data
Connect approver must approve the new request before the copy activity can
access Microsoft 365 data.
If the parameters of the copy activity run changes, a new approval request is
triggered.
A new approval request is triggered if the Azure Synapse or Azure Data Factory
pipeline or copy activity's name change. For example, a new approval is required if
the data table or set of columns that the copy activity is accessing changes.
Copy activities must be approved once every six months. If the original approval
was approved six months ago, a new approval request is automatically triggered.
If a Microsoft 365 data access approver has denied an approval request or revoked
a previously approved request, the copy activity fails continually. Work with the
approver to understand the reason for the denial or revocation, and fix the
parameters of the copy activity accordingly. To trigger a new request for approval,
a new copy activity must be deployed or the name of the existing copy activity
must be changed.
An approval request expires in 24 hours unless a Microsoft 365 data access
approver acts on the request. A new request is submitted once every 24 hours for
approval. If you see your copy activity waiting for approval (in the Consent Pending
stage), then work with a Microsoft 365 data access approver to get your request
approved.
Privacy scrubbing
The member of the approver group who approves the request can specify the name of
one user group whose data would be scrubbed out of extracted data. The rows
containing email addresses corresponding to the members of the denied group are
scrubbed out of extracted data. Groups nested within the denied group are expanded,
and only users are scrubbed out. Refer to the approving requests section of this article
for details about how to apply the deny list during approval through either PowerShell
or the PAM user experience.
The following table shows the names of the datasets and the columns for which the
contents are checked for privacy scrubbing.
BasicDataSet_v0.Contact_v0 EmailAddresses
BasicDataSet_v0.Contact_v1
This article explains the concept of groups in Microsoft Graph Data Connect and the
options for scope selection. Scope selection allows you to specify how to extract objects;
for example, you can extract objects for all users in a Microsoft 365 tenant or select
groups in the Microsoft 365 tenant. For more information, see Demystifying User
Scopes .
You can create and manage several different types of groups in the Microsoft 365 admin
center; for details, see Compare groups. The following types of groups are applicable to
Microsoft Graph Data Connect:
Microsoft 365 Groups - Used for collaboration between users, both inside and
outside your company. They include collaboration services such as SharePoint and
Planner.
Distribution groups - Used for sending email notifications to a group of people.
Security groups - Used for granting access to resources such as SharePoint sites.
Mail-enabled security groups - Used for granting access to resources such as
SharePoint and emailing notifications to those users.
User-scoped datasets
User-scoped datasets can be messages, events, users, and so on. These datasets focus
on data around the individual user for the respective dataset.
* **All users in the tenant**: Returns data for all the users in the tenant.
Data is extracted for individual users in the selected group. For details,
see [User selection and filtering capabilities](/graph/data-connect-
filtering).
* **All users in the tenant with a scope filter**: Returns data for all the
users in the tenant that are part of the scope filter applied. Data is
extracted for individual users from the selected filter (group).
* A scope Filter can help filter the users. If it's left empty, all data
for all users is returned.
* **Select groups from the Microsoft 365 tenant**: Data is extracted for
individual users in the group.
Example
A customer wants to extract the messages dataset and creates a security group of users
A, B, and C in a tenant of 500 users, and passes this group. Microsoft Graph Data
Connect expands the security group into a list of users, extracts the message data for
those users, and delivers the data for those users to the customer. The customer will
only receive the messages dataset for individual users A, B, and C out of their tenant of
500 users.
Group-scoped datasets
Group-scoped datasets can be Outlook group conversations, Teams channel messages,
group details. These datasets focus on the collective data in a group from Outlook or
Teams.
* **All groups in the tenant**: Returns data for all the groups in the
tenant.
* **All groups in the tenant with a scope filter**: Returns data for all the
groups in the tenant with the scope filter applied. The scope Filter can
help narrow down the list of groups.
* **Select groups from the Microsoft 365 tenant**: Returns collective data
for the selected groups. Microsoft Graph Data Connect looks for data
associated with those specific groups rather than the individuals of the
group.
Note: When the customer specifies a group or groups to be the scope, Microsoft
Graph Data Connect looks for data associated with those specific groups rather than
the individuals of the group.
The following table maps certain datasets with certain types of groups. This helps you to
understand which types of groups are compatible with which datasets when you extract
data and use scope filters. Groups can either be distribution groups, security groups, or
Microsoft 365 groups. The types of groups supported varies based on which dataset
you're requesting.
TeamsStandardChannelMessages Yes* No No No
TeamsChannelDetails_v0 Yes* No No No
OutlookGroupConversations Yes No No No
Viva Insights NA NA NA NA
**Group datasets don't contain a primary mailbox; the region defaults to the region of
the tenant.
Example
A customer wants to extract the group details dataset with a security group of users A,
B, and C out of their tenant of 500 users. Because this is a group-scoped dataset, the
customer will only receive group details data for the specified group. The customer will
not receive any individual data for users A, B, and C in the group.
Note: For Teams group-scoped datasets, if the group in scope is not a Teams-
enabled group, it will not return any data. Microsoft 365 groups can be enabled as
Teams groups, but distribution groups and security groups are not Teams-enabled.
The following section provides details about the type of groups that are available to
select.
2. On the Scope tab, select the group-scoped dataset, search for and add a group or
groups, or group IDs, and choose Add.
3. View the group ID. Copy the IDs of the groups you want to verify.
4. In a new tab, go to the Azure homepage and choose Azure Active Directory.
5. On the Overview tab, paste the group ID copied from step 2, and then and choose
the Groups tab.
6. In the Type field for the group, verify the type of group that you have.
Microsoft Graph Data Connect
frequently asked questions
Article • 10/11/2022
Microsoft Graph Data Connect lets developers create applications that customers can
use to provide managed access to their at-scale Microsoft Graph datasets. This article
provides tips that will help you take advantage of the Microsoft Graph Data Connect
feature. For an introduction to Microsoft Graph Data Connect, see the overview.
For more questions, see troubleshooting, or reach out to the Data Connect team.
For example, you might want to use Microsoft Graph Data Connect to do an initial
extraction of the last year of email data, and then use Microsoft Graph APIs to analyze
emails in real time moving forward. Microsoft Graph Data Connect and Microsoft Graph
APIs are different tools for different jobs. It's important to think about which access
method best fits your scenario. For more information, see When should I use Microsoft
Graph API or Microsoft Graph Data Connect.
Business Process Analytics: For better operations, see how work really flows
through the organization on a day-to-day basis. Pinpoint the manual processes
and workflow bottlenecks that should be automated or optimized.
Security and Compliance Analytics: To secure sensitive data, learn how employees
are using and sharing sensitive information. Implement anomaly detection, threat
intelligence, audit log analysis, risk management, and legal forensics.
When customers are looking for insights and analytics beyond Viva Insights, Data
Connect provides the extensibility to deliver custom requirements. For example, it offers
Teams call records and transcripts as well as SharePoint Online data sets, which are not
currently in scope for Viva Insights. Additionally, Data Connect raw data provides
granular details that aren’t otherwise available from Viva Insights.
7 Note
Your tenant admin will need to approve and consent within 24 hours of kicking off
the pipeline. If the consent is not given within 24 hours, it will expire and you will
need to restart the consent process by kicking off your pipelines again. The
overhead time does not include time taken in consent approval.
For a list of Office to Azure regions and mappings, see Dataset, regions and sinks.
Basic: Datasets generated from raw customer created content and inputs from
Microsoft 365 applications and services (for example, Azure Active Directory,
Outlook, or Teams datasets).
Curated: Datasets custom generated for a specific use case or analytics scenarios,
or datasets from first-party Microsoft 365 analytics applications for their
extensibility for example, Viva Insights metrics).
Teams
Outlook
Azure Active Directory (Azure AD)
OneDrive/Sharepoint
Viva Insights
New datasets are added to Microsoft Graph Data Connect on a regular basis. For a
complete list, see Dataset, regions, and sinks.
For information about datasets that are generally avaialble or in preview only, see
Dataset, regions, and sinks.
How much do I have to pay for Microsoft
Graph Data Connect?
Microsoft Graph Data Connect consumption charges are billed monthly on a pay-as-
you-go basis. The Data Connect billing unit is in a multiple of 1000s of objects, where 1
object maps to 1 individual instance of an entity in Microsoft 365. For example, 1 email
== 1 object, 1 file == 1 object, 1 Teams chat message == 1 object, and so on.
Some datasets are available for free or are currently free in preview while other datasets
are charged. Microsoft Graph Data Connect offers datasets across multiple different
Microsoft 365 products and services. For details about datasets that are available
through Microsoft Graph Data Connect, see Dataset, regions, and sinks. For details
about billing, see the Pricing page .
BasicDataSet_v0.User_v0
BasicDataSet_v0.User_v1
BasicDataSet_v0.MailboxSettings
BasicDataSet_v0.Manager
BasicDataSet_v0.DirectReport
BasicDataSet_v0.GroupDetails
BasicDataSet_v0.GroupMembers
BasicDataSet_v0.GroupOwners
For example, a customer has 20 pipeline runs within the month, each yielding 500 rows.
In total, the customer runs pipelines for 10,000 rows that month. However, their bill will
not be 10,000 rows/1000 rows = 10 units.
Instead, the customer will be billed for 20 units because Microsoft Graph Data Connect
rounds up fractions. Because 500 rows /1000 rows = 0.5 and 0.5 is a fraction, it will
rounds up to 1. The customer will be billed one unit per pipeline run, which results in 20
units billed in total.
Does my current Azure discount apply to the
Microsoft Graph Data Connect monthly bill?
Microsoft Graph Data Connect is offered through Azure and is currently available to
Microsoft 365 customers. Your existing discounts can be applied to Microsoft Graph
Data Connect charges because it is billed through Azure. For more information, reach
out to your account manager.
If you create an Azure managed application for others to use in their tenants, you still
provide a service principal for the app to use. This service principal exists in your (the
publisher's) tenant. However, if the app needs other service principals, your customer
(the installer) creates them in their own tenant. For example, your Azure Synapse or
Azure Data Factory pipeline likely needs access to a storage resource in Azure. The
customer creates the service principal with permissions to the storage account for the
pipeline to use.
For more information about building your application with Azure Synapse or Azure Data
Factory, see the Data Connect quick start.
The first time you trigger a pipeline, it waits for a Microsoft 365 administrator (or
appointed delegate) to approve the access request. Although the pipeline status shows
In progress, the underlying copy activity will have a status of ConsentPending until
approval is granted, as shown in the following screenshot.
During development, it's a good idea to make sure that your pipeline runs aren't stuck
on ConsentPending, especially after you make a change to your pipeline. For example, if
you add an additional field to the schema, the next pipeline run issues a new PAM
request that has to be approved. Don't waste time waiting on a pipeline that's waiting
for your approval.
Note that consent requests will expire after 24 hours if not approved and the pipeline
will fail. Additionally, PAM approval is valid for only 6 months (unless revoked).
To approve a request:
When enabling Microsoft Graph Data Connect, you must be within the approver’s
group.
Users must have a Global Admin role.
Users must have an Exchange Online license assigned.
However, even if this account is part of the approver group that you set up, you can't
use it to approve the PAM request because self-approvals are not allowed. If you try,
you'll get an error message in the PAM portal: "Requestor and approver are the same.
Self-approval is not allowed."
For development, you'll want to have a second account in addition to the admin who
approves requests. Both the submitter and the approver must have active Exchange
Online accounts.
You can deduplicate the exported JSON objects based on the internetMessageId of the
messages: two messages with the same internetMessageId are duplicate copies of the
same instance. Because the duplicates can exist in different blobs, you must deduplicate
across all blobs rather than deduplicating in each blob separately.
Can I use the puser field to determine the
relevant user?
The extracted data includes some meta properties that don't exist when using the
corresponding Microsoft Graph APIs. Specifically, the puser field can be useful for
determining which user the data was extracted from. In the scenario where you have
two copies of the same email in different mailboxes, you can use the puser field to
determine which copy came from which mailbox. The puser field is also useful for
datasets such as the Manager dataset. The exported JSON contains information about a
manager, but this is only useful if you know whose manager they are. The puser field
tells you whose manager that JSON object corresponds to.
Microsoft Graph Data Connect enbles you to extend Microsoft 365 data into Azure in
order to create applications for analytics, intelligence, and business process
optimization. This article provides troubleshooting information for working with
Microsoft Graph Data Connect.
The service principal's owner must be a valid user account within the tenant, not
another service principal.
If the owning member is no longer valid in a tenant's system, pipelines will fail this
check unless a current valid user within the tenant owns the account. If there is a
change in ownership, make sure that the owning account is updated to another
member who meets the requirements.
PAM approver issues
If you're having issues approving jobs within your tenant for your specified pipeline runs
or extractions, verify that the approvers in your tenant meet the following criteria.
Certain privileges must be granted to designated approvers to successfully approve
jobs.
Approvers must be active user accounts within the tenant, not other service
principals or groups.
The user account must have an Office 365 or Microsoft 365 E5 license with
Exchange Online capabilities and a mailbox.
If approvers want to approve jobs through the Microsoft 365 admin center, they
will need global admin privileges. Global admin privileges are not needed when
approving jobs via PowerShell script .
Keep the following in mind when customers with multi-geo tenants extract data:
Data Connect only allows datasets to be extracted from the same region as the
tenant. For example, if you have a tenant in Europe (EUR) but want to run your
pipeline for your users in North America (NAM), you will only get data for users in
NAM, because you specified a pipeline for NAM.
Multi-geo tenants can extract data for their tenants by setting up region-specific
pipelines. For example, one region maps to one or a set of pipelines for that
region.
3. On the Sink tab, specify the location where you want the combined file to be
created and make sure you select the Merge files behavior.
You can resolve this issue with an SSP request: INTERNT PROXY (SWG) - EXCEPTION ON
SECURITY FILTERING POLICY .
1. Find an Office-to-Azure region mapping. To look up which Office region you will
be extracting user data from, see the following table.
7 Note
The Azure region you're running a pipeline in must map to an Office region to
extract the users for the tenant. Microsoft Graph Data Connect does not extract
data across regions. For example, if you're running a pipeline in the West Europe
Azure region, it will only extract the users for the Europe (EUR) Office region
because the West Europe Azure region maps to the Europe Office region.
2. After you find the Office to Azure mapping, you need to determine the compatible
location of your destination storage account (see the following table). You can look
up how to configure your Azure storage account and grant access from an internet
IP range.
7 Note
This indicates the Azure regions that may NOT be used per region for the
destination storage when it is closed for public access. This is also the region for
which the IP addresses need to be added to the allow list to allow data delivery. To
find IP ranges, see Azure IP Ranges and Service Tags .
At this point, customers can understand and configure the region they want
to extract users from (what their Office to Azure region mapping is).
Customers can understand which region their destination storage account
can't be in.
Based on a compatible destination storage account, customers can use the
information to understand which IP addresses they need to add to the allow
list.
3. You can create a new integration run time on the same region that you have added
to the allow list, or use auto resolve, depending on your preference and settings.
We recommend creating a new IR in the same region. For details, see Azure
Integration Runtime IP addresses: Specific regions.
If you're using Auto Resolve IR, the region depends on several factors. For
details, see Azure IR location.
1. A user wants to extract data for users in the Europe (EUR) Office region. They
identify their Office to Azure region mapping. Because the Office region is EUR, the
Azure region is in West Europe.
2. All resources, ADF, and storage account are in the West Europe Azure region,
initially.
3. The user closed the destination storage account for public access.
4. The user needs to identify where their compatible destination storage account can
be based on the Office region I want to extract (EUR).
5. Because they cannot add allow list services in the same region as the storage
account, the destination storage account cannot be on the West Europe Azure
region. They can create a new storage account in North Europe.
6. For Data Connect internal services to copy the data into the destination storage
account, they need to add IP addresses to the allow list from compatible regions
based on their Office region (EUR). They will need to add ADF public IPs to the
allow list in the West Europe Azure region.
7. For the ADF destination linked service to also access the destination storage
account, they need to create and use an Integration Runtime on the West Europe
region, or use auto resolve IR instead.
8. The user lists these IP addresses and moves the destination storage to North
Europe because the Office region is EUR, and the Azure region is West Europe.
1. The consent request is only valid for 24 hours. Contact your tenant admin to
approve within this timeframe.
a. If not approved in that timeframe, subsequent runs will fail with the same error
and regenerate a consent request.
b. When approved, the pipeline can be rerun at any time to retrieve data.
2. Verify that the destination storage is set up correctly to allow the app to write data
into it.
See also
Data Connect overview
Data Connect FAQ
Outlook calendar API overview
Article • 10/06/2022
Outlook calendar is part of the Outlook messaging hub in Microsoft 365 that also lets
you manage emails and contacts, find information about users in an organization,
initiate online conversations, share files, and collaborate in groups.
https://www.youtube-nocookie.com/embed/_ST4nyz4g9E
Most features in the Outlook calendar API apply to calendars in personal Microsoft
accounts and work or school accounts.
** Denotes features below that are specifically applicable to Outlook calendars in only
work or school accounts.
In Outlook, customers can create individual calendars for work, family, and other
purposes, and organize them in calendar groups. They can turn on the free
Birthdays and Holiday calendar to remind them of contacts' birthdays and local
holidays. They can add calendars that match their interests, such as calendars for
sport teams and TV programs. Customers can select and overlay calendars, and see
their events in the same view. Through the calendar API, your app can similarly
organize calendars in calendar groups, and interact with interesting calendars just
like any other calendar in the user's mailbox.
Outlook customers can apply categories to events, messages, contacts, tasks, and
group posts in a consistent way to enhance organization and discovery. The
calendar API lets you access and define a user's master list of categories, which
opens up additional creative scenarios. For example, an athletic club can organize a
sports tournament and offer an app that differentiates emails and events for each
sport with their own color category. For last-minute news such as unforeseen
timetable changes, the app can also set the importance property of those events
and emails to alert customers.
In a calendar folder, you can create and update single instance events, or schedule
and maintain recurring events. You can let your customers respond to meeting
requests, and snooze or dismiss reminders using the associated event navigation
property.
You can keep the app local store synchronized by subscribing to change
notifications and tracking changes to events in a user's calendar.
You can display the user's agenda based on a light-weight reminder view.
You can let the user conveniently accept and take a meeting online through its
webLink property, which opens the meeting in Outlook on the web.
Users can also tentatively accept or decline a meeting while on the go.
Enhance collaboration
In Outlook, customers can share calendars with one another and give permissions
to read, write, or delete calendar contents. Or, they can delegate a calendar to let
another customer respond to meeting requests on their behalf. Programmatically,
while you cannot initiate a share or delegate action on behalf of a user, you can
use a set of properties to verify the sharing status and enable scenarios around
shared or delegated calendars: canEdit, canShare, canViewPrivateItems, isShared,
and isSharedWithMe.
The calendar API lets you get calendar items of the signed-in user, or users who
have shared or delegated their calendars to the signed-in user. For example, if
Garth has shared a calendar with John, or if Garth has delegated access to John,
then delegated permissions from John would give you read access to Garth's
shared calendar and contents as well.
Microsoft 365 groups make it convenient for group members to collaborate and
access group conversations and calendars right in Outlook. Aside from a few minor
differences between group calendars and user calendars, the calendar API lets you
interact with group calendars just like user calendars. See the calendar resource for
more information**.
Schedule smart
Outlook and the calendar API offer many smart conveniences to schedule events:
Through Outlook calendar app settings, customers can enable automatic adding of
events from emails, such as flight, hotel, or dining reservations, and billing invoices.
Once added, you can interact with these events just like any other event objects in
the user's mailbox, and build creative scenarios upon this Outlook capability.
In Outlook, booking a meeting room is as straight-forward as adding an attendee
to the event. The calendar API represents a meeting room as an emailAddress
object. You can get rooms and get room lists that are available in a tenant. To
organize a meeting in a specific room, assign it to the location property of the
event.**
You can look up the free/busy information for users and resources for a specific
time period. You can then use this data to apply to different scenarios including
resource planning and event scheduling.**
If your scenario involves scheduling meetings at an optimal time, you can consider
using findMeetingTimes to identify possible times or locations to meet. The
findMeetingTimes function considers the free/busy status of the attendees, and
any preferred rooms, time, and other constraints you provide. If the first try doesn't
return a common meeting time, check the reason, adjust your criteria and call
findMeetingTimes again.**
Incorporate place details in calendar events to help users navigate their day and
enhance productivity.**
Catering applications can use the places API to assist venue navigation and set
up.**
Automate emailing pre-meeting details to attendees and include a map on how to
get to a room.**
Set up reception bot assistants to provide information about specific rooms in a
building.**
Depending on your app scenario, you can use the places API within the context of
Outlook, or independent of Outlook.
Take advantage of social intelligence and other
developer conveniences in Microsoft Graph
Use the people API in Microsoft Graph to connect to people data which is based on a
user's communication and collaboration patterns and business relationships. You can
implement controls such as a people picker and suggest persons relevant to the user
when organizing meetings on the user's behalf.
Save overhead in storing and managing app data in external data stores. With Microsoft
Graph, you can store custom app data as open extensions in individual resource
instances. If you require the data to be typed or would like to be able to share the typed
schema, you can store custom app data in schema extensions.
The API does not support accessing in-place archive mailboxes, not on Exchange Online
nor on Exchange Server.
API reference
Looking for the API reference for this service?
Next steps
Select and try calendar sample queries in Graph Explorer.
Learn about:
Finding possible meeting times on the Outlook calendar
Getting the free/busy schedule for users and resources
Propose meeting times in an Outlook calendar (preview)
Create or set an event as an online meeting in an Outlook calendar
Scheduling repeating appointments as recurring events in Outlook
Getting shared events
Attaching large files to Outlook messages or events
Getting immutable identifiers for Outlook resources
Take a look at the Outlook calendar API reference.
Find possible meeting times on the
Outlook calendar
Article • 07/09/2022
In a workplace or school, looking for a common time and place to meet often incurs
overhead. Microsoft Graph applications can use findMeetingTimes to identify any
possible meeting times that satisfy time, location, and other constraints.
The findMeetingTimes action lets you specify conditions such as the meeting date/time
range, duration, optional or required attendees, and nature of the activity
(activityDomain). The action takes into account the attendees' and organizer's normal
work schedules and free/busy status, and suggests times that are appropriate for the
participants and type of activity. For instance, suggestions for a work-related activity
always occur during the work hours of the organizer and attendees, and suggestions
where required attendees are available are ordered higher up in the suggested list.
In Microsoft 365, work hours and time zones are configurable per mailbox. The
findMeetingTimes action handles time zone variations among the organizer and
attendees. By default, findMeetingTimes returns suggestions in UTC. You can use the
following request header to have findMeetingTimes return suggestions expressed in a
specific time zone.
HTTP
Prefer: outlook.timezone="{time-zone-string}}"
7 Note
Organizer's calendar
Attendee's calendar
The example makes 2 calls to findMeetingTimes:
1. The first call looks in the date range of April 18-20. As the attendee is out-of-office
on April 18-19, and there is no commonly available time on April 20, the first call
returns no suggestions with the reason (emptySuggestionsReason) that attendees
are not available.
2. The second call looks for availability on April 21 and returns a suggestion of 2-
4pm.
The two calls to findMeetingTimes include the following parameters. All parameters for
findMeetingTimes are optional.
attendees: one attendee, Samantha Booth, set as required for the type property
locationConstraint: does not require any location suggestion
timeConstraint: the first call looks in the date/time range of April 18, 9am to April
20, 5pm; after the first call fails to suggest any times, the second call looks at April
21, 9am to 5pm
meetingDuration: two hours
returnSuggestionReasons: this example requires a reason for each suggestion
minimumAttendeePercentage: 100%, as the attendee must be able to attend for
any suggested time
First request
Look for a 2-hour free time slot for both users over April 18-20.
HTTP
POST https://graph.microsoft.com/v1.0/me/findMeetingTimes
Prefer: outlook.timezone="Pacific Standard Time"
Content-type: application/json
{
"attendees": [
{
"type": "required",
"emailAddress": {
"name": "Samantha Booth",
"address": "[email protected]"
}
}
],
"locationConstraint": {
"isRequired": false,
"suggestLocation": false,
"locations": [
{
"resolveAvailability": false,
"displayName": "Conf room Hood"
}
]
},
"timeConstraint": {
"activityDomain":"work",
"timeslots": [
{
"start": {
"dateTime": "2017-04-18T09:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2017-04-20T17:00:00",
"timeZone": "Pacific Standard Time"
}
}
]
},
"meetingDuration": "PT2H",
"returnSuggestionReasons": true,
"minimumAttendeePercentage": 100
}
First response
There is no 2-hour time slot during the work hours of April 18-20 when both users are
available.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
Preference-Applied: outlook.timezone="Pacific Standard Time"
Content-Length: 184
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph
.meetingTimeSuggestionsResult",
"emptySuggestionsReason":"AttendeesUnavailable",
"meetingTimeSuggestions":[
]
}
Second request
Look for a 2-hour time slot on April 21.
HTTP
POST https://graph.microsoft.com/v1.0/me/findMeetingTimes
Prefer: outlook.timezone="Pacific Standard Time"
Content-type: application/json
{
"attendees": [
{
"type": "required",
"emailAddress": {
"name": "Samantha Booth",
"address": "[email protected]"
}
}
],
"locationConstraint": {
"isRequired": false,
"suggestLocation": false,
"locations": [
{
"resolveAvailability": false,
"displayName": "Conf room Hood"
}
]
},
"timeConstraint": {
"activityDomain":"work",
"timeslots": [
{
"start": {
"dateTime": "2017-04-21T09:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2017-04-21T17:00:00",
"timeZone": "Pacific Standard Time"
}
}
]
},
"meetingDuration": "PT2H",
"returnSuggestionReasons": true,
"minimumAttendeePercentage": 100
}
Second response
The second findMeetingTimes request suggests April 21, 2-4pm for both users to meet.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
Preference-Applied: outlook.timezone="Pacific Standard Time"
Content-Length: 714
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph
.meetingTimeSuggestionsResult",
"emptySuggestionsReason":"",
"meetingTimeSuggestions":[
{
"confidence":100.0,
"organizerAvailability":"free",
"suggestionReason":"Suggested because it is one of the nearest
times when all attendees are available.",
"meetingTimeSlot":{
"start":{
"dateTime":"2017-04-21T14:00:00.0000000",
"timeZone":"Pacific Standard Time"
},
"end":{
"dateTime":"2017-04-21T16:00:00.0000000",
"timeZone":"Pacific Standard Time"
}
},
"attendeeAvailability":[
{
"availability":"free",
"attendee":{
"type":"required",
"emailAddress":{
"address":"[email protected]"
}
}
}
],
"locations":[
{
"displayName":"Conf room Hood"
}
]
}
]
}
Next steps
There are times when not all attendees can attend a meeting. You can have
findMeetingTimes suggest a time if the confidence for attendance reaches a certain
percentage, by specifying the minimumAttendeePercentage optional parameter. Learn
more about the confidence of a meeting suggestion and other parameters, and apply
them as appropriate for meetings of larger sizes.
In a work or school setting, a common scenario is to see when a user is free for meeting,
or to browse the availability of a team, room, or equipment for a time period.
The getSchedule action lets you get the availability information of one or more entities -
users, distribution lists, or resources - for a specific period of time.
Example
A simple example is to find the free/busy schedule of a coworker, Alex, on a specific day,
from 9am to 6pm, Pacific Standard Time:
HTTP
POST https://graph.microsoft.com/v1.0/me/calendar/getschedule
Prefer: outlook.timezone="Pacific Standard Time"
Content-Type: application/json
{
"Schedules": ["[email protected]"],
"StartTime": {
"dateTime": "2018-08-06T09:00:00",
"timeZone": "Pacific Standard Time"
},
"EndTime": {
"dateTime": "2018-08-06T18:00:00",
"timeZone": "Pacific Standard Time"
},
"availabilityViewInterval": "15"
}
getSchedule returns two schedule items that match existing events in Alex' default
calendar, showing the start and end times of each event and its free/busy status. You
can assume Alex is free for the remaining time in that date/time range.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#Collection(micr
osoft.graph.scheduleInformation)",
"value":[
{
"scheduleId":"[email protected]",
"availabilityView":"111111002222222200000000000000000000",
"scheduleItems":[
{
"status":"Tentative",
"start":{
"dateTime":"2018-08-06T09:00:00.0000000",
"timeZone":"Pacific Standard Time"
},
"end":{
"dateTime":"2018-08-06T10:30:00.0000000",
"timeZone":"Pacific Standard Time"
}
},
{
"status":"Busy",
"start":{
"dateTime":"2018-08-06T11:00:00.0000000",
"timeZone":"Pacific Standard Time"
},
"end":{
"dateTime":"2018-08-06T13:00:00.0000000",
"timeZone":"Pacific Standard Time"
}
}
],
"workingHours":{
"daysOfWeek":[
"monday",
"tuesday",
"wednesday",
"thursday",
"friday"
],
"startTime":"08:00:00.0000000",
"endTime":"17:00:00.0000000",
"timeZone":{
"@odata.type":"#microsoft.graph.customTimeZone",
"bias":480,
"name":"Customized Time Zone",
"standardOffset":{
"time":"02:00:00.0000000",
"dayOccurrence":1,
"dayOfWeek":"sunday",
"month":11,
"year":0
},
"daylightOffset":{
"daylightBias":-60,
"time":"02:00:00.0000000",
"dayOccurrence":2,
"dayOfWeek":"sunday",
"month":3,
"year":0
}
}
}
}
]
}
Apart from the free/busy schedule and working hours of Alex, getSchedule also returns
availabilityView, which is a merged view of Alex' availability for that day. The merged
view is a string that consists of time slots covering that day, with each time slot
indicating Alex' availability using the following convention:
0 = free
1 = tentative
2 = busy
3 = out of office
4 = working elsewhere.
By default, the length of each time slot is 30 minutes. This example uses the
availabilityViewInterval property to customize the time slot to be 15 minutes.
Application
findMeetingTimes applies certain business logic to suggest meeting times and
locations, such as:
App-only support
findmeetingtimes supports only delegated scenarios which require a user to have
signed in to the app. The app can read events in only the calendars that the signed-in
user can access. This can include calendars that other users have delegated or shared
with the signed-in user.
Permissions
The least privileged permissions required by findmeetingtimes is
Calendars.Read.Shared.
Version support
findmeetingtimes and getSchedule are both generally available and appropriate for use
in production apps.
While the consented permission lets an app use getSchedule on the requested users'
calendars, through Outlook, the requested user controls which event data, if any, that
getSchedule returns.
For example, getSchedule can return the free/busy status and working hours of the
requested users, or it can also return the subject, location, and isPrivate properties of an
event, provided that:
The event is marked with low sensitivity level - normal or personal - AND one or
more of the following conditions apply:
The requested user’s calendar settings allow the signed-in user to view subject
lines and locations
The requested user’s calendar is shared with the signed-in user
HTTP
See also
Permissions reference
Find possible meeting times on the Outlook calendar
Propose new meeting times in Outlook
calendar
Article • 08/26/2022
In Outlook, a meeting organizer can allow invitees to propose alternative meeting times,
if they cannot meet at the original set date/time and accept tentatively or decline. The
organizer can accept a proposal by adjusting the meeting time as appropriate.
HTTP
POST https://graph.microsoft.com/v1.0/me/events
Prefer: outlook.timezone="Pacific Standard Time"
Content-type: application/json
{
"subject": "Let's go for lunch",
"body": {
"contentType": "HTML",
"content": "Does noon work for you?"
},
"start": {
"dateTime": "2019-08-15T12:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-15T14:00:00",
"timeZone": "Pacific Standard Time"
},
"allowNewTimeProposals": true,
"location":{
"displayName":"Harry's Bar"
},
"attendees": [
{
"emailAddress": {
"address":"[email protected]",
"name": "Adele Vance"
},
"type": "required"
}
]
}
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-
b4ab-004ae54f3747')/events/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAAAhBhkg==\"",
"id": "AAMkADAwJXJGu0AAACEhWOAAA=",
"createdDateTime": "2019-08-01T06:41:07.805128Z",
"lastModifiedDateTime": "2019-08-01T06:41:08.3298275Z",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAAAhBhkg==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Let's go for lunch",
"bodyPreview": "Does noon work for you?",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": true,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "busy",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADAwJXJGu0AAACEhWOAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"allowNewTimeProposals": true,
"recurrence": null,
"responseStatus": {
"response": "organizer",
"time": "0001-01-01T00:00:00Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nDoes late morning work for
you?\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-08-15T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-15T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"location": {
"displayName": "Harry's Bar",
"locationType": "default",
"uniqueId": "Harry's Bar",
"uniqueIdType": "private"
},
"locations": [
{
"displayName": "Harry's Bar",
"locationType": "default",
"uniqueId": "Harry's Bar",
"uniqueIdType": "private"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
}
HTTP
POST
https://graph.microsoft.com/v1.0/me/events/AAMkADU5NRaRqdoI4oeRpAAAB_wo
NAAA=/tentativelyAccept
Content-type: application/json
{
"comment": "Can you make the next day instead?",
"sendResponse": "true",
"proposedNewTime": {
"Start": {
"DateTime": "2019-08-16T12:00:00",
"TimeZone": "Pacific Standard Time"
},
"End": {
"DateTime": "2019-08-16T14:00:00",
"TimeZone": "Pacific Standard Time"
}
}
}
HTTP
The subject includes a prefix and says "New Time Proposed: Let's go for
lunch"
The sender is Adele Vance
The responseType is tentativelyAccepted
Adele's proposal is in the proposedNewTime property of the
eventMessageResponse
HTTP
GET https://graph.microsoft.com/v1.0/me/messages?$top=1
Prefer: outlook.timezone="Pacific Standard Time"
For demonstration purpose, assume Adele's reply is the latest message in Alex'
mailbox, and Alex can simply request that latest message.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
Preference-Applied: outlook.timezone="Pacific Standard Time"
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-
b4ab-004ae54f3747')/messages",
"@odata.nextLink": "https://graph.microsoft.com/v1.0/me/messages?
$top=1&$skip=4"",
"value": [
{
"@odata.type": "#microsoft.graph.eventMessageResponse",
"@odata.etag":
"W/\"DAAAABYAAAA0RfLCCxWuR42wWzJXJGu0AAACEGHC\"",
"id": "AAMkADAwJXJGu0AAACEiVAAAA=",
"createdDateTime": "2019-08-01T07:06:27Z",
"lastModifiedDateTime": "2019-08-01T07:06:28Z",
"changeKey": "DAAAABYAAAA0RfLCCxWuR42wWzJXJGu0AAACEGHC",
"categories": [],
"receivedDateTime": "2019-08-01T07:06:28Z",
"sentDateTime": "2019-08-01T07:06:24Z",
"hasAttachments": false,
"internetMessageId": "
<[email protected]>",
"subject": "New Time Proposed: Let's go for lunch",
"bodyPreview": "Can you make the next day instead?",
"importance": "normal",
"parentFolderId": "AQMkADAwQAAAIBDAAAAA==",
"conversationId": "AAQkADAwQAQAMkh89RO3QpBiUCETTtVbIo=",
"conversationIndex": "AdVINBlgySHz1E7dCkGJQIRNO1VsigAA4n6R",
"isDeliveryReceiptRequested": null,
"isReadReceiptRequested": false,
"isRead": false,
"isDraft": false,
"webLink": "https://outlook.office365.com/owa/?
ItemID=AAMkADAwJXJGu0AAACEiVAAAA%3D&exvsurl=1&viewmodel=ReadMessageItem
",
"inferenceClassification": "focused",
"unsubscribeData": [],
"unsubscribeEnabled": false,
"meetingMessageType": "meetingTentativelyAccepted",
"type": "singleInstance",
"isOutOfDate": false,
"isAllDay": false,
"isDelegated": false,
"responseType": "tentativelyAccepted",
"recurrence": null,
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-
Type\" content=\"text/html; charset=utf-8\">\r\n<meta
content=\"text/html; charset=us-ascii\">\r\n</head>\r\n<body>\r\nCan
you make the next day instead?\r\n</body>\r\n</html>\r\n"
},
"sender": {
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
},
"from": {
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
},
"toRecipients": [
{
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
],
"ccRecipients": [],
"bccRecipients": [],
"replyTo": [],
"flag": {
"flagStatus": "notFlagged"
},
"startDateTime": {
"dateTime": "2019-08-15T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"endDateTime": {
"dateTime": "2019-08-15T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"location": {
"displayName": "Harry's Bar",
"locationType": "default",
"uniqueIdType": "unknown"
},
"proposedNewTime": {
"start": {
"dateTime": "2019-08-16T12:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-16T14:00:00",
"timeZone": "Pacific Standard Time"
}
}
}
]
}
4. Alex also notices the event for the lunch now includes a proposedNewTime
property that indicates Adele's proposal. This property is only present as part of an
attendee instance if the corresponding attendee has suggested an alternative
meeting time.
HTTP
GET
https://graph.microsoft.com/v1.0/me/events/AAMkADAwJXJGu0AAACEhWOAAA=?
$select=subject,allowNewTimeProposals,start,end,attendees,organizer
Prefer: outlook.timezone="Pacific Standard Time"
HTTP
HTTP/1.1 200 Ok
{
"@odata.context":
"https://graph.microsoft.com/testexchangev1.0/$metadata#users('64339082
-ed84-4b0b-b4ab-
004ae54f3747')/events(subject,allowNewTimeProposals,start,end,attendees
,organizer)/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAAAhEDMA==\"",
"id": "AAMkADAwJXJGu0AAACEhWOAAA=",
"subject": "Let's go for lunch",
"allowNewTimeProposals": true,
"start": {
"dateTime": "2019-08-15T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-15T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"attendees": [
{
"type": "required",
"status": {
"response": "tentativelyAccepted",
"time": "2019-08-01T07:06:24.5046431Z"
},
"proposedNewTime": {
"start": {
"dateTime": "2019-08-16T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-16T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
}
},
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
}
5. Alex decides to accept Adele's proposal by updating the event to the proposed
start and end date/time.
HTTP
PATCH
https://graph.microsoft.com/v1.0/me/events/AAMkADAwJXJGu0AAACEhWOAAA=
Prefer: outlook.timezone="Pacific Standard Time"
Content-type: application/json
{
"start": {
"dateTime": "2019-08-16T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-16T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
}
}
HTTP
HTTP/1.1 200 Ok
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-
b4ab-004ae54f3747')/events/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAAAhBizA==\"",
"id": "AAMkADAwJXJGu0AAACEhWOAAA=",
"createdDateTime": "2019-08-01T06:41:07.805128Z",
"lastModifiedDateTime": "2019-08-01T08:21:43.5696529Z",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAAAhBizA==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Let's go for lunch",
"bodyPreview": "Does noon work for you?",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": true,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "busy",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADAwJXJGu0AAACEhWOAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"allowNewTimeProposals": true,
"recurrence": null,
"responseStatus": {
"response": "organizer",
"time": "0001-01-01T00:00:00Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nDoes noon work for you?
\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-08-16T12:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-08-16T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"location": {
"displayName": "Harry's Bar",
"locationType": "default",
"uniqueId": "Harry's Bar",
"uniqueIdType": "private"
},
"locations": [
{
"displayName": "Harry's Bar",
"locationType": "default",
"uniqueId": "Harry's Bar",
"uniqueIdType": "private"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "notResponded",
"time": "4501-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
}
See also
Finding possible meeting times on the Outlook calendar
Getting the free/busy schedule for users and resources
Scheduling repeating appointments as recurring events in Outlook
Create or set an event as an online
meeting in an Outlook calendar
Article • 04/19/2023
Use the Outlook calendar API to organize an event where meeting invitees can select a
join URL and attend the meeting online in Microsoft Teams or Skype.
7 Note
The calendar API lets you conveniently set up an online meeting in an Outlook
calendar where attendees can click to join the meeting and continue their
experience in Teams or Skype. For a more customized, richer integration with Teams
or Skype, use the cloud communications API. See Choose an API in Microsoft
Graph to create and join online meetings for more information.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/calendar
Response
HTTP
HTTP/1.1 200 Ok
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/calendar/$entity",
"id": "AQMkADAwAGVAAAJfygAAAA==",
"name": "Calendar",
"color": "auto",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAAAAACOg==",
"canShare": true,
"canViewPrivateItems": true,
"canEdit": true,
"allowedOnlineMeetingProviders": [
"teamsForBusiness",
"skypeForBusiness"
],
"defaultOnlineMeetingProvider": "teamsForBusiness",
"isTallyingResponses": true,
"isRemovable": false,
"owner": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
7 Note
Once you enable a meeting online, Microsoft Graph sets the meeting information
in onlineMeeting. Subsequently, you cannot change the onlineMeetingProvider
property, nor set isOnlineMeeting to false to disable the meeting online.
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/me/events
Prefer: outlook.timezone="Pacific Standard Time"
Content-type: application/json
{
"subject": "Prep for customer meeting",
"body": {
"contentType": "HTML",
"content": "Does this time work for you?"
},
"start": {
"dateTime": "2019-11-20T13:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-11-20T14:00:00",
"timeZone": "Pacific Standard Time"
},
"location":{
"displayName":"Cordova conference room"
},
"attendees": [
{
"emailAddress": {
"address":"[email protected]",
"name": "Adele Vance"
},
"type": "required"
}
],
"allowNewTimeProposals": true,
"isOnlineMeeting": true,
"onlineMeetingProvider": "teamsForBusiness"
}
Response
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/events/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAASBUEsA==\"",
"id": "AAMkADAAABIGYDZAAA=",
"createdDateTime": "2019-11-15T01:55:54.8022848Z",
"lastModifiedDateTime": "2019-11-15T01:55:56.5162924Z",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAASBUEsA==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"iCalUId":
"040000008200E00074C5B7101A82E0080000000076B29D94B32CD6010000000000000000100
000005F31C591C3C328459653D025BD277439",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Prep for customer meeting",
"bodyPreview": "Does this time work for you?
\r\n________________________________________________________________________
________\r\nJoin Microsoft Teams Meeting\r\n+1 323-555-0166 United States,
Los Angeles (Toll)\r\nConference ID: 291 633 251#\r\nLocal numbers | Reset
PIN | Lea",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": true,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "busy",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADAABIGYDZAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"isOnlineMeeting": true,
"onlineMeetingProvider": "teamsForBusiness",
"allowNewTimeProposals": true,
"recurrence": null,
"responseStatus": {
"response": "organizer",
"time": "0001-01-01T00:00:00Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nDoes this time work for you?
\r\n<div style=\"width:100%; height:20px\"><span style=\"white-space:nowrap;
color:gray;
opacity:.36\">______________________________________________________________
__________________</span>\r\n</div>\r\n<div class=\"me-email-text\"
style=\"color:#252424; font-family:'Segoe UI','Helvetica
Neue',Helvetica,Arial,sans-serif\">\r\n<div style=\"margin-top:24px; margin-
bottom:10px\"><a class=\"me-email-headline\"
href=\"https://teams.microsoft.com/l/meetup-
join/19%3ameeting_ODkyNWFmNGYtZjBjYS00MDdlLTllOWQtN2E3MzJlNjM0ZWRj%40thread.
v2/0?context=%7b%22Tid%22%3a%2298a79ebe-74bf-4e07-a017-
7b410848cb32%22%2c%22Oid%22%3a%2264339082-ed84-4b0b-b4ab-
004ae54f3747%22%7d\" target=\"_blank\" rel=\"noreferrer noopener\"
style=\"font-size:18px; font-family:'Segoe UI Semibold','Segoe
UI','Helvetica Neue',Helvetica,Arial,sans-serif; text-decoration:underline;
color:#6264a7\">Join\r\n Microsoft Teams Meeting</a>
</div>\r\n<div>\r\n<div><a class=\"me-email-link\" href=\"tel:+1 323-
886-7531,,291633251# \" target=\"_blank\" rel=\"noreferrer noopener\"
style=\"font-size:14px; text-decoration:none; color:#6264a7\">+1 323-
886-7531</a>\r\n<span style=\"font-size:12px\"> United States, Los
Angeles (Toll) </span></div>\r\n</div>\r\n<div style=\"margin-top:10px;
margin-bottom:20px\"><span style=\"font-size:12px\">Conference
ID:\r\n</span><span style=\"font-size:14px\">291 633 251# </span>
</div>\r\n<div style=\"margin-bottom:24px\"><a class=\"me-email-link\"
target=\"_blank\" href=\"https://dialin.teams.microsoft.com/1f9a0550-737c-
41bd-8c7d-4c81dc1c4070?id=291633251\" rel=\"noreferrer noopener\"
style=\"font-size:12px; text-decoration:none; color:#6264a7\">Local\r\n
numbers</a> | <a class=\"me-email-link\" target=\"_blank\"
href=\"https://mysettings.lync.com/pstnconferencing\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nReset PIN</a> | <a class=\"me-email-link\"
target=\"_blank\" href=\"https://aka.ms/JoinTeamsMeeting\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nLearn more about Teams</a> | <a class=\"me-email-link\"
target=\"_blank\" href=\"https://teams.microsoft.com/meetingOptions/?
organizerId=64339082-ed84-4b0b-b4ab-004ae54f3747&tenantId=98a79ebe-74bf-
4e07-a017-
7b410848cb32&threadId=19_meeting_ODkyNWFmNGYtZjBjYS00MDdlLTllOWQtN2E3MzJ
[email protected]&messageId=0&language=en-US\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nMeeting options</a> </div>\r\n<div style=\"font-
size:14px; margin-bottom:4px\"></div>\r\n<div style=\"font-size:12px\">
</div>\r\n</div>\r\n<div style=\"width:100%; height:20px\"><span
style=\"white-space:nowrap; color:gray;
opacity:.36\">______________________________________________________________
__________________</span>\r\n</div>\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-11-20T13:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-11-20T14:00:00.0000000",
"timeZone": "Pacific Standard Time"
},
"location": {
"displayName": "Cordova conference room",
"locationType": "default",
"uniqueId": "Cordova conference room",
"uniqueIdType": "private"
},
"locations": [
{
"displayName": "Cordova conference room",
"locationType": "default",
"uniqueId": "Cordova conference room",
"uniqueIdType": "private"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
},
"onlineMeeting": {
"joinUrl": "https://teams.microsoft.com/l/meetup-
join/19%3ameeting_ODkyNWFmNGYtZjBjYS00MDdlLTllOWQtN2E3MzJlNjM0ZWRj%40thread.
v2/0?context=%7b%22Tid%22%3a%2298a79ebe-74bf-4e07-a017-
7b410848cb32%22%2c%22Oid%22%3a%2264339082-ed84-4b0b-b4ab-
004ae54f3747%22%7d",
"conferenceId": "291633251",
"tollNumber": "+1 323-555-0166"
}
}
) Important
Access the URL to join a meeting using joinUrl, available via the onlineMeeting
property of the event. Do not use the onlineMeetingUrl property of the event
because onlineMeetingUrl will soon be deprecated.
Request
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/events/AAMkADAGu0AABIGYDZAAA=?
$select=isOnlineMeeting,onlineMeetingProvider,onlineMeeting
Response
HTTP
HTTP/1.1 200 Ok
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/events(isOnlineMeeting,onlineMeetingProvider,onlineMeeting)/$
entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAASBUExA==\"",
"id": "AAMkADAGu0AABIGYDZAAA=",
"isOnlineMeeting": true,
"onlineMeetingProvider": "teamsForBusiness",
"onlineMeeting": {
"joinUrl": "https://teams.microsoft.com/l/meetup-
join/19%3ameeting_ODkyNWFmNGYtZjBjYS00MDdlLTllOWQtN2E3MzJlNjM0ZWRj%40thread.
v2/0?context=%7b%22Tid%22%3a%2298a79ebe-74bf-4e07-a017-
7b410848cb32%22%2c%22Oid%22%3a%2264339082-ed84-4b0b-b4ab-
004ae54f3747%22%7d",
"conferenceId": "291633251",
"tollNumber": "+1 323-555-0166"
}
}
7 Note
Once you enable a meeting online, Microsoft Graph sets the meeting information
in onlineMeeting. Subsequently, you cannot change the onlineMeetingProvider
property, nor set isOnlineMeeting to false to disable the meeting online.
Request
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/me/events/AAMkADAGu0AABIGYDaAAA=
{
"isOnlineMeeting": true,
"onlineMeetingProvider": "teamsForBusiness"
}
Response
HTTP
HTTP/1.1 200 Ok
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/events/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAASBUFEA==\"",
"id": "AAMkADAGu0AABIGYDaAAA=",
"createdDateTime": "2019-11-15T02:13:38.5558455Z",
"lastModifiedDateTime": "2019-11-15T02:15:00.0654529Z",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAASBUFEA==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"iCalUId":
"040000008200E00074C5B7101A82E00800000000CD93094B5A9BD5010000000000000000100
00000A16AF77C6F6C254EA13F69C3B2808B4A",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Price strategy",
"bodyPreview": "Let's define our
strategy.\r\n_______________________________________________________________
_________________\r\nJoin Microsoft Teams Meeting\r\n+1 323-555-0166
United States, Los Angeles (Toll)\r\nConference ID: 275 984 951#\r\nLocal
numbers | Reset PIN | Learn",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": true,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "busy",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADAGu0AABIGYDaAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"isOnlineMeeting": true,
"onlineMeetingProvider": "teamsForBusiness",
"allowNewTimeProposals": true,
"recurrence": null,
"responseStatus": {
"response": "organizer",
"time": "0001-01-01T00:00:00Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\n<div>Let's define our strategy.
</div>\r\n<div style=\"width:100%; height:20px\"><span style=\"white-
space:nowrap; color:gray;
opacity:.36\">______________________________________________________________
__________________</span>\r\n</div>\r\n<div class=\"me-email-text\"
style=\"color:#252424; font-family:'Segoe UI','Helvetica
Neue',Helvetica,Arial,sans-serif\">\r\n<div style=\"margin-top:24px; margin-
bottom:10px\"><a class=\"me-email-headline\"
href=\"https://teams.microsoft.com/l/meetup-
join/19%3ameeting_NTRkMWViMmEtNzcxNC00OTk3LWJjOTEtYTdhMDU3ZmJhYWFi%40thread.
v2/0?context=%7b%22Tid%22%3a%2298a79ebe-74bf-4e07-a017-
7b410848cb32%22%2c%22Oid%22%3a%2264339082-ed84-4b0b-b4ab-
004ae54f3747%22%7d\" target=\"_blank\" rel=\"noreferrer noopener\"
style=\"font-size:18px; font-family:'Segoe UI Semibold','Segoe
UI','Helvetica Neue',Helvetica,Arial,sans-serif; text-decoration:underline;
color:#6264a7\">Join\r\n Microsoft Teams Meeting</a>
</div>\r\n<div>\r\n<div><a class=\"me-email-link\" href=\"tel:+1 323-
886-7531,,275984951# \" target=\"_blank\" rel=\"noreferrer noopener\"
style=\"font-size:14px; text-decoration:none; color:#6264a7\">+1 323-
886-7531</a>\r\n<span style=\"font-size:12px\"> United States, Los
Angeles (Toll) </span></div>\r\n</div>\r\n<div style=\"margin-top:10px;
margin-bottom:20px\"><span style=\"font-size:12px\">Conference
ID:\r\n</span><span style=\"font-size:14px\">275 984 951# </span>
</div>\r\n<div style=\"margin-bottom:24px\"><a class=\"me-email-link\"
target=\"_blank\" href=\"https://dialin.teams.microsoft.com/1f9a0550-737c-
41bd-8c7d-4c81dc1c4070?id=275984951\" rel=\"noreferrer noopener\"
style=\"font-size:12px; text-decoration:none; color:#6264a7\">Local\r\n
numbers</a> | <a class=\"me-email-link\" target=\"_blank\"
href=\"https://mysettings.lync.com/pstnconferencing\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nReset PIN</a> | <a class=\"me-email-link\"
target=\"_blank\" href=\"https://aka.ms/JoinTeamsMeeting\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nLearn more about Teams</a> | <a class=\"me-email-link\"
target=\"_blank\" href=\"https://teams.microsoft.com/meetingOptions/?
organizerId=64339082-ed84-4b0b-b4ab-004ae54f3747&tenantId=98a79ebe-74bf-
4e07-a017-
7b410848cb32&threadId=19_meeting_NTRkMWViMmEtNzcxNC00OTk3LWJjOTEtYTdhMDU
[email protected]&messageId=0&language=en-US\" rel=\"noreferrer
noopener\" style=\"font-size:12px; text-decoration:none;
color:#6264a7\">\r\nMeeting options</a> </div>\r\n<div style=\"font-
size:14px; margin-bottom:4px\"></div>\r\n<div style=\"font-size:12px\">
</div>\r\n</div>\r\n<div style=\"width:100%; height:20px\"><span
style=\"white-space:nowrap; color:gray;
opacity:.36\">______________________________________________________________
__________________</span>\r\n</div>\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-11-18T23:00:00.0000000",
"timeZone": "UTC"
},
"end": {
"dateTime": "2019-11-19T00:00:00.0000000",
"timeZone": "UTC"
},
"location": {
"displayName": "Conf Room Baker",
"locationType": "conferenceRoom",
"uniqueId": "[email protected]",
"uniqueIdType": "directory"
},
"locations": [
{
"displayName": "Conf Room Baker",
"locationType": "conferenceRoom",
"uniqueId": "[email protected]",
"uniqueIdType": "directory"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
},
"onlineMeeting": {
"joinUrl": "https://teams.microsoft.com/l/meetup-
join/19%3ameeting_NTRkMWViMmEtNzcxNC00OTk3LWJjOTEtYTdhMDU3ZmJhYWFi%40thread.
v2/0?context=%7b%22Tid%22%3a%2298a79ebe-74bf-4e07-a017-
7b410848cb32%22%2c%22Oid%22%3a%2264339082-ed84-4b0b-b4ab-
004ae54f3747%22%7d",
"conferenceId": "275984951",
"tollNumber": "+1 323-555-0166"
}
}
See also
For information on Microsoft Teams interoperability with Microsoft 365, see:
How Exchange and Microsoft Teams interact
Setting your coexistence and upgrade settings
Choose an API in Microsoft Graph to create and join online meetings
Finding possible meeting times on the Outlook calendar
Getting the free/busy schedule for users and resources
Propose meeting times in an Outlook calendar (preview)
Scheduling repeating appointments as recurring events in Outlook
Choose an API in Microsoft Graph to
create and join online meetings
Article • 11/15/2022
Microsoft Graph offers two API sets that arrange and join online meetings on Microsoft
Teams or Skype:
Programmatic support:
Apps can directly create or update an event as an online meeting in the Outlook
calendar, with a join-Teams-meeting blob inserted in the Outlook calendar
event.
Apps get properties for joining meeting over the Internet or by dialing in.
Attendees' UI experience with the programmatically created calendar event is in
full parity with any event that has been created through the Outlook UI:
Attendees can choose to meet online or in person.
Attendees can click in the join-Teams-meeting blob to join meeting over the
Internet or by dialing in.
Attendees can use other rich features of Teams, including video conferencing
and meeting lobby, if configured.
7 Note
Integration with Outlook calendar assumes an administrator has set up Outlook for
online meetings. Verify the support before using the API.
Choose the cloud communications API for flexibility and broader programmatic support:
Apps have more flexibility to further integrate the API results with line of business
and other apps. The API is decoupled with any specific calendar, and does not
create an event in any calendar.
Apps can provide the following capabilities for attendees:
Locale-based join information.
Joining meeting over the Internet or by dialing in.
Video-conferencing.
Additional security features such as meeting lobby and automating attendee
admission (preview).
Associating meeting with a Microsoft Teams chat.
Meeting lobby - No direct API integration. - API differentiates attendees from the
and - In the injected join-Teams- organizer’s company and federated
automating meeting blob of the event, companies, and other attendees including
attendee attendee can click a Meeting anonymous ones.
admission into options link to access meeting - Use the lobbyBypassSettings property.
online lobby, if enabled by the
meeting administrator.
Recurring events are an important part of Outlook calendaring. Whether it's a weekly
one-on-one meeting with your manager or a division-wide review meeting that happens
on the second Tuesday of each month, recurring events make it easy to create the event
once and let the server fill in the rest of the series.
The key bit of information that allows recurring events to "expand" into individual
occurrences is the recurrence rule. The rule specifies both how often an event repeats
and for how long. The Outlook REST APIs model recurrence rules in the recurrence
property of the event resource.
Each recurrence is made up of two parts: the recurrence pattern (how often) and the
recurrence range (for how long).
Recurrence patterns
The first part of a recurrence is the pattern. This specifies how often the event repeats.
For example, an event could repeat "every 3 days," "every Thursday," or "on July 22
every year." A pattern is represented in the API by the recurrencePattern resource.
Depending on the type of pattern, certain fields of the recurrencePattern are required,
optional, or ignored.
7 Note
Even if a field is ignored, it is still validated. If a field has a set list of possible values,
using a value outside the allowed set causes an error, even if that field is ignored.
Daily
The daily recurrence pattern causes an event to repeat based on a number of days
between each occurrence.
Relevant properties
Property Relevance Description
Examples
Repeat this event every day
JSON
"pattern": {
"type": "daily",
"interval": 1
}
JSON
"pattern": {
"type": "daily",
"interval": 3
}
Weekly
The weekly recurrence pattern causes an event to repeat on the same day or days of the
week, based on the number of weeks between each set of occurrences.
Relevant properties
daysOfWeek Required Specifies on which day(s) of the week the event occurs.
firstDayOfWeek Optional Specifies which day is considered the first day of the week.
Default value: Sunday .
interval Required Specifies the number of weeks between each set of occurrences.
JSON
"pattern": {
"type": "weekly",
"interval": 1,
"daysOfWeek": [ "Thursday" ]
}
JSON
"pattern": {
"type": "weekly",
"interval": 2,
"daysOfWeek": [
"Monday",
"Tuesday"
]
}
Absolute monthly
The absolute monthly pattern causes an event to repeat on the same day of the month
(for example, the 15th), based on the number of months between each occurrence.
Relevant properties
dayOfMonth Required Specifies on which day of the month the event occurs.
Examples
Repeat this event on the 15th of every month
JSON
"pattern": {
"type": "absoluteMonthly",
"interval": 1,
"dayOfMonth": 15
}
JSON
"pattern": {
"type": "absoluteMonthly",
"interval": 3,
"dayOfMonth": 7
}
Relative monthly
The relative monthly pattern causes an event to repeat on the same day of the week in
the same relative position in the month, based on the number of months between each
occurrence. For example, "every second Wednesday of the month."
Relevant properties
daysOfWeek Required Specifies on which day(s) of the week the event can occur. Relative
monthly events only occur once per month, so if more than one
value is specified, the event falls on the first day that satisfies the
pattern.
Examples
Repeat this event on the second Wednesday of every month
JSON
"pattern": {
"type": "relativeMonthly",
"interval": 1,
"daysOfWeek": [ "Wednesday" ],
"index": "second"
}
JSON
"pattern": {
"type": "relativeMonthly",
"interval": 1,
"daysOfWeek": [ "Thursday", "Friday" ],
"index": "first"
}
Absolute yearly
The absolute yearly pattern causes an event to repeat on the same month and day (for
example, April 15), based on the number of years between each occurrence.
Relevant properties
dayOfMonth Required Specifies on which day of the month the event occurs.
Example
Repeat this event on April 15 every year
JSON
"pattern": {
"type": "absoluteYearly",
"interval": 1,
"dayOfMonth": 15,
"month": 4
}
Relative yearly
The relative yearly pattern causes an event to repeat on the same day of the week in the
same relative position in a specific month, based on the number of years between each
occurrence. For example, "every last Wednesday of November."
Relevant properties
daysOfWeek Required Specifies on which day(s) of the week the event can occur. Relative
yearly events only occur once per year, so if more than one value is
specified, the event falls on the first day that satisfies the pattern.
Examples
JSON
"pattern": {
"type": "relativeYearly",
"interval": 1,
"daysOfWeek": [ "Wednesday" ],
"index": "last",
"month": 11
}
Recurrence ranges
The second part of a recurrence is the range. This specifies how long the pattern
repeats. For example, an event could end after 10 occurrences, by a specific date, or
could have no end. A range is represented in the API by the recurrenceRange resource.
7 Note
Even if a field is ignored, it is still validated. If a field has a set list of possible values,
using a value outside the allowed set causes an error, even if that field is ignored.
Numbered range
The numbered range causes an event to occur a fixed number of times (based on the
pattern) from a start date.
Relevant properties
recurrenceTimeZone Optional Specifies the time zone for the startDate property. If not
specified, the time zone of the event is used.
startDate Required Specifies the date to start applying the pattern. The value
of startDate MUST correspond to the date value of the
start property on the event resource. Note that the first
occurrence of the meeting may not occur on this date if it
does not fit the pattern.
Examples
Repeat this event 10 times
JSON
"range": {
"type": "numbered",
"startDate": "2017-04-02",
"numberOfOccurrences": 10
}
Relevant properties
endDate Required Specifies the date to stop applying the pattern. Note that the
last occurrence of the meeting may not occur on this date if
it does not fit the pattern.
recurrenceTimeZone Optional Specifies the time zone for the startDate and endDate
properties. If not specified, the time zone of the event is
used.
startDate Required Specifies the date to start applying the pattern. The value of
startDate MUST correspond to the date value of the start
property on the event resource. Note that the first
occurrence of the meeting may not occur on this date if it
does not fit the pattern.
Examples
JSON
"range": {
"type": "endDate",
"startDate": "2017-07-01",
"endDate": "2017-07-31"
}
No end range
The no end range causes an event to occur on all days that fit the applicable pattern
after a start date.
Relevant properties
recurrenceTimeZone Optional Specifies the time zone for the startDate property. If not
specified, the time zone of the event is used.
startDate Required Specifies the date to start applying the pattern. The value of
startDate MUST correspond to the date value of the start
property on the event resource. Note that the first
occurrence of the meeting may not occur on this date if it
does not fit the pattern.
Examples
Repeat this event from May 15, 2017, forever
JSON
"range": {
"type": "noEnd",
"startDate": "2017-05-15"
}
Examples
Meet from 1:00 PM to 1:30 PM every Monday starting September 4, 2017, until
the end of the year
The "every Monday" requirement is easily met by the weekly recurrence pattern
type.
The "until the end of the year" requirement indicates an endDate recurrence
range type.
JSON
"recurrence": {
"pattern": {
"type": "weekly",
"interval": 1,
"daysOfWeek": [ "Monday" ]
},
"range": {
"type": "endDate",
"startDate": "2017-09-04",
"endDate": "2017-12-31"
}
}
Because December 31, 2017, is on a Sunday, the last occurrence in this series will
be on Monday, December 25.
Meet from 2:00 PM to 3:00 PM on the first Thursday of every other month
starting August 29, 2017
The "first Thursday of every other month" requirement is achievable by using a
relative monthly pattern. The "every other month" portion indicates that the
interval should be set to 2 .
Because there is no requirement on an end date, a noEnd range type can be
used.
JSON
"recurrence": {
"pattern": {
"type": "relativeMonthly",
"interval": 2,
"daysOfWeek": [ "Thursday" ],
"index": "first"
},
"range": {
"type": "noEnd",
"startDate": "2017-08-29"
}
}
Because the value of startDate is after the first Thursday in August, the first
occurrence of this series will be in September.
Next steps
Find out more about integrating with Outlook calendar.
See other recurring event examples in the calendar API reference:
Create a recurring event that occurs once a week
Create a daily recurring event
Share or delegate a calendar in Outlook
Article • 03/02/2023
In Outlook, a calendar owner can share the calendar with another user. The owner can
specify which information in non-private events is viewable, and can give write access to
the calendar to users in the same organization.
The owner can also delegate another user to manage meetings in the owner's primary
calendar. Delegates are sharees who can view all information in and have write access to
non-private events. They also receive meeting requests and responses, and respond to
meeting requests on behalf of the owner. Additionally, the owner can give explicit
permissions to delegates to view the owner's private events on the calendar.
Before calendar sharing or delegation can take effect, the owner sends a sharee or
delegate an invitation, and the sharee or delegate accepts the invitation, or, explicitly
adds the shared or delegated calendar for access. The invitation and adding a shared or
delegated calendar occur in an Outlook client.
After sharing or delegation is set up in Outlook, apps can then use the Microsoft Graph
API to manage the sharing and delegation.
Alex Wilber has delegated Megan Bowen to his primary calendar, and also
permitted Megan to view private events in that calendar.
Alex shared a "Kids parties" calendar with Adele Vance and Megan Bowen, and
gave both Adele and Megan read permissions to all the details of non-private
events on the "Kids parties" calendar, and free/busy status for private events.
This article describes programmatically carrying out the following tasks with a shared or
delegated calendar:
Get calendar information about sharees, delegates, and allowed permissions, and
update individual permissions.
Get the properties that describe the sharing or delegation of the calendar.
Get or set mailbox setting to receive meeting requests and responses for a
delegated calendar.
Delete a sharee or delegate of a calendar.
Apps can also do the following using API that is generally available:
The properties and API for calendar sharing and delegating as described in this
topic are currently available in the v1.0 endpoint, with the exception of the calendar
properties isShared and isSharedWithMe. These two properties are exposed in
only the beta endpoint.
none This value applies to only My Organization which does not have any
permissions to the calendar. It doesn't apply to individual users, as only users with
permissions are associated with a calendarPermission object for the calendar.
freeBusyRead The sharee can view the owner's free/busy status, but not other
view all the details and edit (create, update, or delete) non-private events on the
calendar.
delegateWithoutPrivateEventAccess The delegate can view the owner's free/busy
status in private events, and has write access to non-private events on the
calendar.
delegateWithPrivateEventAccess The delegate can view details of the owner's
private and non-private events, and has write access to all the events on the
calendar.
The primary calendar of a user is always shared with "My Organization", which
represents the users in the same organization as the owner. By default, they can read
the owner's free/busy status on that calendar and have the freeBusyRead permission.
The first calendarPermission object is assigned to the delegate, Megan, and has
the following property values:
isRemovable is set to true, providing Alex the option to cancel the delegation.
isInsideOrganization is true as only users in the same organization can be
delegates.
role for Megan is delegateWithPrivateEventAccess , as set up by Alex.
allowedRoles includes the role types delegateWithoutPrivateEventAccess and
delegateWithPrivateEventAccess that support delegation.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/users/[email protected]/cal
endar/calendarPermissions
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/calendar/calendarPermissions",
"value": [
{
"id": "L289RXhjaGFuZ2VMYWJTWVnYW5C",
"isRemovable": true,
"isInsideOrganization": true,
"role": "delegateWithPrivateEventAccess",
"allowedRoles": [
"freeBusyRead",
"limitedRead",
"read",
"write",
"delegateWithoutPrivateEventAccess",
"delegateWithPrivateEventAccess"
],
"emailAddress": {
"name": "Megan Bowen",
"address": "[email protected]"
}
},
{
"id": "RGVmYXVsdA==",
"isRemovable": false,
"isInsideOrganization": true,
"role": "freeBusyRead",
"allowedRoles": [
"none",
"freeBusyRead",
"limitedRead",
"read",
"write"
],
"emailAddress": {
"name": "My Organization"
}
}
]
}
Aside from the role property, you cannot update other properties of an existing sharee
or delegate. Changing the emailAddress property value requires deleting the sharee or
delegate and setting up a new instance of calendarPermission again.
The example in this section updates the role property, changing the permission of an
existing sharee, Adele, from read to write for the custom calendar "Kids parties".
HTTP
HTTP
PATCH
https://graph.microsoft.com/beta/users/[email protected]/cal
endars/AAMkADAwAABf02bAAAA=/calendarPermissions/L289RXhjaGFuZ2VMYWJQWRlb
GVW
Content-type: application/json
{
"role": "write"
}
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/calendars('AAMkADAwAABf02bAAAA%3D')/calendarPermissions/$enti
ty",
"id": "L289RXhjaGFuZ2VMYWJQWRlbGVW",
"isRemovable": true,
"isInsideOrganization": true,
"role": "write",
"allowedRoles": [
"freeBusyRead",
"limitedRead",
"read",
"write"
],
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
Recalling in this example, Alex has delegated his primary calendar and given the
delegate, Megan Bowen, the permission to view calendar items that are marked private.
This section shows the properties of the delegated calendar, first from the perspective of
and with the consent of the owner, Alex, and then from the perspective of and with the
consent of the delegate, Megan. Consent from the administrator also works for each
case.
HTTP
GET
https://graph.microsoft.com/beta/users/[email protected]/cal
endar
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/calendar/$entity",
"id": "AQMkADAw7QAAAJfygAAAA==",
"name": "Calendar",
"color": "auto",
"hexColor": "",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAAAAACOg==",
"canShare": true,
"canViewPrivateItems": true,
"isShared": true,
"isSharedWithMe": false,
"canEdit": true,
"allowedOnlineMeetingProviders": [
"teamsForBusiness"
],
"defaultOnlineMeetingProvider": "teamsForBusiness",
"isTallyingResponses": true,
"isRemovable": false,
"owner": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
7 Note
HTTP
HTTP
GET
https://graph.microsoft.com/beta/users/[email protected]/ca
lendars/AAMkADlAABhbftjAAA=
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('meganb%40contoso.OnMicros
oft.com')/calendars/$entity",
"id": "AAMkADlAABhbftjAAA=",
"name": "Alex Wilber",
"color": "auto",
"hexColor": "",
"changeKey": "E6LznKWmX0KTsAD9qRJjeAAAYWo3EQ==",
"canShare": false,
"canViewPrivateItems": true,
"isShared": false,
"isSharedWithMe": true,
"canEdit": true,
"allowedOnlineMeetingProviders": [
"teamsForBusiness"
],
"defaultOnlineMeetingProvider": "teamsForBusiness",
"isTallyingResponses": true,
"isRemovable": true,
"owner": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
Depending on the level of delegation a calendar owner prefers, the owner can specify
who should receive meeting requests and responses to manage meetings on the
calendar.
sendToDelegateOnly
sendToDelegateAndInformationToPrincipal
sendToDelegateAndPrincipal
This is a mailbox-wide setting, so the same setting applies to all delegates of the
mailbox owner.
HTTP
HTTP
GET
https://graph.microsoft.com/beta/users/[email protected]/mai
lboxsettings
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/mailboxSettings",
"archiveFolder": "AQMkADAwAGVQAAAKfowAAAA==",
"timeZone": "Pacific Standard Time",
"delegateMeetingMessageDeliveryOptions": "sendToDelegateOnly",
"dateFormat": "M/d/yyyy",
"timeFormat": "h:mm tt",
"automaticRepliesSetting": {
"status": "disabled",
"externalAudience": "all",
"internalReplyMessage": "",
"externalReplyMessage": "",
"scheduledStartDateTime": {
"dateTime": "2019-12-24T05:00:00.0000000",
"timeZone": "UTC"
},
"scheduledEndDateTime": {
"dateTime": "2019-12-25T05:00:00.0000000",
"timeZone": "UTC"
}
},
"language": {
"locale": "en-US",
"displayName": "English (United States)"
},
"workingHours": {
"daysOfWeek": [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday"
],
"startTime": "08:00:00.0000000",
"endTime": "17:00:00.0000000",
"timeZone": {
"name": "Pacific Standard Time"
}
}
}
HTTP
HTTP
PATCH
https://graph.microsoft.com/beta/users/[email protected]/mai
lboxsettings
Content-type: application/json
{
"delegateMeetingMessageDeliveryOptions": "sendToDelegateAndPrincipal"
}
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/mailboxSettings",
"delegateMeetingMessageDeliveryOptions": "sendToDelegateAndPrincipal"
}
HTTP
HTTP
DELETE
https://graph.microsoft.com/beta/users/[email protected]/cal
endars/AAMkADAwAABf02bAAAA=/calendarPermissions/L289RXhjaGFuZ2VMYWJTWVnY
W5C
HTTP
In Outlook, a calendar owner can share a calendar with other users and let them view or
modify events in that calendar; the shared calendar can be the owner's primary calendar
or a custom calendar created by the owner. The owner can also grant a delegate to their
primary calendar and act on their behalf to receive or respond to meeting requests or
create or change items in the primary calendar.
The three examples specify the owner's identity (Alex' user ID or user principal name)
and the calendar shortcut. They access calendar and event IDs that correspond to only
the owner's mailbox. Specifying these calendar and event IDs in the sharee's mailbox
(Megan's user ID or user principal name) would return an error. To use calendar and
event IDs that correspond to the sharee's mailbox, see Sharee: Get shared, custom
calendar or its events from sharee's mailbox.
7 Note
HTTP
On successful completion, you'll get HTTP 200 OK and a calendar instance that
represents Alex' shared, primary calendar, in Alex' mailbox.
HTTP
On successful completion, you'll get HTTP 200 OK and the event instance identified by
{id} in Alex' primary calendar, directly from Alex' mailbox.
HTTP
The same GET capabilities apply if Alex has delegated Megan access to Alex' primary
calendar, or if Alex has delegated Megan his entire mailbox.
If Alex has not shared nor delegated his primary calendar with Megan, specifying Alex’s
user ID or user principal name in the preceding GET operations will return an error.
1. Signed in as Adele, use either of the following requests to get all the calendars that
Adele has access to, including the shared custom calendar.
HTTP
GET https://graph.microsoft.com/v1.0/me/calendars
GET https://graph.microsoft.com/v1.0/users/{Adele-userId | Adele-
userPrincipalName}/calendars
A successful response includes the response code HTTP 200, and the collection of
calendars that Adele has access to, including the calendar ("Kids parties") that has
the owner name as "Alex Wilber" as the second calendar in the response. For a
sharee, Adele, the canShare property of the shared calendar is always false.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('d3b9214b-dd8b-441d-
b7dc-c446c9fa0e69')/calendars",
"value": [
{
"id": "AQMkADU5NAAAJMjAAAAA==",
"name": "Calendar",
"color": "auto",
"changeKey": "NDznl+Uh50WkanaCOKHkaQAAAAACXQ==",
"canShare": true,
"canViewPrivateItems": true,
"canEdit": true,
"owner": {
"name": "Adele Vance",
"address": "[email protected]"
}
},
{
"id": "AAMkADAABf0JlyAAA=",
"name": "Kids parties",
"color": "lightYellow",
"changeKey": "NDznl+Uh50WkanaCOKHkaQAAYumJRQ==",
"canShare": false,
"canViewPrivateItems": false,
"canEdit": false,
"owner": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
]
}
2. Signed in as Adele, get the shared calendar, or get one or more events in the
shared calendar, using the second calendar ID in the response from step 1. The IDs
of the shared calendar and its event correspond to the local copy of Alex' calendar
in Adele's mailbox.
HTTP
GET https://graph.microsoft.com/v1.0/me/calendars/AAMkADAABf0JlyAAA=
GET https://graph.microsoft.com/v1.0/users/{Adele-userId | Adele-
userPrincipalName}/calendars/AAMkADAABf0JlyAAA=
GET
https://graph.microsoft.com/v1.0/me/calendars/AAMkADAABf0JlyAAA=/events
/{id}
GET https://graph.microsoft.com/v1.0/users/{Adele-userId | Adele-
userPrincipalName}/calendars/AAMkADAABf0JlyAAA=/events/{id}
GET
https://graph.microsoft.com/v1.0/me/calendars/AAMkADAABf0JlyAAA=/events
GET https://graph.microsoft.com/v1.0/users/{Adele-userId | Adele-
userPrincipalName}/calendars/AAMkADAABf0JlyAAA=/events
On successful completion, you'll get HTTP 200 OK and the requested event, events, or
calendar that Alex has shared with Adele.
Next steps
Find out more about:
In Outlook, customers can share a calendar with other users and let them view, create,
or modify events in that calendar. Customers can also grant a delegate to act on their
behalf to receive or respond to meeting requests or create or change items in the
calendar.
The walkthrough below uses the example scenario where Alex has delegated his primary
calendar to Adele in Outlook, and kept the default Outlook mailbox setting to direct
meeting requests and responses to only delegates. (This setting corresponds to the
delegateMeetingMessageDeliveryOptions property of Alex' mailboxSettings set as the
default value sendToDelegateOnly .)
If Alex has shared and not delegated his calendar with Adele:
Signed in as Adele, an app can get the calendar that Alex has shared with Adele.
The app can use the requests and responses in steps 2 to 4 to apply to the shared
calendar the same way as the delegated calendar.
In step 5, the app can sign in as Alex, instead of Adele, to receive Christie's
response message.
Step 1: Adele gets the delegated calendar
Signed in as Adele, get the calendars she has access to and identify the one Alex has
delegated to her, so to use it in the next step to create an event in that calendar.
HTTP
HTTP
GET https://graph.microsoft.com/v1.0/me/calendars
Notice a successful response includes the response code HTTP 200, Adele's own primary
calendar, and a copy of the calendar delegated by Alex in Adele's mailbox, with the
following properties:
canShare is false since Adele is only a delegate and not the calendar owner.
canEdit is true since as delegate, Adele has write access to non-private events in
the delegated calendar.
owner is Alex Wilber indicating it is Alex' calendar.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69')/calendars",
"value": [
{
"id": "AQMkADGkAAAJMjAAAAA==",
"name": "Calendar",
"color": "auto",
"changeKey": "NDznl+Uh50WkanaCOKHkaQAAAAACXQ==",
"canShare": true,
"canViewPrivateItems": true,
"canEdit": true,
"owner": {
"name": "Adele Vance",
"address": "[email protected]"
}
},
{
"id": "AAMkADRpAABf0JlzAAA=",
"name": "Alex Wilber",
"color": "auto",
"changeKey": "NDznl+Uh50WkanaCOKHkaQAAX8m4eQ==",
"canShare": false,
"canViewPrivateItems": false,
"canEdit": true,
"owner": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
]
}
7 Note
Signed in as Adele, you can alternatively get the delegated calendar directly from
Alex' mailbox, by specifying Alex' identity and the calendar shortcut, as in GET
https://graph.microsoft.com/v1.0/users/[email protected]/calendar .
The returned calendar ID corresponds to only Alex' mailbox.
HTTP
POST
https://graph.microsoft.com/v1.0/me/calendars/AAMkADRpAABf0JlzAAA=/events
{
"subject": "Christmas dinner",
"body": {
"contentType": "HTML",
"content": "Happy holidays!"
},
"start": {
"dateTime": "2019-12-25T18:00:00",
"timeZone": "Pacific Standard Time"
},
"end": {
"dateTime": "2019-12-25T22:00:00",
"timeZone": "Pacific Standard Time"
},
"location":{
"displayName":"Alex' home"
},
"attendees": [
{
"emailAddress": {
"address":"[email protected]",
"name": "Megan Bowen"
},
"type": "required"
},
{
"emailAddress": {
"address":"[email protected]",
"name": "Christie Cline"
},
"type": "required"
}
]
}
C#
Read the SDK documentation for details on how to add the SDK to your project
and create an authProvider instance.
Notice a successful response includes the response code HTTP 200 and the following
eventMessage properties:
Adele's identity appears only in the sender property of the eventMessage and not in the
associated event.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('662b947c-d9a1-4064-926c-
eba1316d4462')/messages(microsoft.graph.eventMessage/event())/$entity",
"@odata.type": "#microsoft.graph.eventMessage",
"@odata.etag": "W/\"CwAAABYAAADK82uJYVo4RrFV3ADVj3fyAABZ378h\"",
"id": "AAMkADADVj3fyAABZ5hYdAAA=",
"createdDateTime": "2019-12-21T04:59:03Z",
"lastModifiedDateTime": "2019-12-21T04:59:04Z",
"changeKey": "CwAAABYAAADK82uJYVo4RrFV3ADVj3fyAABZ378h",
"categories": [],
"receivedDateTime": "2019-12-21T04:59:03Z",
"sentDateTime": "2019-12-21T04:59:01Z",
"hasAttachments": false,
"internetMessageId": "
<DM6PR17MB3593711A1C0A098167F5A977A12C0@DM6PR17MB3593.namprd17.prod.outlook.
com>",
"subject": "Christmas dinner",
"bodyPreview": "Happy holidays!",
"importance": "normal",
"parentFolderId": "AQMkADIAAAIBDAAAAA==",
"conversationId": "AAQkADNqQlzYAM8jQM=",
"conversationIndex": "AdW3u1xx5S7TYrbluE2pCXNgAzyNAw==",
"isDeliveryReceiptRequested": null,
"isReadReceiptRequested": false,
"isRead": true,
"isDraft": false,
"webLink": "https://outlook.office365.com/owa/?
ItemID=AAMkADADVj3fyAABZ5hYdAAA%3D&exvsurl=1&viewmodel=ReadMessageItem",
"inferenceClassification": "focused",
"meetingMessageType": "meetingRequest",
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nHappy
holidays!\r\n</body>\r\n</html>\r\n"
},
"sender": {
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
},
"from": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
},
"toRecipients": [
{
"emailAddress": {
"name": "Megan Bowen",
"address": "[email protected]"
}
},
{
"emailAddress": {
"name": "Christie Cline",
"address": "[email protected]"
}
}
],
"ccRecipients": [],
"bccRecipients": [],
"replyTo": [],
"flag": {
"flagStatus": "notFlagged"
},
"event": {
"@odata.etag": "W/\"yvNriWFaOEaxVdwA1Y938gAAX+T7Jg==\"",
"id": "AAMkADADVj3fyAABZ5ieyAAA=",
"createdDateTime": "2019-12-21T04:59:03.4336242Z",
"lastModifiedDateTime": "2019-12-27T01:38:32.3766961Z",
"changeKey": "yvNriWFaOEaxVdwA1Y938gAAX+T7Jg==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"iCalUId": "040000008200FEFE0BA532444B5FD89BDE22BA103",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Christmas dinner",
"bodyPreview": "Happy holidays!",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": false,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "tentative",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADADVj3fyAABZ5ieyAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"recurrence": null,
"responseStatus": {
"response": "none",
"time": "2019-12-21T05:16:48.8931825Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-
Type\" content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nHappy
holidays!\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-12-26T02:00:00.0000000",
"timeZone": "UTC"
},
"end": {
"dateTime": "2019-12-26T06:00:00.0000000",
"timeZone": "UTC"
},
"location": {
"displayName": "Alex' home",
"locationType": "default",
"uniqueId": "Alex' home",
"uniqueIdType": "private"
},
"locations": [
{
"displayName": "Alex' home",
"locationType": "default",
"uniqueId": "1396aaf3-e344-4567-a4e3-797557ec24c8",
"uniqueIdType": "locationStore"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
},
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Megan Bowen",
"address": "[email protected]"
}
},
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Christie Cline",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
}
}
HTTP C#
HTTP
POST
https://graph.microsoft.com/v1.0/me/events/AAMkADADVj3fyAABZ5ieyAAA=/ten
tativelyAccept
Content-type: application/json
{
"comment": "I will probably be able to make it.",
"sendResponse": true
}
C#
// Code snippets are only available for the latest version. Current
version is 5.x
Read the SDK documentation for details on how to add the SDK to your project
and create an authProvider instance.
HTTP
Signed in as Adele, get the eventMessage that represents the response from Christie in
step 4.
HTTP C#
HTTP
GET
https://graph.microsoft.com/v1.0/me/messages/AAMkADI4oeRpAABf0HJUAAA=
C#
// Code snippets are only available for the latest version. Current
version is 5.x
Read the SDK documentation for details on how to add the SDK to your project
and create an authProvider instance.
Notice a successful response includes the response code HTTP 200 and the following
eventMessage properties:
meetingMessageType is meetingTenativelyAccepted .
from is Christie.
toRecipients includes only Adele, but not the calendar owner Alex. This is because
Alex kept the default to have Outlook direct all meeting responses to only
delegates.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69')/messages/$entity",
"@odata.type": "#microsoft.graph.eventMessage",
"@odata.etag": "W/\"DAAAABYAAAA0POeX5SHnRaRqdoI4oeRpAABfybkT\"",
"id": "AAMkADI4oeRpAABf0HJUAAA=",
"createdDateTime": "2019-12-21T05:16:55Z",
"lastModifiedDateTime": "2019-12-21T05:16:57Z",
"changeKey": "DAAAABYAAAA0POeX5SHnRaRqdoI4oeRpAABfybkT",
"categories": [],
"receivedDateTime": "2019-12-21T05:16:56Z",
"sentDateTime": "2019-12-21T05:16:49Z",
"hasAttachments": false,
"internetMessageId": "
<86880ccb8ec64184996e46eaddaed279@DM6PR17MB3593.namprd17.prod.outlook.com>",
"subject": "Tentative: Christmas dinner",
"bodyPreview": "I will probably be able to make it.",
"importance": "normal",
"parentFolderId": "AQMkAD5GkAAAIBDAAAAA==",
"conversationId": "AAQkADK25bhNqQlzYAM8jQM=",
"conversationIndex": "AdW3u1xx5S7TYrbluE2pCXNgAzyNAwAAoBoZ",
"isDeliveryReceiptRequested": null,
"isReadReceiptRequested": false,
"isRead": false,
"isDraft": false,
"webLink": "https://outlook.office365.com/owa/?
ItemID=AAMkADI4oeRpAABf0HJUAAA%3D&exvsurl=1&viewmodel=ReadMessageItem",
"inferenceClassification": "focused",
"meetingMessageType": "meetingTenativelyAccepted",
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nI will probably be able to make
it.\r\n</body>\r\n</html>\r\n"
},
"sender": {
"emailAddress": {
"name": "Christie Cline",
"address": "[email protected]"
}
},
"from": {
"emailAddress": {
"name": "Christie Cline",
"address": "[email protected]"
}
},
"toRecipients": [
{
"emailAddress": {
"name": "Adele Vance",
"address": "[email protected]"
}
}
],
"ccRecipients": [],
"bccRecipients": [],
"replyTo": [],
"flag": {
"flagStatus": "notFlagged"
}
}
Signed in as Alex, get the event that Adele created in step 2 and get responses from the
attendees property.
Use the least privileged delegated permission, Calendars.Read . For more information,
see calendar permissions.
HTTP C#
HTTP
GET
https://graph.microsoft.com/v1.0/me/calendar/events/AAMkADJXJGu0AABf02qw
AAA=
C#
// Code snippets are only available for the latest version. Current
version is 5.x
Read the SDK documentation for details on how to add the SDK to your project
and create an authProvider instance.
Notice a successful response includes the response code HTTP 200 and the following
event properties:
isOrganizer is true.
attendees include only Megan and Christie.
The status property of each attendee instance indicates any response from the
attendee:
Megan's response is none .
Christie's response is tentativelyAccepted .
organizer is Alex.
No property in the returned event indicates the delegate, Adele.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('64339082-ed84-4b0b-b4ab-
004ae54f3747')/calendars('AQMkADAw7QAAAJfygAAAA%3D%3D')/events/$entity",
"@odata.etag": "W/\"NEXywgsVrkeNsFsyVyRrtAAAX8xuhA==\"",
"id": "AAMkADJXJGu0AABf02qwAAA=",
"createdDateTime": "2019-12-21T04:59:01.4435895Z",
"lastModifiedDateTime": "2019-12-21T05:16:54.689345Z",
"changeKey": "NEXywgsVrkeNsFsyVyRrtAAAX8xuhA==",
"categories": [],
"originalStartTimeZone": "Pacific Standard Time",
"originalEndTimeZone": "Pacific Standard Time",
"iCalUId": "040000008200FEFE0BA532444B5FD89BDE22BA103",
"reminderMinutesBeforeStart": 15,
"isReminderOn": true,
"hasAttachments": false,
"subject": "Christmas dinner",
"bodyPreview": "Happy holidays!",
"importance": "normal",
"sensitivity": "normal",
"isAllDay": false,
"isCancelled": false,
"isOrganizer": true,
"responseRequested": true,
"seriesMasterId": null,
"showAs": "busy",
"type": "singleInstance",
"webLink": "https://outlook.office365.com/owa/?
itemid=AAMkADJXJGu0AABf02qwAAA%3D&exvsurl=1&path=/calendar/item",
"onlineMeetingUrl": null,
"recurrence": null,
"responseStatus": {
"response": "organizer",
"time": "0001-01-01T00:00:00Z"
},
"body": {
"contentType": "html",
"content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"
content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html;
charset=us-ascii\">\r\n</head>\r\n<body>\r\nHappy
holidays!\r\n</body>\r\n</html>\r\n"
},
"start": {
"dateTime": "2019-12-26T02:00:00.0000000",
"timeZone": "UTC"
},
"end": {
"dateTime": "2019-12-26T06:00:00.0000000",
"timeZone": "UTC"
},
"location": {
"displayName": "Alex' home",
"locationType": "default",
"uniqueId": "Alex' home",
"uniqueIdType": "private"
},
"locations": [
{
"displayName": "Alex' home",
"locationType": "default",
"uniqueId": "Alex' home",
"uniqueIdType": "private"
}
],
"attendees": [
{
"type": "required",
"status": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "Megan Bowen",
"address": "[email protected]"
}
},
{
"type": "required",
"status": {
"response": "tentativelyAccepted",
"time": "2019-12-21T05:16:48.8931825Z"
},
"emailAddress": {
"name": "Christie Cline",
"address": "[email protected]"
}
}
],
"organizer": {
"emailAddress": {
"name": "Alex Wilber",
"address": "[email protected]"
}
}
}
Next steps
Find out more about:
Using the Microsoft Graph API, you can attach files up to 150 MB to an Outlook
message or event item. Depending on the file size, choose one of two ways to attach
the file:
If the file size is under 3 MB, do a single POST on the attachments navigation
property of the Outlook item; see how to do this for a message or for an event.
The successful POST response includes the ID of the file attachment.
If the file size is between 3 MB and 150 MB, create an upload session, and
iteratively use PUT to upload ranges of bytes of the file until you have uploaded
the entire file. A header in the final successful PUT response includes a URL with
the attachment ID.
To attach multiple files to a message, choose the approach for each file based on its file
size and attach the files individually.
This article illustrates the second approach step by step, creating and using an upload
session to add a large file attachment (of size over 3 MB) to an Outlook item. Each step
shows the corresponding code for a message and for an event. Upon successfully
uploading the entire file, the article shows getting a response header that contains an ID
for the file attachment, and then using that attachment ID to get the raw attachment
content or attachment metadata.
) Important
A successful operation returns HTTP 201 Created and a new uploadSession instance,
which contains an opaque URL that you can use in subsequent PUT operations to
upload portions of the file. The uploadSession provides a temporary storage location
where the bytes of the file are saved until you have uploaded the complete file.
Permissions
Make sure to request Mail.ReadWrite permission to create the uploadSession for a
message, and Calendars.ReadWrite for an event.
The opaque URL, returned in the uploadUrl property of the new uploadSession, is pre-
authenticated and contains the appropriate authorization token for subsequent PUT
queries in the https://outlook.office.com domain. That token expires by
expirationDateTime. Do not customize this URL for the PUT operations.
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/me/messages/AAMkADI5MAAIT3drCAAA=/attac
hments/createUploadSession
Content-type: application/json
{
"AttachmentItem": {
"attachmentType": "file",
"name": "flower",
"size": 3483322
}
}
Response
The following example response shows the uploadSession resource returned for the
message.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
"uploadUrl": "https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-
95c1-b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?
authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI",
"expirationDateTime": "2019-09-25T01:09:30.7671707Z",
"nextExpectedRanges": [
"0-"
]
}
Request
HTTP
HTTP
POST
https://graph.microsoft.com/v1.0/me/events/AAMkADU5CCmSAAA=/attachments/
createUploadSession
Content-type: application/json
{
"AttachmentItem": {
"attachmentType": "file",
"name": "flower",
"size": 3483322
}
}
Response
The following example response shows the uploadSession resource returned for the
event.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
"uploadUrl": "https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-
441d-b7dc-c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJ
lCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw",
"expirationDateTime": "2020-02-22T02:46:56.7410786Z",
"nextExpectedRanges": [
"0-"
]
}
Request headers
Content- Int32 The number of bytes being uploaded in this operation. For better
Length performance, keep the upper limit of the number of bytes for each PUT
operation to 4 MB. Required.
Content- String The 0-based byte range of the file being uploaded in this operation,
Range expressed in the format bytes {start}-{end}/{total} . Required.
Do not specify an Authorization request header. The PUT query uses a pre-
authenticated URL from the uploadUrl property, that allows access to the
https://outlook.office.com domain.
Request body
Specify the actual bytes of the file to be attached, that are in the location range
specified by the Content-Range request header.
Response
A successful upload returns HTTP 200 OK and an uploadSession object. Note the
following in the response object:
The expirationDateTime property indicates the expiration date/time for the auth
token embedded in the uploadUrl property value. This expiration date/time
remains the same as returned by the initial uploadSession in step 1.
The nextExpectedRanges specifies the next byte location to start uploading from,
for example, "nextExpectedRanges":["2097152"] . You must upload bytes in a file in
order.
The uploadUrl property is not explicitly returned, because all PUT operations of an
upload session use the same URL returned when creating the session (step 1).
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
Content-Type: application/octet-stream
Content-Length: 2097152
Content-Range: bytes 0-2097151/3483322
{
<bytes 0-2097151 of the file to be attached, in binary format>
}
Response
The following example response shows in the nextExpectedRanges property the start of
the next byte range that the server expects.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
"@odata.context":"https://outlook.office.com/api/v2.0/$metadata#Users('a8e8e
219-4931-95c1-b73d-62626fd79c32%4072aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA%3D')/AttachmentSessions/$entit
y",
"ExpirationDateTime":"2019-09-25T01:09:30.7671707Z",
"nextExpectedRanges":["2097152"]
}
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJ
lCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw
Content-Type: application/octet-stream
Content-Length: 2097152
Content-Range: bytes 0-2097151/3483322
{
<bytes 0-2097151 of the file to be attached, in binary format>
}
Response
The following example response shows in the nextExpectedRanges property the start of
the next byte range that the server expects.
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://outlook.office.com/api/v2.0/$metadata#Users('d3b92
14b-dd8b-441d-b7dc-c446c9fa0e69%4098a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA%3D')/AttachmentSessions/$entity",
"ExpirationDateTime":"2020-02-22T02:46:56.7410786Z",
"nextExpectedRanges":["2097152"]
}
Once the last byte of the file has been successfully uploaded, the final PUT operation
returns HTTP 201 Created and a Location header that indicates the URL to the file
attachment in the https://outlook.office.com domain. You can get the attachment ID
from the URL and save it for later use. Depending on your scenario, you can use that ID
to get the metadata of the attachment, or remove the attachment from the Outlook
item using the Microsoft Graph endpoint.
The following examples show uploading the last byte range of the file to the message
and to the event in the preceding steps.
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
Content-Type: application/octet-stream
Content-Length: 1386170
Content-Range: bytes 2097152-3483321/3483322
{
<bytes 2097152-3483321 of the file to be attached, in binary format>
}
Response
The following example response shows a Location response header from which you can
save the attachment ID ( AAMkADI5MAAIT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0= ) for later
use.
HTTP
Location: https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-
b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/Attachments('AAMkADI5MAAIT3
drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=')
Content-Length: 0
Request
HTTP
PUT https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJ
lCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw
Content-Type: application/octet-stream
Content-Length: 1386170
Content-Range: bytes 2097152-3483321/3483322
{
<bytes 2097152-3483321 of the file to be attached, in binary format>
}
Response
The following example response shows a Location response header from which you can
save the attachment ID ( AAMkADU5CCmSAAANZAlYPeyQByv7Y= ) for later use.
HTTP
HTTP/1.1 201 Created
Location: https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-
b7dc-c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/Attachments('AAMkADU5CCmSAAANZAlYP
eyQByv7Y=')
Content-Length: 0
As an alternative to getting the attachment content in base64 format, you can get
the raw data of the file attachment.
To get the metadata of the file attachment, append a $select parameter to
include only those metadata properties you want, excluding the contentBytes
property which returns the file attachment in base64 format.
Permissions
Use the least privileged delegated or application permission, Calendars.Read , as
appropriate, for this operation. For more information, see calendar permissions.
Request
HTTP
GET https://graph.microsoft.com/v1.0/Users('d3b9214b-dd8b-441d-b7dc-
c446c9fa0e69@98a79ebe-74bf-4e07-a017-
7b410848cb32')/Events('AAMkADU5CCmSAAA=')/Attachments('AAMkADU5CCmSAAANZAlYP
eyQByv7Y=')/$value
Response
HTTP
HTTP/1.1 200 OK
content-length: 3483322
Content-type: image/jpeg
Permissions
Use the least privileged delegated or application permission, Mail.Read , as appropriate,
for this operation. For more information, see mail permissions.
Request
HTTP
GET https://graph.microsoft.com/api/v1.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/Attachments('AAMkADI5MAAIT3
drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=')?
$select=lastModifiedDateTime,name,contentType,size,isInline
Response
HTTP
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":
"https://graph.microsoft.com/v1.0/$metadata#users('a8e8e219-4931-95c1-b73d-
62626fd79c32%4072aa88bf-76f0-494f-91ab-
2d7cd730db47')/messages('AAMkADI5MAAIT3drCAAA%3D')/attachments/$entity",
"@odata.type": "#microsoft.graph.fileAttachment",
"@odata.mediaContentType": "image/jpeg",
"id": "AAMkADI5MAAIT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=",
"lastModifiedDateTime": "2019-09-24T23:27:43Z",
"name": "flower",
"contentType": "image/jpeg",
"size": 3640066,
"isInline": false
}
Permissions
Because the initial opaque URL is pre-authenticated and contains the appropriate
authorization token for subsequent queries for that upload session, do not specify an
Authorization request header for this operation.
Request
HTTP
DELETE https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-
62626fd79c32@72aa88bf-76f0-494f-91ab-
2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI
5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
Response
HTTP
ErrorAttachmentSizeShouldNotBeLessThanMinimumSize
This error is returned when attempting to create an upload session to attach a file
smaller than 3 MB. If the file size is under 3 MB, you should do a single POST on the
attachments navigation property of the message or of the event. The successful POST
response includes the ID of the file attached to the message.
Obtain immutable identifiers for
Outlook resources
Article • 06/25/2022
Outlook items (messages, events, contacts, tasks) have an interesting behavior that
you've probably either never noticed or has caused you significant frustration: their IDs
change. It doesn't happen often, only if the item is moved, but it can cause real
problems for apps that store IDs offline for later use. Immutable identifiers (IDs) enable
your application to obtain an ID that does not change for the lifetime of the item.
7 Note
Immutable identifiers, like all identifiers in Microsoft Graph, are case-sensitive. Keep
this in mind if you are comparing IDs.
How it works
Immutable ID is an optional feature for Microsoft Graph. To opt in, your application
needs to send an additional HTTP header in your API requests:
HTTP
Prefer: IdType="ImmutableId"
This header only applies to the request it is included with. If you want to always use
immutable IDs, you must include this header with every API request.
Container types (mailFolder, calendar, etc.) do not support immutable ID, but their
regular IDs were already constant.
1. Create a draft message using the Prefer: IdType="ImmutableId" header and save
the id property of the message in the response.
2. Send the message using the ID from the previous step.
3. Get the message using the ID from the first step. This is the copy in Sent Items.
7 Note
Getting the message in Sent Items may not succeed immediately after sending the
message. The copy of the message is not created until the message successfully
sends, which may take time.
with both ID formats, so your application does not need to re-synchronize to take
advantage of immutable ID. You can use the header to get immutable IDs going
forward, and you can update your app's storage separately.
7 Note
Example
The following example translates a normal Microsoft Graph ID to an immutable
Microsoft Graph ID.
Request
HTTP
POST https://graph.microsoft.com/v1.0/me/translateExchangeIds
{
"inputIds" :
[
"AQMkAGM2…"
],
"targetIdType" : "restImmutableEntryId",
"sourceIdType" : "restId"
}
Response
HTTP
HTTP 200 OK
{
"value": [
{
"targetId": "AAkALgAA...",
"sourceId": "AQMkAGM2..."
}
]
}
Change notifications for Outlook
resources in Microsoft Graph
Article • 03/02/2023
The Microsoft Graph API lets you subscribe to changes to a resource—including creation,
update, or deletion of the resource—and receive notifications via webhooks. A subscription
specifies the desired types of changes to monitor for a specific resource, and includes a
URL for an endpoint to receive notifications of those changes.
Setting up a subscription reduces the overhead of otherwise having to query and compare
resources to deduce any changes. You can optionally specify in the subscription request to
encrypt and include as part of a notification the resource data that has changed, saving a
separate subsequent API call to get the resource payload.
There is a maximum limit of 1000 active subscriptions for Outlook resources per mailbox
for all applications. You can subscribe to changes in contacts, events, or messages in the
mailbox.
The following Outlook resources support subscriptions with or without resource data in the
change notification payload.
contact
event
message
Create a subscription
To create a subscription, specify the Outlook resource and the type of changes (creation,
update, or deletion) for which you want to receive notifications. See an example.
Request permissions
Creating and managing (getting, updating, and deleting) a subscription requires a read
scope to the resource. For example, to get change notifications on messages, your app
needs the Mail.Read permission. Outlook change notifications support delegated and
application permission scopes. Note the following limitations:
Depending on the resource, use the least privileged permission specified in the following
table to call this API.
Notifications with resource data for Outlook resources are currently available only in
the Microsoft Graph beta endpoint.
To have resource data included in a change notification, you must specify the following
properties, in addition to those you normally include when creating a subscription:
resource: This property specifies the resource URL. Make sure to use the $select
query parameter to explicitly specify the Outlook resource properties to include in the
notification payload.
7 Note
encryptionCertificate: This property contains only the public key that Microsoft Graph
uses to encrypt resource data. Keep the corresponding private key to decrypt the
content.
encryptionCertificateId: This property is your own identifier for the certificate. Use
this ID to match in each change notification which certificate to use for decryption.
See an example for subscribing to change notifications with resource data for the message
resource.
One common application of $filter is to get notified upon a change in a specific resource
property. For example, you can use $filter to subscribe to unread messages in a folder
(the isRead property is false ), and include all the change types:
If you lose the permission granted earlier for a subscription and the subscription expires
meanwhile, request permission again to create a new subscription.
{
"value": [
{
"subscriptionId": "dfd11b2f-8222-4189-9545-4205c95d6235",
"subscriptionExpirationDateTime": "2021-12-31T16:16:44.9907405+05:30",
"changeType": "created",
"resource": "Users('722effaf-0433-4272-9ac4-
d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>",
"encryptedContent": {
"data": "<<--EncryptedContent-->>",
"dataKey": "<<--EnryptedDataKeyUsedForEncryptingContent-->>",
"dataSignature": "Qw/9ubWeUYJPWWXvNiGgct2FkNG2MXTRm/BLUpJM66k=",
"encryptionCertificateId": "<<--
IdOfTheCertificateUsedForEncryptingDataKey-->>",
"encryptionCertificateThumbprint": "<<--
ThumbprintOfTheCertificateUsedForEncryptingDataKey-->>"
},
"resourceData": {
"@odata.type": "#microsoft.graph.message",
"@odata.id": "Users('722effaf-0433-4272-9ac4-
d5ec11c3cd77')/messages('AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA=')",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUR8n\"",
"id": "AAMkAGUwNjQ4ZjIxLTQ3Y2Y8AAA="
}
}
]
"validationTokens": ["<<--ValidationTokens-->>"]
}
For details about how to validate tokens and decrypt the payload, see Set up change
notifications that include resource data.
JSON
{
"[email protected]":"#DateTimeOffset",
"receivedDateTime":"2021-12-30T10:53:35Z",
"subject":"TEST MESSAGE FOR RICH NOTIFICATIONS",
"bodyPreview":"Hello,\r\n\r\nWhat\u2019s up?\r\n\r\nThanks\r\nMegan",
"[email protected]":"#microsoft.graph.importance",
"importance":"normal",
"from": {
"@odata.type":"#microsoft.graph.recipient",
"emailAddress": {
"@odata.type":"#microsoft.graph.emailAddress",
"name":"Megan Brown",
"address":"[email protected]"
}
}
}
The next example shows the payload of a notification that corresponds to an Outlook
message resource. It includes the resource and resourceData properties, which represent
the resource that triggered the notification. Use the resource and @odata.id properties to
make calls to Microsoft Graph to get the payload of the resource.
7 Note
GET calls always return the current state of the resource. If the resource is changed
between the time the notification is sent and the time the resource is retrieved, the
operation returns the state of the resource on retrieval.
JSON
"value": [
{
"subscriptionId": "c6126aa3-0ed8-412f-a988-71e6cee627c4",
"subscriptionExpirationDateTime": "2022-01-02T03:12:18.2257768+05:30",
"changeType": "created",
"resource": "Users/622eaaff-0683-4862-9de4-
f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIxAAA=",
"resourceData": {
"@odata.type": "#Microsoft.Graph.Message",
"@odata.id": "Users/622eaaff-0683-4862-9de4-
f2ec83c2bd98/Messages/AAMkAGUwNjQ4ZjIAAA=",
"@odata.etag": "W/\"CQAAABYAAACQ2fKdhq8oSKEDSVrdi3lRAAGDUUXn\"",
"id": "AAMkAGUwNjQ4ZjIxAAA="
},
"clientState": "<<--SpecifiedClientState-->>",
"tenantId": "<<--TenantForWhichNotificationWasSent-->>"
}
]
Examples
Request
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"expirationDateTime": "2021-07-07T21:42:18.2257768+00:00",
"clientState": "secretClientState"
}
Response
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "5522bd62-7c96-4530-85b0-00b916f6151a",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientState",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T21:42:18.2257768Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": null,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": null,
"encryptionCertificateId": null,
"notificationUrlAppId": null
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?
$select=Subject,bodyPreview,importance,receivedDateTime,from",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "178eec5f-cf3c-4e7e-8a9c-8640deb5b5c5",
"resource": "users/622eaaff-0683-4862-9de4-f2ec83c2bd98/messages?
$select=Subject,bodyPreview,importance,receivedDateTime,from",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-01T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}
Request
HTTP
HTTP
POST https://graph.microsoft.com/beta/subscriptions
Content-type: application/json
{
"changeType": "created",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"resource": "me/mailfolders('Drafts')/messages?
$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance
eq 'High'",
"expirationDateTime": "2022-01-01T21:42:18.2257768+00:00",
"clientState": "secretClientValue",
"includeResourceData": true,
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId"
}
Response
The following is an example of the response.
Note: The response object shown here might be shortened for readability.
HTTP
{
"@odata.context":
"https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id": "239dbc5f-cf3c-4e7e-8c9c-3340abc5b5c5",
"resource": "me/mailfolders('Drafts')/messages?
$select=Subject,bodyPreview&$filter=hasAttachments eq true AND importance eq
'High'",
"applicationId": "507c3b9a-67b8-463d-88a2-15a8cefb2111",
"changeType": "created",
"clientState": "secretClientValue",
"notificationUrl":
"https://webhook.azurewebsites.net/api/send/myNotifyClient",
"notificationQueryOptions": null,
"notificationContentType": null,
"lifecycleNotificationUrl": null,
"expirationDateTime": "2022-01-20T12:32:35.1582696Z",
"creatorId": "a4c7bd34-4f3b-46b7-a25d-b63c1e2a2842",
"includeResourceData": true,
"latestSupportedTlsVersion": "v1_2",
"encryptionCertificate": "MIIDMzCCAhugAwIBAgIQE7D+++Dk1hKQBqWA==",
"encryptionCertificateId": "testCertificateId",
"notificationUrlAppId": null
}
See also
Microsoft Graph change notifications
Set up change notifications that include resource data
Outlook mail API overview
Outlook contacts API overview
Outlook calendar API overview
Set up notifications for changes in
resource data
Article • 04/20/2023
https://www.youtube-nocookie.com/embed/rC1bunenaq4
Basic notifications: Change notifications that don't contain resource data other
than the id of the resource that changed. All Microsoft Graph resources support
basic notifications. When an app receives a basic notification, the service can use
the id to query to changed object.
Rich notifications: Change notifications that include the resource data of the
object that changed. For more information about rich notifications, see Rich
notifications.
Lifecycle notifications: Notifications that alert the customer when they are at risk
of missing change notifications due to the lifecycle of their subscription. For more
information about lifecycle notifications, see Lifecycle notifications.
Supported resources
An app can subscribe to changes on the Microsoft Graph resources listed in the table,
which also indicates the limits that apply for subscriptions to the resources. When any
limit is exceeded, attempts to create a subscription will result in an 403 Forbidden error
response. The message property of the error response will explain the limit that has
been exceeded.
7 Note
Cloud printing Changes when there is a valid job in the queue (jobStarted -
printTaskDefinition event): /print/printtaskdefinition/{id}/tasks
Not
supported for
Azure AD
B2C tenants.
A known
issue for the
subscription
changeType.
Teams chatMessage Changes to chat messages in all channels in all teams: Maximum
/teams/getAllMessages subscription
quotas:
Changes to chat messages in a specific channel: Per app
/teams/{id}/channels/{id}/messages and channel
or chat
Changes to chat messages in all chats: /chats/getAllMessages combination:
1
Changes to chat messages in a specific chat: subscription.
/chats/{id}/messages Per user
(for
Changes to chat messages in all chats a particular user is part subscriptions
of: /users/{id}/chats/getAllMessages tracking chat
messages in
Changes to chat messages for all chats in an organization all chats the
where a particular Teams app is installed: user is part
/appCatalogs/teamsApps/{id}/installedToChats/getAllMessages of): 10
subscriptions.
Per
organization:
10,000 total
subscriptions.
Resource Supported resource paths Limitations
Not
supported for
personal
Microsoft
accounts like
outlook.com.
Not
supported for
Azure AD
B2C tenants.
A known
issue for the
subscription
changeType.
Some of these resources support rich notifications (notifications with resource data). For
more information about resources that support rich notifications, see Set up change
notifications that include resource data.
Subscription lifetime
Subscriptions have a limited lifetime. Apps need to renew their subscriptions before the
expiration time; Otherwise, they need to create a new subscription. Apps can also
unsubscribe at any time to stop getting change notifications.
The following table shows the maximum expiration times for subscriptions per resource
in Microsoft Graph.
Webhooks for this resource are only available in the global endpoint
and not in the national clouds.
Note: Existing applications and new applications should not exceed the supported
value. In the future, any requests to create or renew a subscription beyond the
maximum value will fail.
Managing subscriptions
Clients can create subscriptions, renew subscriptions, and delete subscriptions. Then
while the subscription is valid and when changes occur in the subscribed resource,
Microsoft Graph sends change notifications to the specified notification endpoint.
You manage the subscription using the subscription resource type and its related
methods. While the subscription is valid and changes occur in the subscribed resource,
Microsoft Graph sends a change notification in a structure defined in the
changeNotificationCollection resource type.
For more information about managing subscriptions for the different delivery channels
using Microsoft Graph, see the following articles.
Code samples
The following code samples are available on GitHub.
Microsoft Graph Training Module - Using Change Notifications and Track Changes
with Microsoft Graph
Microsoft Graph Webhooks Sample for Node.js
Microsoft Graph Webhooks Sample for ASP.NET Core
Microsoft Graph Webhooks Sample for Java Spring
Latency
The following table lists the latency to expect between an event happening in the
service and the delivery of the change notification.
Deployment resources
Get change notifications through webhooks
Get change notifications through Azure Event Hubs
Get change notifications through Azure Event Grid
Rich notifications (notifications with resource data)
Lifecycle notifications
Tutorials
Change notifications for cloud printing
Change notifications for Outlook resources
Change notifications for Microsoft Teams resources
See also
Training: Use change notifications and track changes with Microsoft Graph
Receive change notifications through
webhooks
Article • 03/24/2023
A webhook is a HTTP-based user-defined callback API that you can set up in your
infrastructure to receive change notifications and events from a service, such as
Microsoft Graph. You must configure the webhook using a well-known and accessible
HTTPS-secured endpoint.
The article guides you through the process of managing your Microsoft Graph
subscription and how to receive change notifications through webhooks.
Create a subscription
Before you can receive Microsoft Graph change notifications, you must first create a
subscription. The process to set up a valid subscription involves both the client app and
Microsoft Graph as follows:
3. When the client receives the notification URL validation request, the client
responds with the validation token in plain text as explained later in this article.
4. Microsoft Graph validates the client's validation token response and if the
validation token is valid, responds with a subscription ID.
Subscription request
The client app sends a POST request to the /subscriptions endpoint. The following
example shows a basic request to subscribe to changes to a specific mail folder on
behalf of the signed-in user. For more information about other Microsoft Graph
resources that support change notifications, see supported resources.
HTTP
HTTP
POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json
{
"changeType": "created,updated",
"notificationUrl":
"https://webhook.azurewebsites.net/notificationClient",
"lifecycleNotificationUrl":
"https://webhook.azurewebsites.net/api/lifecycleNotifications",
"resource": "/me/mailfolders('inbox')/messages",
"expirationDateTime": "2016-03-20T11:00:00.0000000Z",
"clientState": "SecretClientState"
}
The clientState property is required. Setting this property allows your service to confirm
that change notifications you receive originate from Microsoft Graph. For this reason,
the value of the property should remain secret and known only to your application and
the Microsoft Graph service.
If successful, Microsoft Graph returns a 201 Created code and a subscription object in
the body.
Each subscription has a unique subscriptionId, even if you have multiple subscriptions
that monitor the same resource and use the same notification URL.
7 Note
notificationUrl validation
When you create a subscription to receive change notifications through webhooks,
Microsoft Graph first validates the notification endpoint that's provided in the
notificationUrl property of the subscription request. The validation process occurs as
follows:
HTTP
2. The client must properly decode the URL to get the plain text validation token
from Microsoft Graph.
Escaping any HTML or JavaScript is a good practice because malicious actors can
use the notification endpoint for cross-site scripting type of attacks. Microsoft
Graph never sends any value containing HTML or JavaScript code.
In general, treat the validation token value as opaque, as the token format can
change without notice.
3. The client must respond with the following characteristics within 10 seconds of
step 1:
) Important
The validation token must be returned in plain text. If the client returns an
encoded validation token, the validation fails.
4. If the endpoint validation fails, Microsoft Graph doesn't create the subscription.
Additionally, you can use the Microsoft Graph Postman collection to confirm that your
endpoint properly implements the validation request. The notificationUrl validation
request in the Misc folder provides unit tests that validate the response provided by
your endpoint.
Receive notifications
While the subscription is valid and there are changes to the resource that you
subscribed to, Microsoft Graph sends a POST request to the notificationUrl with details
of the changes. This payload is the change notification.
For most subscriptions, Microsoft Graph doesn't delay sending notifications but delivers
all notifications within the SLA unless the service is experiencing an incident.
A change notification payload sent to your app can contain a collection of change
notifications relating to your subscriptions.
When many changes occur, Microsoft Graph may send multiple notifications that
correspond to different subscriptions in the same POST request.
JSON
{
"value": [
{
"id": "lsgTZMr9KwAAA",
"subscriptionId":"{subscription_guid}",
"subscriptionExpirationDateTime":"2016-03-19T22:11:09.952Z",
"clientState":"secretClientValue",
"changeType":"created",
"resource":"users/{user_guid}@{tenant_guid}/messages/{long_id_string}",
"tenantId": "84bd8158-6d4d-4958-8b9f-9d6445542f95",
"resourceData":
{
"@odata.type":"#Microsoft.Graph.Message",
"@odata.id":"Users/{user_guid}@{tenant_guid}/Messages/{long_id_string}",
"@odata.etag":"W/\"CQAAABYAAADkrWGo7bouTKlsgTZMr9KwAAAUWRHf\"",
"id":"{long_id_string}"
}
}
]
}
1. After receiving the change notification, send a 2xx class code back to Microsoft
Graph. If Microsoft Graph doesn't receive a 2xx class code within 3 seconds, it tries
to resend the change notification multiple times, for up to 4 hours. If Microsoft
Graph still doesn't receive a 2xx code within the period, it discards the change
notification. If the client app consistently doesn't respond within 3 seconds, the
notifications might be subject to throttling.
If your service can take more than 3 seconds to process the change notification, it
should persist the notification, return a 202 - Accepted status code in the response
to Microsoft Graph, then process the notifications at its capacity. If the notification
isn't persisted, return a 5xx class code to indicate an error so that Microsoft Graph
can retry the notification.
If your service is expected to take less than 3 seconds, it should process the
notifications and return a 200 - OK status code to Microsoft Graph. If the
notification isn't processed correctly, return a 5xx class code to indicate an error so
that Microsoft Graph can retry the notification.
2. Validate the clientState property. It must match the value originally submitted
with the subscription creation request.
If there's a mismatch, don't consider the change notification as valid. It's possible
that the change notification hasn't originated from Microsoft Graph and may have
been sent by a rogue actor. You should also investigate where the change
notification comes from and take appropriate action.
When you subscribe to lifecycle notifications, Microsoft Graph alerts you when a
subscription is almost expiring and should be renewed. If you don't subscribe to lifecycle
notifications, you can use the subscriptionExpirationDateTime to monitor when your
app should send a subscription renewal request.
HTTP
HTTP
PATCH https://graph.microsoft.com/v1.0/subscriptions/{id}
Content-Type: application/json
{
"expirationDateTime": "2016-03-22T11:00:00.0000000Z"
}
Delete a subscription
If the client app no longer wants change notifications, it can delete the subscription
using its subscriptionId as follows:
HTTP
HTTP
DELETE https://graph.microsoft.com/v1.0/subscriptions/{id}
If successful, Microsoft Graph returns a 204 No Content code.
Throttling
If a subscription notification URL is slow or fails to respond, and Microsoft Graph doesn't
receive a 2xx class code within 3 seconds, Microsoft Graph tries to resend the change
notification multiple times, for up to 4 hours. In this case Microsoft Graph might throttle
notifications for the notification endpoint that's associated with the subscription.
1. If the publishing time is greater than 2900 ms, the response is considered slow.
2. The change notification service then calculates the percentage of slow responses
after the endpoint receives 100 notifications.
3. If the percentage of slow responses reaches 10%, the endpoint associated with the
notification URL is flagged as a slow endpoint. All notifications for all subscriptions
associated with the endpoint are subjected to throttling.
4. The evaluation continues in real time and the accumulation of responses is flushed
every 10 minutes.
Firewall configuration
You can configure the firewall that protects your notification URL to allow inbound
connections only from Microsoft Graph, reducing further exposure to invalid change
notifications. For a complete list of IP addresses used by Microsoft Graph to deliver
change notifications, see additional endpoints for Microsoft 365.
7 Note
The listed IP addresses that are used to deliver change notifications can be updated
at any time without notice.
Summary
In this article, you learned how to receive change notifications through webhooks.
See also
Training module: Use change notifications and track changes with Microsoft Graph
subscription resource type
changeNotificationCollection resource type
Lifecycle notifications
Receive change notifications through
Azure Event Hubs
Article • 03/30/2023
Webhooks may not be suitable for receiving change notifications in high throughput
scenarios or when the receiver cannot expose a publicly available notification URL. As an
alternative, you can use Azure Event Hubs.
The article guides you through the process of managing your Microsoft Graph
subscription and how to receive change notifications through Azure Event Hubs.
You don't rely on publicly exposed notification URLs. The Event Hubs SDK will relay
the notifications to your application.
You don't need to reply to the notification URL validation. You can ignore the
validation message that you receive.
You'll need to provision an Azure Event Hub.
You'll need to provision an Azure Key Vault.
Azure CLI
# --------------
# TODO: update the following values
#sets the name of the resource group
resourcegroup=rg-graphevents-dev
#sets the location of the resources
location='uk south'
#sets the name of the Azure Event Hubs namespace
evhamespacename=evh-graphevents-dev
#sets the name of the hub under the namespace
evhhubname=graphevents
#sets the name of the access policy to the hub
evhpolicyname=grapheventspolicy
#sets the name of the Azure KeyVault
keyvaultname=kv-graphevents
#sets the name of the secret in Azure KeyVault that will contain the
connection string to the hub
keyvaultsecretname=grapheventsconnectionstring
# --------------
az group create --location $location --name $resourcegroup
az eventhubs namespace create --name $evhamespacename --resource-group
$resourcegroup --sku Basic --location $location
az eventhubs eventhub create --name $evhhubname --namespace-name
$evhamespacename --resource-group $resourcegroup --partition-count 2 --
message-retention 1
az eventhubs eventhub authorization-rule create --name $evhpolicyname --
eventhub-name $evhhubname --namespace-name $evhamespacename --resource-
group $resourcegroup --rights Send
evhprimaryconnectionstring=`az eventhubs eventhub authorization-rule
keys list --name $evhpolicyname --eventhub-name $evhhubname --namespace-
name $evhamespacename --resource-group $resourcegroup --query
"primaryConnectionString" --output tsv`
az keyvault create --name $keyvaultname --resource-group $resourcegroup
--location $location --enable-soft-delete true --sku standard --
retention-days 90
az keyvault secret set --name $keyvaultsecretname --value
$evhprimaryconnectionstring --vault-name $keyvaultname --output none
graphspn=`az ad sp list --display-name 'Microsoft Graph Change Tracking'
--query "[].appId" --output tsv`
az keyvault set-policy --name $keyvaultname --resource-group
$resourcegroup --secret-permissions get --spn $graphspn --output none
keyvaulturi=`az keyvault show --name $keyvaultname --resource-group
$resourcegroup --query "properties.vaultUri" --output tsv`
domainname=`az ad signed-in-user show --query 'userPrincipalName' | cut
-d '@' -f 2 | sed 's/\"//'`
notificationUrl="EventHub:${keyvaulturi}secrets/${keyvaultsecretname}?
tenantId=${domainname}"
echo "Notification Url:\n${notificationUrl}"
Note: The script provided here is compatible with Linux based shells, Windows
WSL, and Azure Cloud Shell. It will require some updates to run in Windows
shells.
The main difference during subscription creation will be the notificationUrl. You must
set it to EventHub:https://<azurekeyvaultname>.vault.azure.net/secrets/<secretname>?
tenantId=<domainname> , with the following values:
azurekeyvaultname - The name you gave to the key vault when you created it. Can
be found in the DNS name.
secretname - The name you gave to the secret when you created it. Can be found
on the Azure Key Vault Secrets page.
domainname - The name of your tenant; for example, consto.onmicrosoft.com or
contoso.com. Because this domain will be used to access the Azure Key Vault, it is
important that it matches the domain used by the Azure subscription that holds
the Azure Key Vault. To get this information, you can go to the overview page of
the Azure Key Vault you created and click the subscription. The domain name is
displayed under the Directory field.
Receiving notifications
Events will be now delivered to your application by Event Hubs. For details, see receiving
events in the Event Hubs documentation.
Before you can receive the notifications in your application, you'll need to create
another shared access poli