An API that connects multiple Microsoft services, enabling data access and automation across platforms
Microsoft Graph does not support combining an advanced directory query with $expand=manager; retrieve the filtered users first, then request their managers in a second phase.
The restriction applies when the filter requires advanced query parameters—ConsistencyLevel: eventual and $count=true. Microsoft explicitly documents that $expand is not supported with advanced queries.^1^ This also applies to advanced filtering on directory-object relationships.^2^
Supported approach
1. Retrieve the filtered users
For example:
GET https://graph.microsoft.com/v1.0/users?$select=id,displayName,userPrincipalName&$filter=accountEnabled ne true&$count=true
Authorization: Bearer {token}
ConsistencyLevel: eventual
Follow every @odata.nextLink until it is absent. The advanced query uses a separately maintained index, so recent directory changes might not appear immediately.^2^
2. Retrieve each returned user’s manager
For every user ID returned by step 1:
GET https://graph.microsoft.com/v1.0/users/{user-id}/manager?$select=id,displayName,mail,userPrincipalName
Authorization: Bearer {token}
A user without an assigned manager returns 404 Not Found.^3^
Reduce round trips with JSON batching
After collecting the filtered user IDs, place up to 20 manager requests in one $batch call:
POST https://graph.microsoft.com/v1.0/$batch
Authorization: Bearer {token}
Content-Type: application/json
{
"requests": [
{
"id": "1",
"method": "GET",
"url": "/users/{user-id-1}/manager?$select=id,displayName,mail"
},
{
"id": "2",
"method": "GET",
"url": "/users/{user-id-2}/manager?$select=id,displayName,mail"
}
]
}
A batch supports up to 20 individual requests.^4^ Check each individual response status: the overall batch can return 200 even when an individual manager request returns 404, 403, or 429.
This still requires at least:
- One or more calls to obtain all pages of filtered users.
- One or more batch calls for their managers.
A single batch cannot dynamically create one manager request per user returned by the filtering request. Batch request URLs must be defined in the submitted payload; dependsOn controls execution order but does not provide dynamic fan-out or substitute IDs from a collection response.
If an individual request is throttled, retry that request using its Retry-After value; batched requests are not automatically retried by the SDK.^5^
When one ordinary GET can work
If the filter does not require advanced-query mode, the manager API documents expansion over the users collection:
GET https://graph.microsoft.com/v1.0/users?$select=id,displayName,userPrincipalName&$filter=accountEnabled eq false&$expand=manager
Authorization: Bearer {token}
$expand=manager returns the immediate manager when no $levels value is supplied.^3^ Do not add $count=true and ConsistencyLevel: eventual merely to force this combination; they do not remove the advanced-query restriction.
Also note that unsupported query-parameter combinations can sometimes fail silently rather than return an explicit error, so verify that the response actually contains manager data.^6^
Permissions
For the documented user-manager operation, the least-privileged delegated work-or-school permission is User.Read.All; personal Microsoft accounts are unsupported. The current manager API permissions table lists application permissions as unsupported.^3^ If the application uses app-only authentication, validate the intended manager operation against that limitation before implementing the batching design.
References