Reference: Changes & Activity
What changed, when, and who did it. This is the data behind the Change Tracking, Change Analysis and Activity Explorer pages. Scan pair and time window rules are in Conventions.
7 Routes
Which change route should I use?
getScanDiffcompares two StratoLens scans exactly like the Changes page: ignore rules applied, role assignment changes included. Its counts match the UI.getResourceGraphChangesandresource-changes-summaryare raw Azure Resource Graph change events, with exact time and changer. They are not filtered by ignore rules and do not include role assignment changes.- The activity-log routes give Azure Activity Log operations, including role assignment (RBAC) activity and failed operations.
Scan Comparison
GET /api/getScanDiff
Permission: View Resources
Everything added, deleted or modified between two scans. Every page recomputes the whole diff, so prefer one unpaged call.
Parameters
| Name | Required | Notes |
|---|---|---|
baseScanId, compareScanId | yes | Scan pair: older, then newer |
pageSize | no | Absent = the whole diff in one response (recommended). Present = up to 1000; 0, a negative or a non-numeric value means 100 |
continuationToken | no | The offset returned by the previous page. Read only when pageSize is also sent; without pageSize it is silently ignored and the whole diff is returned |
Errors
- 400Scan-pair errors (see Conventions). A 404 can also mean the scan has no inventory you can see
- 400
Invalid continuationToken '<tok>' - expected a non-negative integer offset. - 500
An error occurred while processing the scan comparison.
Response: { summary, manifest, resources[], optimizationMetadata, pagination? }.
| Field | Meaning |
|---|---|
summary | { baseScanId, compareScanId, baseScanTime, compareScanTime, added, deleted, modified }. Counts cover the whole diff |
manifest | The newer scan's summary record (see getScanResults) |
resources[] | One item per entity (below) |
optimizationMetadata | { ignoreMetrics, ignoreRulesUsed[], ignoreRulesTimestamp }: what the installation's ignore rules suppressed |
pagination | Only when pageSize was sent: { pageSize, continuationToken?, hasMore, totalResults } |
resources[] item
| Field | Meaning |
|---|---|
id, name, type, location, resourceGroup, subscriptionId, subscriptionName, tenantId, tags, entityType, properties | The entity |
rbacSummary, rbacAssignments | Role assignments |
changeStatus | added, deleted, modified, unchanged |
changes[] | { property, before, after }, where property is one of name, entityName, location, subscriptionName, resourceGroup, properties, rbacAssignments, tags |
diffTree? | Nested property diff. Each node: { status: added | deleted | modified | nested, before?, after?, children?, isIgnored? } |
hasIgnoredChanges? | Changes hidden by ignore rules |
hasChildChanges?, childChangeCounts? | { added, modified, deleted } for child resources |
Notes
resourcesalso contains every subscription and management group (even when unchanged) and resources whose only changes were ignored. Filter onchangeStatus !== "unchanged"to get real changes.
Example
GET /api/getScanDiff?baseScanId=<older>&compareScanId=<newer>Resource Graph Changes and Attribution
GET /api/getResourceGraphChanges
Permission: View Resource Changes
Raw Azure change events in a time window, newest first. Every page re-reads the whole window, so prefer narrower windows over deep offset walks.
Parameters
| Name | Required | Notes |
|---|---|---|
start, end | yes | Time window |
subscriptionId | no | Exact |
resourceGroupName, resourceName | no | Case-insensitive |
resourceId | no | Any case |
entityType | no | subscription, resourceGroup, resource, managementGroup |
managementGroupId | no | Plain management group name (not a path); used with entityType=managementGroup |
limit | no | 1-10000; default all |
offset | no | ≥ 0; default 0 |
entityType rules: subscription returns only subscription-level events; resourceGroup needs resourceGroupName; resource needs resourceName + resourceGroupName; managementGroup needs managementGroupId. Without its companion parameter, the type filter is ignored.
Errors
- 400
GET requests require 'start' and 'end' query parameters - 400Time-window errors
- 400
limit must be an integer between 1 and 10000 - 400
offset must be a non-negative integer - 400
entityType must be 'subscription', 'resourceGroup', 'resource', or 'managementGroup' - 500
Failed to retrieve resource graph changes: <message>
Response: { changes[], totalCount, hasMore, limit, offset }. totalCount counts every match. Each change:
| Field | Meaning |
|---|---|
resourceId (lower-case), originalResourceId, resourceName?, resourceType?, resourceGroupName?, subscriptionId, subscriptionName?, entityType?, managementGroupId?, managementGroupName? | What changed |
changeType | Create, Update, Delete |
changeTime | When |
changedBy? | UPN or app ID |
userDisplayName? | Resolved name |
changedByType?, clientType? | Who or what made the change |
changedProperties[] | Property paths that changed |
beforeState?, afterState? | Full resource snapshots |
hasFullSnapshots?, snapshotDataSource? | Snapshot provenance |
correlationId? | Links to Activity Log operations |
activityMonth | YYYY-MM |
Notes
- Ordered newest first, then by ID; offset walks are stable.
Example
GET /api/getResourceGraphChanges?start=2026-10-01T00:00:00Z&end=2026-10-14T23:59:59Z&subscriptionId=<guid>&limit=500GET /api/resource-changes-summary
Permission: View Resource Changes
Change counts per entity, per change type and per user, for a window.
Parameters
| Name | Required | Notes |
|---|---|---|
start, end | yes | Time window |
subscriptionId | no | |
resourceGroupName | no | Needs subscriptionId |
Errors
- 400
GET requests require 'start' and 'end' query parameters - 400Time-window errors
- 400
resourceGroupName requires subscriptionId to be specified - 500
Failed to retrieve resource graph changes summary: <message>
Response: { compactSummaries[], availableFilters, totalCount }. availableFilters is { changeTypes[], operationTypes[] (same values), users[] }. Each summary:
| Field | Meaning |
|---|---|
entityId, displayName, entityType | ARM ID (Azure casing), name, level |
subscriptionId, subscriptionName, resourceGroupName?, resourceType?, managementGroupId?, managementGroupName? | Location |
totalCount | Changes |
changeTypeCounts | { Create, Update, Delete } |
userCounts | Keyed by display name, else changer ID, else "Unknown" |
combinedCounts | Key changeType|user; split on the first | |
Example
GET /api/resource-changes-summary?start=…&end=…&subscriptionId=<guid>GET /api/getChangeAttribution
Permission: View Resource Changes and/or View Azure Activity Logs. Each source is used when you have its permission
For a window, who changed each resource.
Parameters
| Name | Required | Notes |
|---|---|---|
startTimestamp, endTimestamp | yes | Time window. Bounds are compared as you sent them, not whole-second normalised |
subscriptionIds | no | Encoded list, max 200. Management-group records are always included |
Errors
- 403
Requires change_tracking.read or activity_log.read permission - 400
Please provide both startTimestamp and endTimestamp query parameters - 400Time-window and list errors
- 500
Failed to retrieve change attribution
Response: { attributions, sources, timeWindow }.
| Field | Meaning |
|---|---|
attributions | Object keyed by lower-case resource ID. Each value is an array of { key, displayName, sources: ["arg" | "activity"], changeCount, rbacCount, lastChangeTime } |
sources | { arg, activity }: which sources were used |
timeWindow | Echoes your input |
Example
GET /api/getChangeAttribution?startTimestamp=2026-10-07T02:00:00Z&endTimestamp=2026-10-14T02:00:00Z&subscriptionIds=<guid1>,<guid2>Azure Activity Log
GET /api/getActivityLogsInTimeWindow
Permission: View Azure Activity Logs
Activity Log operations that changed something, in a window. Ordered oldest first, no paging.
Parameters
| Name | Required | Notes |
|---|---|---|
startTimestamp, endTimestamp | yes | Time window |
resourceIds | no | CSV, max 200. A prefix match, so child resources are included. Send lower-case IDs |
subscriptionIds | no | CSV, max 200 |
includeFailedOperations | no | Default true; only false turns it off |
Errors
- 400
Please provide both startTimestamp and endTimestamp query parameters - 400Time-window errors
- 400
resourceIds must list at least one resource ID - 400
resourceIds must list at most 200 values - 400
subscriptionIds must list at least one subscription ID - 400
subscriptionIds must list at most 200 values - 500
Failed to retrieve activity logs in time window
Response: { operations[], timeWindow, totalCount, includeFailedOperations, resourceIds, subscriptionIds }. Each operation:
| Field | Meaning |
|---|---|
resourceId, originalResourceId?, resourceName?, resourceType, resourceGroupName, subscriptionId, subscriptionName?, managementGroupId?, managementGroupName?, entityType? | Target |
operationName | E.g. Microsoft.Compute/virtualMachines/write |
operationType | create, update, delete, action, rbac |
operationCategory | Administrative, Security, Policy, ServiceHealth |
status | Started, Accepted, Succeeded, Failed, Active, Resolved, InProgress |
caller, userDisplayName?, sourceIpAddress? | Who |
timestamp, correlationId, operationId | When and IDs |
changeSummary?, keyChanges?[] | keyChanges items: { field, friendlyName, oldValue?, newValue?, changeType: added | removed | modified } |
requestBody?, responseBody? | Raw JSON strings, may be truncated |
roleAssignmentDetails? | RBAC operations only |
subscriptionMoveDetails? | Subscription moves only |
Example
GET /api/getActivityLogsInTimeWindow?startTimestamp=…&endTimestamp=…&subscriptionIds=<guid>&includeFailedOperations=falseGET /api/activity-log-summary
Permission: View Azure Activity Logs
Operation counts per entity for a window. Counts all operations, not only changes.
Parameters
| Name | Required | Notes |
|---|---|---|
startTimestamp, endTimestamp | yes | Time window |
Errors
- 400
Please provide both startTimestamp and endTimestamp query parameters - 400Time-window errors
- 500
Failed to retrieve activity log hierarchy summary
Response: { compactSummaries[], availableFilters: { operationTypes[], users[] }, totalCount }. Each summary:
| Field | Meaning |
|---|---|
entityId, displayName, entityType | The entity |
subscriptionId, subscriptionName, managementGroupId?, managementGroupName?, resourceGroupName?, resourceType? | Location |
totalCount | Operations |
operationTypeCounts | Per operation type |
userCounts | Operations without a known user are not counted here |
combinedCounts | Key operationType|user; either part may be missing |
Example
GET /api/activity-log-summary?startTimestamp=…&endTimestamp=…GET /api/activity-log-details
Permission: View Azure Activity Logs
All operations on one entity in a window. Only operations recorded at that exact level are returned, and all operations are included, not only changes.
Parameters
| Name | Required | Notes |
|---|---|---|
startTimestamp, endTimestamp | yes | Time window |
entityType | yes | subscription, resourceGroup, resource, managementGroup |
| Identifiers | per entityType | For management groups, managementGroupId is the full path /providers/Microsoft.Management/managementGroups/<id>, URL-encoded |
Errors
- 400Time-window errors
- 400
entityType is required - 400
entityType must be one of subscription, resourceGroup, resource, managementGroup - 400
subscriptionId is required for non-managementGroup entityTypes - 400
managementGroupId is required for managementGroup entityType - 400
resourceGroupName is required for resourceGroup entityType - 400
resourceName and resourceGroupName are required for resource entityType - 500
Failed to retrieve activity log details
Response: { operations[], totalCount }, with the same operation fields as getActivityLogsInTimeWindow.
Notes
- Unordered: sort by
timestampyourself.
Example
GET /api/activity-log-details?startTimestamp=…&endTimestamp=…&entityType=resource&subscriptionId=<guid>&resourceGroupName=rg-web&resourceName=app-web01