Announcing the new version of the Graph API: api-version=2013-11-08

We’re excited to announce the next version of the Graph API, api-version=2013-11-08 is now available. There are several updates that can be useful for your applications, and enable some new scenarios.

The major updates in this release include: 

  • Support for provisioning Federated users
  • User License assignment
  • Support for adding multiple members to a Group
  • Managing a Group’s Owner
  • Sorting Groups by their Display Name property
  • Additional Differential Query features

1. Provisioning Federated Users, by exposing a new user property: immutableId

We now expose a new user property called “immutableId” through the Graph API. What is the significance of this property?  It is used to associate the on-premises user object account to the cloud user hosted in Azure Active Directory – for example, if you have an on-premise directory, and the user object from that directory has an identifier GUID with a value of “9c5923e9-de52-33ea-88de-7ebc8633b9cc”, then the Azure AD User object can store this value in its immutableId property (stored as a string). The immutableId is used to link the on-premises account identity with the Azure AD account identity.  Note: the immutableId value cannot contain spaces or the $ symbol.

Note: customers using the Microsoft DirSync tool, will automatically have sync’ed Azure AD Users’ immutableId property populated – DirSync writes this value as the base64 encoded value of the on-premises object Guid.  Application should store the value that meets the requirements of their federated identity service provider

Here’s an example GET call, requesting only a user’s immutableId property: 


RESPONSE (in JSON):   {   “value”:”6SNZnFLe6jOI3n68hjO5zA==”   }

If you are creating an Azure AD User, and are using a federated domain for the User’s userPrincipalName property, then you must specify a value for the user’s immutableId property – for example, this is the POST operation to create a new user, assigning to the user’s userPrincipalName, which is configured as a federated domain.

Creating a New User using a federated  domain “”



Content-Type: application/json

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1T….




    “displayName”:”Derek “, 


     “passwordProfile”:{ “password”:”placeHold3r$”, “forceChangePasswordNextLogin”:false},

     “immutableId”: “6SNZnFLe6jOI3n68hjO5zA==”


 HTTP RESPONSE: 201 Created

 NOTE: in the above example, a password is required as part of the POST user creation call, but is not used because the User is using a Federated identity.

In this new API version, we have also exposed a new user property, userType.  This is a string value that can be used to allow tenants to classify the types of users within their organization.  For example, regular employees can be identified by userType =  “Member”,  and guest accounts associated with vendors, consultants or temporary workers, could be have userType = “Guest” .

 2. Support for User Licensing

This action was first available under a preview version (api-version=2013-04-10-preview) and is now officially supported in the “2013-11-08” release.  This method allows assignment and removal of a subscription for any provisioned user account. For example, here’s an initial license assignment of the Enterprise Office Sku, which contains SharePoint Online, Lync Online and the Exchange Online service plans.



Content-Type: application/json

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1T….


  “addLicenses”:[{“disabledPlans”:[ ],”skuId”:”6fd2c87f-b296-42f0-b197-1e91e994b900″}],
  “removeLicenses”:[ ]




Here’s an example of updating a User’s license by disabling specific plans.  In this example, there are 2 disabledPlans (SharePointOnline and LyncOnline”), leaving only the Exchange Service Plan.

Select User License Assignment



Content-Type: application/json

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1T….


  “addLicenses”:[  { “disabledPlans”:  [”5dbe027f-2339-4123-9542-606e4d348a72”,
                                                            “0feaeb32-d00e-4d66-bd5a-43b5b83db82c” ], 


   “removeLicenses”:[ ]




Finally, here’s how to remove the license from the user.

Remove User License Preview



Content-Type: application/json

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1T….



  “addLicenses”:[ ],





How do you get the subscription Sku Id and the plan ids?  These can be read from the tenant object, by calling GET
which will return the subscriptions available for the tenant – this includes the SkuId and servicePlans Id’s under the Sku. Availability of subscriptions can be calculated from the “consumedUnits” property and values
from “prepaidUnits” complex property, which includes counts of units that are “enabled”, “suspended” and in “warning” states.  You can view this using the demo – select
“Use Demo Company”, and execute this query:

 3. Adding Group Members operation can now support multiple member objects in the same request.  

We have always allowed adding a single object to a group, but we now support multiple objects being added to a group in one call.  The example below adds two new users to a group.  NOTE: The maximum allowed number of links to add in a single POST/PATCH request should be kept to 20 or below.  Attempts to add a higher number of links can result in a failure response.

Update Group or Role membership



Content-Type: application/json

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1T….








HTTP RESPONSE:   204 No Content

 Note: Removing multiple members is not supported at this time.


4. Managing Group Owners  

How do you find a Group’s owner?  Easy – the following will return the Group’s owner: GET

The following will return the group object, and the owner objects in one call:$expand=owners?api-version=2013-11-08

And to assign an owner to a Group, the following POST operation can be executed:

Update a Group’s Owner



Content-Type: application/json

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1T….



   “url”:  “


RESPONSE: 204 No Content

 And with other links, you can also find out what objects are owned for a User: 


Or retrieve the user and the user’s owned objects in one call: GET$expand=ownedObjects&api-version=2013-11-08

5. Sorting lists of Groups by display name

We now allow your app to specify sorting by the Group’s display name property. For example: GET$orderby=displayName?api-version=2013-11-8.  And in case you missed it in my previous blog post, you can specify sort order for user lists, by either the displayName or userPrincipalName property. 

6. Additional Differential Query features

Differential Queries can now return only updated properties and links – this allows faster processing and reduced payloads for Differential Query calls. This option is enabled by setting the header ocp-aad-dq-include-only-changed-properties to true as shown in this example.


GET furK18V1T….


ocp-aad-dq-include-only-changed-properties : true

Content-Type: application/json

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5nl0aEV1T….

Response: 200 OK

For example if only the “displayName” property of user has changed.  The returned object would be similar to this:


          “displayName” : “AnUpdatedDisplayName”,

         “objectId” :  “c1bf5c59-7974-4aff-a59a-f8dfe9809b18”,

         “objectType” :  “User”,

          “odata.type” :  “Microsoft.WindowsAzure.ActiveDirectory.User”


Differential Sync Support to Sync from “now” – a special header can be specified, requesting to only get an up-to-date deltaToken, this token can be used in subsequent queries, which will
return only changes from “now”.  Here’s the example call:



ocp-aad-dq-include-only-delta-token: true

Content-Type: application/json

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5nl0aEV1T….

Response: 200 OK

The response will contain the deltaLink, but will not have the changed object(s), similar to this:

{   …  “aad.deltaLink”:……   }

We’ll dive into Differential Query calls in much more detail in the upcoming posts.

Give Use Feedback

We will be updating our sample applications to show some of the above mentioned features in the new version: and in an upcoming post, we will include code snippets showing how to use these new capabilities.

Please let us know if the new features are useful, and let us know what other Api’s will be useful for your scenarios.  Leave a comment or your questions on this Post.

Thanks, Edward

Azure Active Directory Team

Microsoft Corp

Comments (33)

  1. HansZ says:

    About "Provisioning Federated Users", you're killing me with your spelling, is it: "immutableId", "immutabelId" or "immudatableId"??

  2. Apologies HansZ, it is corrected and should be "immutableId"

  3. Adam Bradley says:

    Brilliant! Thanks for this. I've been trying to use standard oData libraries against GraphAPI but I've discovered that there is no support for the standard oData paging mechanism via $top and $skip in api-version 2013-04-05. Is this available in this version?



  4. Edward Wu says:

    Hi Adam, $top is available in the previous version (2013-04-05) and in this latest version (2013-11-08), however $skip is supported at this time. You can read my previous post about paging using $top and how to page forward and backwards.  Here's an example of paging for the first 999 results:…/users$top=999&api-version=2013-11-08

    let me know if you have more questions after reading our previous Post about paging.

    Thanks, Ed

  5. Edward Wu says:

    i missed a "not" in my previous reply – I meant to write "… $skip is not supported at this time".


  6. Jacques Swanepoel says:

    Excellent!… Now I can move off PowerSshell directly to Graph as the two major limitations have been addressed:

    1. Federated Users

    2. Licensing

  7. P.K. says:


    I can't figure out how to update "immutableId" for already existing users.

    The error is: "One or more properties contains invalid values"

    Meanwhile the same value is OK for account creation.

    I'm using "general' user update endpoint like:…/<UserPrincipalName>

    PATCH HTTP Method

    and JSON content is:




    Is it possible?

    Or maybe there is any separate endpoint for that purposes?


  8. Edward Wu says:

    Looks like you're executing this correctly – I just validated that I could update this on an existing user in my tenant.  how long of a value are you using for the immutableId property?

  9. P.K. says:

    Thanks for the response.

    I can confirm that all works fine. That was some "strange" encoding issue on my side.

  10. Rob Potter says:

    Great news – we've been waiting for license assignment and the ability to set ImmutableId.

    The only gap in support for us is the ability to update domain settings, moving them between managed and federated, and setting STS urls and signing keys. Will this be available on the Graph API and if so when?

  11. D.K. says:


    But I cant' seem the update the user licenses of a existing user of when adding a new user.

    User update failed. Service returned error:A node of type 'StartObject' was read from the JSON reader when trying to read the items of a collection; however, a 'StartArray' node was expected.


                       "addLicenses" => array("disabledPlans" => "", "skuId" => "xxxxxxxxxxxxxxxxx"),

                       "removeLicenses" => ''


    Is there a PHP example somewhere.

    Thanks David

  12. test says:

    Does the rest api support creating multiple users in one call? If yes can you post a sample payload?

  13. Edward Wu says:

    Yes, we support batching – there are some current limits on the batching:

    1. batch size is currently limited to 5 operations (e.g. 5 GETs, 5 POSTs etc.)
    2. batch operations must be of the same type (e.g you can't have a GET, POST, PATCH, DELETE in the batch)

    I will follow-up and show the sample payload and response.

  14. Error Creating a new user says:

    I tried to create a new user but I keep getting this error

    StatusCode: 401, ReasonPhrase: 'Unauthorized'


    a) I am logged in using a "Global Administator" account.

    b) The application is provisioned for Read/Write Directory permissions

    c) The app is configured to allow Azure Graph Access

    d) I am using the id/secret for the app

    I succesfully get an Access Token. I fail at the PastAsJsonAsync line.  What am I doing wrong? My code is below

    ClientCredential clientCred = new ClientCredential(clientID,


         string resource = "";

           AuthenticationResult   authenticationResult = authenticationContext.AcquireToken(resource, clientCred);

      string resourceurl = "…/users //2013-04-05";

               using (HttpClient httpClient = new HttpClient())


                    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authenticationResult.AccessToken);

               HttpResponseMessage response = httpClient.PostAsJsonAsync(resourceurl, userData).Result;

    // etc etc

    I have userData very similar to your example.

  15. Ricardo J. O. Vieira says:

    I'm using this solution in the institution where i work. But at this moment I'm having a problem to list all users. Only 100 records are displayed. I'm using this operation:…/dn151678.aspx

    How can i show ALL users?

  16. Edward Wu [Msft] says:

    Regarding the Error Creating User – if you receive 401 Unauthorized, then the only reason is the app doesn't have write permissions – can you do any other update operations, such as updating an existing user or deleting a user?   Or creating,updating,deleting a security group?

    BTW, when using client creds (appId and secret), the context of the logged on user doesn't matter – the logged on user is just a user (non-Admin), but the app has read/write permissions, then the app will have read/write permission when the user executes the app.

    Thanks, Ed

  17. Edward Wu [Msft] says:

    Answer to Ricardo's question about only 100 users being returned for this query:…/users

    By default, the page size is 100.  To specify a different page size, use $top – the maximum page size is 999 – for example:…/users$top=999

    Note, if there are more results beyond your page size, the response body will contain a property called odata.nextLink  For example (note, I truncated the skiptoken value to make this more readable):

    "odata.nextLink": "directoryObjects/$/Microsoft.WindowsAzure.ActiveDirectory.User?$skiptoken=X'44537074….000000'"

    To get the next page of results, your next query would use the $skiptoken value – for example:…/users$top=999&$skiptoken=X'44537074….000000'

    If you want to read more about paging (including how to page forward/backward), please review #3 on my post:…/enhancing-graph-api-queries-with-additional-odata-supported-queries.aspx

    Thanks, Ed

  18. Edward Wu [Msft] says:

    Response to Rob Potter's question regarding domain management, and configuring managed and federation properties on the domains – you are correct, we don't have these API's today – it is something we are planning to add, so we have parity with capabilities available in Msonline PowerShell – stay tuned.

    Thanks, Ed

  19. Edward Wu says:

    Answer to P.K's question about how to update the immutableId property – after the immutableId property is set on a user, and the user has a UPN that is using a federated domain, then the way to modify the immutableId is through a 3 step process:

    1. change the user's UPN to use a non-federated (i.e. managed) domain – for example: a user with UPN = has an immutableId value set, and the domain, is a federated domain.  We need to change the UPN to a managed domain (e.g. change
    2. Now update the immutableId value

    3. Now update the user's UPN back to the federated domain – set

    these are the steps for modifying an existing immutableId property.  

    Also note: if you delete a user that has an immutableId value set, and you attempt to create or update a user to use the immutableId of the deleted user, your create/update attempt will fail with "..object already exists.."    This is because the object is in the soft-deleted state – to fix this, you will need to hard-delete the object, before attempting to re-use the immutableId on a new or existing object.

  20. Logon User silent login equivalent says:

    Is there an equivalent to Windows AD LogonUser operation in Windows Azure AD. This is to allow a user to silently login with his user ID and password to Azure AD to retrieve a JWT Token.

  21. John says:


    I'm unable to retrieve any metadata from$metadata?api-version=2013-11-08

    Also, I am trying to remove a license from a User. When I try using the 2013-04-05 API, the resource isn't there (as expected). However, I then try with 2013-11-08 and get the following response:

    Request (summarized):…/assignLicense


    "addLicenses": [],




    {"odata.error":{"code":"Request_BadRequest","message":{"lang":"en","value":"Method Not Allowed"}}}

    I have set my ServicePrincipal to be a member of 'Company Administrator' and also 'Partner Tier1 Support'.

    I'm based in the UK (not sure if this makes a difference).

    Any clues on the above? I would really like to be able to add & remove licenses using the API but I'm a bit blocked on this

  22. John says:

    I've solved the problem. I've been referring to an MS implementation document, which put the verb required as PATCH. Send through the request with a POST verb and it works fine

  23. John says:

    How do I link the Offer Id provided in the MOSI PlaceOrder call to the subscriptions/subscribedSkus for that tenant?

    I know the MOSI SubscriptionId is an internal id to MOSI. However, we rely on the OfferId and send that across. Then, when querying GRAPH, I can get the SubscribedSkus….but this only gives me a list of servicePlans (inc. GUIDS); a SKU id (unique to the tenant); and an object Id.

    Given a tenant that has 2+ subscriptions (none of which to the same offerId), how do I link these to the offer Id?

    My question from above still stands also: how do i get the metadata for the 2013-11-08 api? I can make calls to this API but I can't retrieve the metadata (which is causing me problems with the immutableId not being present)?

    Appreciate your advice. Thanks

  24. Adam Bradley says:


    A little delayed, sorry! Not being able to use GraphAPI with standard OData libraries is a bit of a hassle, given the mechanism is similar, would it be possible to implement the $skip method?

    After all, its part of the standard and I'm a little miffed as to why a non-standard method was used, curious decision (:…/ff478141.aspx


  25. Joe says:

    Whats the plan for updating these docs to include the new fields?…/hh974483.aspx

    Also how about something that describes permissible values for all known fields?

  26. Joe says:

    How does one set a value for thumbnailPhoto via the REST api? It says Edm.Stream, but does that mean I pass the bytes as a base64 encoded string?

  27. Joe says:

    What are the actual permissible values for 'userType'? The sentence below seems to imply the tenant can set it to any arbitrary string but that does not seem to be the case

    "In this new API version, we have also exposed a new user property, userType.  This is a string value that can be used to allow tenants to classify the types of users within their organization.  For example, regular employees can be identified by userType =  “Member”,  and guest accounts associated with vendors, consultants or temporary workers, could be have userType = “Guest” ."

  28. Joe says:

    For the "assignLicenses" feature

    a) I am doing the exact same thing as the example where I disable 2 service plans within a sku. This is accepted by the service with a 200

    b) I then do a GET of that user I just adjusted the licenses for. The service plans I disabled are not reflected in the AssignedPlans return element, NOR does the number of total AssignedPlans seem to reflect the change

    Why is this?

  29. Martin says:

    Is it possible to create a 'Microsoft Account' user with this version of the API?

  30. rnd says:

    there exist several complementary "relationships":  members|memberOf, owners|ownedObjects, manager|directReports …

    if these were in an sql database, they might be represented in a simple relationship table.  what i'd like to be able to do is get that *whole table* returned to me, instead of having to pick a value in either column and get all the values it has in the "other column"

    in AAD, this would amount to a call that would return links with "one endpoint of the relationship, the relationship 'method', and the other endpoint of the relationship"

    is there anything i can do to mimic this result?

    as it stands, if i have N users and M groups, i have to do at least min(M,N) separate queries…  would like "one-stop-shopping" please!

  31. Chris Williams says:

    Does "ocp-aad-dq-include-only-changed-properties" still work?  I've been trying to get it working with the 1.5 and 1.6 version apis and it always returns the entire object, not just the properties that were updated.

  32. Vikram says:

    We are trying for optimization (minimizing the time required for aggregation) of aggregation process. Currently we are using pagination but it takes lots of time min 25hrs . We wanted to reduce it to 4-5 hrs. How to achieve that ?.  Is there any query to get all users in one call without using skiptoken? Or  is there any other way to do it ?

  33. Jeverick says:


    I'm also having issues updating the immutableId property.

    My request:

    curl -v -H "Authorization: Bearer <my_token>" -H "Accept: application/json" -H "Content-Type: application/json" -X PATCH -d '{"immutableId":"some_unique_value"}' "…/<my_id>

    And I receive the following response:

    HTTP/1.1 400 Bad Request

    {"odata.error":{"code":"Request_BadRequest","message":{"lang":"en","value":"Property immutableId is invalid."},"values":[{"item":"PropertyName","value":"immutableId"},{"item":"PropertyErrorCode","value":"GenericError"}]}}

    Any help with this would be greatly appreciated.

    Thanks in advance,