|
| 1 | +--- |
| 2 | +title: "Migrate from legacy alerts to the alerts and incidents API" |
| 3 | +description: "Learn how to migrate your apps from the deprecated Microsoft Graph security alerts v1 API to the new alerts and incidents API in Microsoft 365 Defender." |
| 4 | +author: "FaithOmbongi" |
| 5 | +ms.reviewer: "Austin.Beauchamp,fengzhu" |
| 6 | +ms.localizationpriority: medium |
| 7 | +ms.subservice: "security" |
| 8 | +doc_type: conceptualPageType |
| 9 | +ms.date: 05/14/2026 |
| 10 | +ms.topic: upgrade-and-migration-article |
| 11 | +--- |
| 12 | + |
| 13 | +# Migrate from legacy alerts to the alerts and incidents API |
| 14 | + |
| 15 | +The legacy Microsoft Graph security alerts API available through the `/security/alerts` endpoint is deprecated and will be retired on **August 31, 2026**. If your app currently uses the legacy alerts API to retrieve, monitor, or manage security alerts, you should migrate to the new [alerts and incidents API](/graph/api/resources/security-alert) in Microsoft 365 Defender. |
| 16 | + |
| 17 | +This article describes the key differences between the two APIs, provides a field mapping reference, and outlines the steps to migrate your app. |
| 18 | + |
| 19 | +> [!IMPORTANT] |
| 20 | +> - After August 31, 2026, the legacy `/security/alerts` endpoint will stop returning data. Migrate your apps before this deadline to avoid disruption to your security operations workflows. |
| 21 | +> |
| 22 | +> - The new alerts and incidents API is **not** a direct, one-to-one replacement for the legacy alerts API. It surfaces alerts that are part of the Microsoft 365 Defender ecosystem. Alerts from sources that aren't integrated with Microsoft 365 Defender—such as a Microsoft Sentinel workspace that isn't connected to the Microsoft Defender portal, or standalone and tuned alerts—aren't returned by the new API. Review the [known differences and limitations](#known-differences-and-limitations) section before you begin your migration. |
| 23 | +
|
| 24 | +## Before you begin |
| 25 | + |
| 26 | +Before you start your migration, complete the following tasks: |
| 27 | + |
| 28 | +- Identify all integrations, scripts, connectors, and downstream processes that call `/security/alerts`. |
| 29 | +- If you use Microsoft Sentinel, verify whether your workspace is connected to the Microsoft Defender portal. Sentinel-generated alerts aren't available through the v2 API until you complete that onboarding. In the interim, use the [Sentinel REST API](/rest/api/loganalytics/) to retrieve Sentinel alerts. Standalone Sentinel alerts aren't supported in the v2 API, and the Sentinel REST API will be retired in the future. |
| 30 | +- Review the [known differences and limitations](#known-differences-and-limitations) to identify any supplemental data sources your workflows may require. |
| 31 | + |
| 32 | +## Why migrate? |
| 33 | + |
| 34 | +The new alerts and incidents API offers significant improvements over the legacy alerts API: |
| 35 | + |
| 36 | +- **Automatic correlation**: Alerts from multiple signals—identity, endpoint, email, and cloud—are automatically grouped into incidents, giving analysts a broader view of an attack. |
| 37 | +- **Richer evidence**: Legacy state collections (`userStates`, `hostStates`, `fileStates`) are replaced by over 40 strongly typed evidence objects, such as `userEvidence`, `azureResourceEvidence`, `aiAgentEvidence`, and `analyzedMessageEvidence` which are easier to work with programmatically. |
| 38 | +- **Incident-centric model**: The new API introduces a first-class [incident](/graph/api/resources/security-incident) object that represents the full attack story, enabling more effective investigation and response. |
| 39 | +- **Expanded threat coverage**: The unified API includes additional sources such as Microsoft Purview Data Loss Prevention and Insider Risk Management. |
| 40 | +- **Richer threat context**: Alerts and incidents include MITRE ATT&CK techniques, detection sources, and threat classification. |
| 41 | + |
| 42 | +## API differences |
| 43 | + |
| 44 | +### Endpoints |
| 45 | + |
| 46 | +The following table lists the endpoint changes. |
| 47 | + |
| 48 | +| Operation | Legacy endpoint | New endpoint | |
| 49 | +|:---|:---|:---| |
| 50 | +| List alerts | `GET /v1.0/security/alerts` | `GET /v1.0/security/alerts_v2` | |
| 51 | +| Get alert by ID | `GET /v1.0/security/alerts/{id}` | `GET /v1.0/security/alerts_v2/{id}` | |
| 52 | +| Update alert | `PATCH /v1.0/security/alerts/{id}` | `PATCH /v1.0/security/alerts_v2/{id}` | |
| 53 | +| List incidents | Not available | `GET /v1.0/security/incidents` | |
| 54 | +| Get incident by ID | Not available | `GET /v1.0/security/incidents/{id}` | |
| 55 | + |
| 56 | +### Permissions |
| 57 | + |
| 58 | +Your app registration must be updated with new Microsoft Graph permission scopes. |
| 59 | + |
| 60 | +| Scenario | Legacy permission | New permission | |
| 61 | +|:---|:---|:---| |
| 62 | +| Read alerts | `SecurityEvents.Read.All` | `SecurityAlert.Read.All` | |
| 63 | +| Read and write alerts | `SecurityEvents.ReadWrite.All` | `SecurityAlert.ReadWrite.All` | |
| 64 | +| Read incidents | API not available | `SecurityIncident.Read.All` | |
| 65 | +| Read and write incidents | API not available | `SecurityIncident.ReadWrite.All` | |
| 66 | + |
| 67 | +After you add the new permissions to your app registration, an admin must grant consent before the app can use them in production. |
| 68 | + |
| 69 | +For more information about these permissions, see [Microsoft Graph permissions reference](/graph/permissions-reference). |
| 70 | + |
| 71 | +### Field mapping |
| 72 | + |
| 73 | +The following table maps legacy [alerts v1](/graph/api/resources/alert) fields to their [alerts v2](/graph/api/resources/security-alert) equivalents. This mapping only covers fields that exist in v1 and have a direct or approximate counterpart in v2. The new API includes many additional fields that provide richer context about alerts and incidents. |
| 74 | + |
| 75 | +> [!div class="mx-tableFixed"] |
| 76 | +> | v1 field | v2 field | Notes | |
| 77 | +> |:---|:---|:---| |
| 78 | +> | azureTenantId | tenantId | Same meaning, renamed property. | |
| 79 | +> | lastModifiedDateTime | lastUpdateDateTime | Tracks the latest update time. | |
| 80 | +> | closedDateTime | resolvedDateTime | Represents when the alert was resolved. | |
| 81 | +> | activityGroupName | actorDisplayName | Renamed field for actor context. | |
| 82 | +> | feedback | classification + determination | v2 separates disposition from attack-type determination. | |
| 83 | +> | vendorInformation.provider | serviceSource + productName | Provider metadata is split into an enum and a display name. | |
| 84 | +> | sourceMaterials[] | alertWebUrl + incidentWebUrl | Portal links now point to the unified Defender experience. | |
| 85 | +> | eventDateTime | firstActivityDateTime + lastActivityDateTime | Single timestamp becomes a time range. | |
| 86 | +> | incidentIds[] | incidentId | Each alert now belongs to exactly one incident. | |
| 87 | +> | userStates[].userPrincipalName | evidence(userEvidence).userAccount.userPrincipalName | User entities move into typed evidence objects. | |
| 88 | +> | hostStates[].fqdn | evidence(deviceEvidence).deviceDnsName | Host information moves into device evidence. | |
| 89 | +> | fileStates[].name / fileHash.hashValue | evidence(fileEvidence).fileName / fileDetails.sha256 | File metadata and hashes move into file evidence. | |
| 90 | +> | networkConnections[].destinationUrl | evidence(urlEvidence).url | Network artifacts decompose into separate evidence types. | |
| 91 | +> | networkConnections[].destinationAddress | evidence(ipEvidence).ipAddress | IP addresses move into IP evidence. | |
| 92 | +> | confidence | No direct replacement | Use evidence-level verdict values such as suspicious or malicious instead of a numeric score. | |
| 93 | +
|
| 94 | +## Migrate your app |
| 95 | + |
| 96 | +Use these steps to migrate from the legacy alerts API to the new alerts and incidents API. |
| 97 | + |
| 98 | +### Step 1: Identify dependencies |
| 99 | + |
| 100 | +Before you change any code, identify all integrations, scripts, connectors, and downstream processes that currently call `/security/alerts`. |
| 101 | + |
| 102 | +### Step 2: Connect Microsoft Sentinel for unified visibility |
| 103 | + |
| 104 | +If you use Microsoft Sentinel, connect your workspace to the Microsoft Defender portal and confirm that relevant detections are promoted into incidents. Without this integration, Sentinel-generated alerts don't appear in the v2 API. |
| 105 | + |
| 106 | +While you prepare for onboarding, use the [Sentinel REST API](/rest/api/loganalytics/) to retrieve Sentinel alerts. Be aware that standalone Sentinel alerts aren't supported in the new API model, and the Sentinel REST API will be retired in the future. Prioritize Defender portal onboarding ahead of the August 31, 2026 deadline. |
| 107 | + |
| 108 | +For more information, see [Connect Microsoft Sentinel to the Microsoft Defender portal](/unified-secops/microsoft-sentinel-onboard) and [Transition your Microsoft Sentinel environment to the Defender portal](/azure/sentinel/move-to-defender). |
| 109 | + |
| 110 | +### Step 3: Update API endpoints and permissions |
| 111 | + |
| 112 | +For each integration: |
| 113 | + |
| 114 | +1. Replace calls to `/security/alerts` with `/security/alerts_v2` or `/security/incidents` as appropriate for your workflow. |
| 115 | +2. Update app registration permissions and obtain admin consent. |
| 116 | +3. Document any authentication gaps and resolve them before the retirement deadline. |
| 117 | + |
| 118 | +### Step 4: Update your data model and query logic |
| 119 | + |
| 120 | +The v2 migration requires more than a field-for-field swap. Plan for the following changes: |
| 121 | + |
| 122 | +- **Treat incidents as first-class objects**: In v2, alerts belong to incidents. Consider building your workflow around incidents to get the full attack story. |
| 123 | +- **Update parsing and enrichment logic**: Replace references to `userStates`, `hostStates`, `fileStates`, and `networkConnections` with the corresponding typed evidence objects. |
| 124 | +- **Rewrite OData filters**: Update query filters to use the new property names and the `evidence/any()` function for evidence-based filtering. |
| 125 | + |
| 126 | +The following examples show common filter rewrites. |
| 127 | + |
| 128 | +**Filter by product or source** |
| 129 | + |
| 130 | +```http |
| 131 | +# Legacy |
| 132 | +GET /v1.0/security/alerts?$filter=vendorInformation/provider eq 'Microsoft Defender ATP' |
| 133 | +
|
| 134 | +# New - alerts v2 |
| 135 | +GET /v1.0/security/alerts_v2?$filter=serviceSource eq 'microsoftDefenderForEndpoint' |
| 136 | +``` |
| 137 | + |
| 138 | +**Filter by involved user** |
| 139 | + |
| 140 | +```http |
| 141 | +# Legacy: No direct OData filter on userStates sub-properties; required client-side filtering. |
| 142 | +
|
| 143 | +# New - alerts v2 |
| 144 | +GET /v1.0/security/alerts_v2?$filter=evidence/any(e: e/microsoft.graph.security.userEvidence/userAccount/userPrincipalName eq 'alice@contoso.com') |
| 145 | +``` |
| 146 | + |
| 147 | +**Filter by involved device** |
| 148 | + |
| 149 | +```http |
| 150 | +# Legacy |
| 151 | +GET /v1.0/security/alerts?$filter=hostStates/any(h: h/fqdn eq 'pc123.contoso.com') |
| 152 | +
|
| 153 | +# New |
| 154 | +GET /v1.0/security/alerts_v2?$filter=evidence/any(e: e/microsoft.graph.security.deviceEvidence/deviceDnsName eq 'pc123.contoso.com') |
| 155 | +``` |
| 156 | + |
| 157 | +**Incident-centric queries (new capability)** |
| 158 | + |
| 159 | +```http |
| 160 | +# Get all active, high-severity incidents |
| 161 | +GET /v1.0/security/incidents?$filter=status eq 'active' and severity eq 'high' |
| 162 | +
|
| 163 | +# Get all alerts for a specific incident |
| 164 | +GET /v1.0/security/incidents/{incidentId}/alerts |
| 165 | +``` |
| 166 | + |
| 167 | +### Step 5: Validate coverage and downstream workflows |
| 168 | + |
| 169 | +Before you retire your legacy integration: |
| 170 | + |
| 171 | +1. Confirm that expected alerts and incidents are returned by the new API. |
| 172 | +2. Verify that downstream workflows—such as automation, reporting, and SIEM ingestion—work correctly after the migration. |
| 173 | +3. Review known coverage differences and identify any supplemental data sources you still need. |
| 174 | + |
| 175 | +Use an API testing tool like [Graph Explorer](https://aka.ms/ge) to validate your queries and inspect the new data model. |
| 176 | + |
| 177 | +## Known differences and limitations |
| 178 | + |
| 179 | +- **Microsoft Sentinel coverage**: Sentinel-generated alerts aren't returned by the v2 API unless your Sentinel workspace is connected to the Microsoft Defender portal. In the interim, use the [Sentinel REST API](/rest/api/loganalytics/) to retrieve these alerts. |
| 180 | +- **Standalone alerts**: Alerts that exist outside of the Microsoft 365 Defender incident model—including standalone detections not promoted to an incident—aren't returned by the v2 API. |
| 181 | +- **Tuned alerts**: Alerts suppressed by alert-tuning rules aren't returned through the `alerts_v2` endpoint. |
| 182 | +- **Low-signal Exchange Online events**: Certain low-signal Exchange Online events, such as mailbox rule creation and message delays, aren't included in `alerts_v2`. Retrieve these through audit logs or other relevant data sources. |
| 183 | + |
| 184 | +## Related content |
| 185 | + |
| 186 | +- [alert resource type (deprecated)](/graph/api/resources/alert) |
| 187 | +- [alert resource type (new)](/graph/api/resources/security-alert) |
| 188 | +- [incident resource type](/graph/api/resources/security-incident) |
| 189 | +- [Connect Microsoft Sentinel to the Microsoft Defender portal](/unified-secops/microsoft-sentinel-onboard) |
0 commit comments