Security & identity

Defender advanced hunting API retirement: move to Graph runHuntingQuery

The Defender for Endpoint and Defender XDR advanced hunting APIs stop working on 1 February 2027 (MC1220762). Find callers, switch to Microsoft Graph runHuntingQuery and ThreatHunting.Read.All.

By EpiFive Editorial TeamReviewed/updated 11 min readHow we check articles
On this page

Microsoft is retiring the Microsoft Defender for Endpoint and Microsoft Defender XDR advanced hunting APIs: according to Message center post MC1220762, they no longer function after 1 February 2027, and you should finish migrating by 31 January 2027. The replacement is the Microsoft Graph security API action runHuntingQuery, called at https://graph.microsoft.com/v1.0/security/runHuntingQuery with the ThreatHunting.Read.All permission. Your KQL queries normally carry over unchanged; the token audience, endpoint, permission and response property names are what you change.

Who this is for and what you will have

This guide is for security engineers and developers who run advanced hunting queries from scripts, SIEM or SOAR integrations, Power Automate flows, Logic Apps or Power BI reports. At the end you will have:

  • A list of integrations and app registrations still calling the old endpoints.
  • The new permission granted and the old ones scheduled for removal.
  • Working code against runHuntingQuery, with a side-by-side comparison of the old and new calls.
  • A test plan to run both in parallel before the cutoff.

What changes and when

DateEvent
January 2026Retirement begins, per the Defender for Endpoint API page.
22 January 2026MC1220762 published, with retirement starting 6 February 2026.
26 October 2026MC1220762 updated as a reminder.
31 January 2027Act-by date: migrate every workflow.
1 February 2027The old APIs stop functioning and stop returning data.

Microsoft sent MC1220762 to tenants where its telemetry suggests the old APIs are in use, so if you received it, treat that as a strong signal that something in your tenant still calls them.

Which endpoints are retiring

APIEndpointOld permissions
Defender for Endpoint advanced huntingPOST https://api.securitycenter.microsoft.com/api/advancedqueries/run, also documented as https://api.security.microsoft.com/api/advancedqueries/run and regional hosts such as us.api.security.microsoft.comAdvancedQuery.Read (delegated), AdvancedQuery.Read.All (application) on the Microsoft Defender for Endpoint API (formerly Windows Defender Advanced Threat Protection)
Defender XDR advanced huntingPOST https://api.security.microsoft.com/api/advancedhunting/runAdvancedHunting.Read (delegated), AdvancedHunting.Read.All (application) on Microsoft Threat Protection

A related deadline: the Microsoft Graph legacy alerts API (/security/alerts) was due for retirement on 15 October 2026, with alerts_v2 and incidents as the replacement. If your integration still uses it, it's already on borrowed time.

What the new API looks like

SubjectOld APIMicrosoft Graph
Endpoint.../api/advancedqueries/run or .../api/advancedhunting/runhttps://graph.microsoft.com/v1.0/security/runHuntingQuery
Token audienceDefender for Endpoint resource, https://api.securitycenter.microsoft.comMicrosoft Graph, https://graph.microsoft.com
PermissionAdvancedQuery.Read(.All) or AdvancedHunting.Read(.All)ThreatHunting.Read.All, delegated or application
Request bodyQueryQuery, optional Timespan (ISO 8601) and optional workspaceId
ResponseStats, Schema, ResultshuntingQueryResults with schema and results

runHuntingQuery is available in Microsoft Graph v1.0 for the global service, US Government L4 and US Government L5 (DOD). It is not available in Microsoft Graph China operated by 21Vianet, and Microsoft doesn't document an alternative for that cloud on the pages reviewed here.

Limits

Microsoft documents these quotas for Graph advanced hunting:

  • Queries return data from the past 30 days.
  • Up to 100,000 rows per result and an overall result size limit of 50 MB.
  • At least 45 calls per minute per tenant, varying with tenant size.
  • CPU is allocated per tenant; at 100 percent, queries are blocked until the next 15-minute cycle.
  • A single request times out after three minutes.
  • HTTP 429 means you reached a call or CPU limit; the response body says which.

The old API documented a 200-second maximum per request and fixed hourly and daily execution budgets, so retry logic tuned for those numbers should be reviewed.

One inconsistency to know about: the runHuntingQuery page shows an example with "Timespan": "P90D", while the quota list says queries explore the past 30 days. Microsoft's documentation doesn't reconcile the two, so test the time range you need rather than assuming more than 30 days.

Prerequisites

  • An app registration in Microsoft Entra ID for each integration, or permission to create one.
  • An admin who can grant tenant-wide consent to Microsoft Graph application permissions; Microsoft's admin consent documentation requires Privileged Role Administrator for Microsoft Graph app roles.
  • For delegated calls, users with access to the advanced hunting data in Microsoft Defender XDR.
  • Microsoft Graph PowerShell (Microsoft.Graph.Security) if you want to use the SDK cmdlet.

Step 1: Find everything that calls the old APIs

Search code and configuration for these strings: advancedqueries/run, advancedhunting/run, api.securitycenter.microsoft.com and api.security.microsoft.com. Include SIEM connector settings, SOAR playbooks, Azure Functions, Logic Apps definitions, Power BI data source queries and scheduled scripts.

Check Power Automate and Logic Apps for the Advanced Hunting action in the Microsoft Defender ATP connector.

Check app registrations for the old permissions. This script lists which service principals hold application permissions on the two old APIs. It uses standard Microsoft Graph PowerShell cmdlets; it isn't a script Microsoft publishes:

Connect-MgGraph -Scopes 'Application.Read.All'
 
foreach ($api in 'WindowsDefenderATP', 'Microsoft Threat Protection') {
    $sp = Get-MgServicePrincipal -Filter "displayName eq '$api'"
    if (-not $sp) { continue }
    Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $sp.Id -All |
        ForEach-Object {
            $role = $sp.AppRoles | Where-Object Id -eq $_.AppRoleId
            [pscustomobject]@{
                Api        = $api
                ClientApp  = $_.PrincipalDisplayName
                Permission = $role.Value
            }
        } | Where-Object Permission -in 'AdvancedQuery.Read.All', 'AdvancedHunting.Read.All'
}

Every client app in the output is a candidate for migration. Delegated permissions (AdvancedQuery.Read, AdvancedHunting.Read) are granted differently and won't appear here; review those under each app's API permissions page in the Microsoft Entra admin center.

Step 2: Grant the Graph permission

For each app that needs to keep hunting:

  1. In the Microsoft Entra admin center, open App registrations and select the app.
  2. Select API permissions > Add a permission > Microsoft Graph.
  3. Choose Application permissions for a daemon or Delegated permissions for a signed-in user, then select ThreatHunting.Read.All and Add permissions.
  4. Select Grant admin consent for your organization.

Keep the old permission until the new code is tested in production; remove it afterwards.

Step 3: Change the code

Before: Defender for Endpoint API

A typical legacy daemon script requests a token for the Defender for Endpoint resource and posts the query:

$tenantId = '<tenant-id>'
$appId    = '<app-id>'
$secret   = '<client-secret>'
 
$tokenBody = @{
    resource      = 'https://api.securitycenter.microsoft.com'
    client_id     = $appId
    client_secret = $secret
    grant_type    = 'client_credentials'
}
$token = (Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$tenantId/oauth2/token" -Body $tokenBody).access_token
 
$body = @{ Query = "DeviceProcessEvents | where InitiatingProcessFileName =~ 'powershell.exe' | project Timestamp, FileName, InitiatingProcessFileName, DeviceId | limit 2" } | ConvertTo-Json
 
$response = Invoke-RestMethod -Method Post -Uri 'https://api.securitycenter.microsoft.com/api/advancedqueries/run' -Headers @{ Authorization = "Bearer $token" } -ContentType 'application/json' -Body $body
$response.Results

After: Microsoft Graph with the PowerShell SDK

The SDK cmdlet that wraps runHuntingQuery is Start-MgSecurityHuntingQuery. With app-only authentication and a certificate:

Import-Module Microsoft.Graph.Security
 
Connect-MgGraph -TenantId '<tenant-id>' -ClientId '<app-id>' -CertificateThumbprint '<thumbprint>'
 
$params = @{
    Query    = "DeviceProcessEvents | where InitiatingProcessFileName =~ 'powershell.exe' | project Timestamp, FileName, InitiatingProcessFileName, DeviceId | limit 2"
    Timespan = 'P7D'
}
 
$result = Start-MgSecurityHuntingQuery -BodyParameter $params
$result.Results

After: Microsoft Graph over REST

If you call the REST API directly, request a token for Microsoft Graph with the client credentials flow and the .default scope, then post to the new endpoint:

$tokenBody = @{
    client_id     = $appId
    scope         = 'https://graph.microsoft.com/.default'
    client_secret = $secret
    grant_type    = 'client_credentials'
}
$token = (Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -Body $tokenBody).access_token
 
$body = @{
    Query    = "DeviceProcessEvents | where InitiatingProcessFileName =~ 'powershell.exe' | project Timestamp, FileName, InitiatingProcessFileName, DeviceId | limit 2"
    Timespan = 'P7D'
} | ConvertTo-Json
 
$response = Invoke-RestMethod -Method Post -Uri 'https://graph.microsoft.com/v1.0/security/runHuntingQuery' -Headers @{ Authorization = "Bearer $token" } -ContentType 'application/json; charset=utf-8' -Body $body
$response.results

Prefer a certificate over a client secret for production daemons. Microsoft notes that if a query contains non-ANSI characters, such as lookalike characters in email subjects, the Content-Type should be application/json; charset=utf-8.

The response

The documented Graph response looks like this:

{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.security.huntingQueryResults",
    "schema": [
        { "name": "Timestamp", "type": "DateTime" },
        { "name": "FileName", "type": "String" },
        { "name": "InitiatingProcessFileName", "type": "String" }
    ],
    "results": [
        {
            "Timestamp": "2024-03-26T09:39:50.7688641Z",
            "FileName": "cmd.exe",
            "InitiatingProcessFileName": "powershell.exe"
        }
    ]
}

Property access in PowerShell is case-insensitive, so $response.Results still works. In Python dictionaries, JavaScript objects and strict JSON deserializers it doesn't: change Results to results, Schema to schema, and Name/Type inside the schema to name/type. Code that read Stats from the old response has no equivalent property in the documented Graph response. Microsoft's second runHuntingQuery example also shows result columns in camelCase (timestamp, fileName), so don't hard-code the casing of column names; read them from schema.

Step 4: Power Platform and Power BI

  • Power Automate, Power Apps and Logic Apps: Microsoft says Graph has no built-in equivalent of the Defender ATP connector's Advanced Hunting action. Create a custom connector that calls runHuntingQuery, following Microsoft's Power Automate custom connector tutorial for Microsoft Graph, and use the parameters in the table above.
  • Power BI: update the report's query to the Graph endpoint, token audience and body. Microsoft has a separate article on custom Defender XDR reports with the Graph security API and Power BI.

Step 5: Test, cut over and roll back

  1. Run the old and new calls side by side with the same query and a fixed time range, and compare row counts and a sample of rows.
  2. Load test at your real schedule. Look for 429 responses and three-minute timeouts, and add back-off that reads the response body.
  3. Switch production to the new call. Keep the old code path behind a configuration flag until you have a few days of clean runs.
  4. Rollback before 1 February 2027 is that flag: the old API still answers until then. After that date there is nothing to roll back to, so finish the cutover with time to spare.
  5. Remove AdvancedQuery.Read.All or AdvancedHunting.Read.All from each migrated app and revoke any client secrets you replaced with certificates.

Troubleshooting

401 or 403 from Graph. The token is still for the old resource, or ThreatHunting.Read.All hasn't been consented. Decode the token and check the audience is Microsoft Graph and the roles claim includes the permission.

A large query fails after the switch. The old API returned 400 Bad Request for results over 50 MB, and Graph documents the same 50 MB overall limit, along with a three-minute timeout. Reduce columns and rows with project, summarize and limit.

Parser errors after the switch. The code expects Results and Schema with capital letters. Update it as described above.

Fewer rows than expected. Graph applies the shorter of the query's own time filter and Timespan. If you didn't set Timespan, the default is 30 days.

For KQL you can reuse in these calls, see Defender XDR advanced hunting KQL queries for identity attacks.

Checklist

  • Searched code, connectors, flows and reports for the old endpoints.
  • Listed app registrations with AdvancedQuery.Read.All or AdvancedHunting.Read.All.
  • Granted ThreatHunting.Read.All and admin consent.
  • Updated token audience, endpoint, body and response parsing.
  • Rebuilt Power Automate actions as a custom connector and updated Power BI queries.
  • Ran old and new side by side, then cut over before 31 January 2027.
  • Removed the old permissions and secrets.

What we checked

  • Opened MC1220762 on mc.merill.net on 2026-11-12: published 22 January 2026, updated 26 October 2026, retirement starting 6 February 2026, full retirement 1 February 2027 and act-by 31 January 2027. The post itself lists no endpoint URLs or permissions.
  • Copied the migration table (endpoints, resource URI, old and new permissions, request body and response properties) from the Microsoft Graph security API overview, updated 3 November 2026, which says the older APIs stop returning data on 1 February 2027.
  • Confirmed on the runHuntingQuery v1.0 page that the least privileged permission is ThreatHunting.Read.All for both delegated and application, that 21Vianet isn't supported, and copied the Start-MgSecurityHuntingQuery cmdlet and the documented response.
  • Compared the limits on the old Defender for Endpoint API page (updated 28 July 2026: 200 seconds per request, 45 calls per minute, 1,500 per hour) with the Graph quotas (three-minute timeout, CPU per 15-minute cycle).
  • Noted two documentation inconsistencies: the Defender for Endpoint page says retirement began in January 2026 while MC1220762 says 6 February 2026, and the runHuntingQuery example uses P90D while the quotas say 30 days.
  • The app registration script in Step 1 is our own composition of documented Microsoft Graph PowerShell cmdlets and wasn't run against a tenant. The "before" token request follows the client credentials pattern the old Defender for Endpoint samples used.
  • Not tested on a live tenant; steps follow Microsoft's documentation as of 2026-11-12.

Last tested: 2026-11-12

References

Questions people ask

When do the Defender advanced hunting APIs stop working?

Message center post MC1220762 says the Microsoft Defender for Endpoint and Defender XDR advanced hunting APIs are fully retired on 1 February 2027 and will no longer function after that date. Microsoft asks you to finish migrating by 31 January 2027. There is no automatic migration.

Which permission does Microsoft Graph runHuntingQuery need?

ThreatHunting.Read.All, as a delegated or application permission on Microsoft Graph. It replaces AdvancedQuery.Read and AdvancedQuery.Read.All on the Defender for Endpoint API and AdvancedHunting.Read and AdvancedHunting.Read.All on Microsoft Threat Protection.

Do I need to rewrite my KQL queries?

Usually not. runHuntingQuery takes the same Kusto query in the Query property. What changes is the endpoint, the token audience, the permission and the response property names, which are schema and results in lowercase instead of Schema and Results.

Is there a Power Automate action for Graph advanced hunting?

Not a built-in one. Microsoft says Graph has no equivalent of the Advanced Hunting action in the Microsoft Defender ATP connector, and recommends a custom connector that calls runHuntingQuery.

Is runHuntingQuery available in all clouds?

Microsoft lists it for the global service, US Government L4 and US Government L5 (DOD), but not for Microsoft Graph China operated by 21Vianet.

Microsoft Defender XDRMicrosoft Defender for EndpointMicrosoft Graph security APIAdvanced huntingKQL
  1. Defender XDR Advanced Hunting KQL Queries for Identity Attacks

    Hunt password spray, MFA fatigue and suspicious Entra sign-ins with KQL in Defender XDR advanced hunting, then turn the queries into custom detections.

  2. Send Entra Sign-in and Audit Logs to Log Analytics for Retention

    Route Microsoft Entra sign-in and audit logs to a Log Analytics workspace, set table retention beyond 30 days, and query or restore old data later.

  3. Investigating AiTM Phishing and Token Theft in Entra Sign-in Logs

    Scope an adversary-in-the-middle phishing incident with Entra sign-in logs, ID Protection detections and KQL, then contain it, remove attacker persistence and close the gaps.

  4. Attack surface reduction rules: move from audit mode to block safely

    Roll out Microsoft Defender attack surface reduction rules in rings: audit first, read the data in advanced hunting, add narrow exclusions, then block.

  5. Apache HTTP Server HTTP/2 RCE (CVE-2026-119618): Check and Patch

    Apache HTTP Server 2.4.55 through 2.4.70 has a critical mod_http2 flaw, CVE-2026-119618. Learn how to check whether you are exposed, upgrade to 2.4.71 or disable HTTP/2.

  6. Hijacked GitHub Accounts Ran a CI Secret Stealer: Check Your Repos Now

    Thousands of hijacked GitHub accounts pushed the wfx-loot CI secret stealer into repositories. Check for the published indicators, rotate secrets and remove cloud backdoors.