Skip to main content

Reference: Scans, Inventory & Performance Metrics

Read scan history and the inventory a scan discovered. This is the data behind the Automated Scanning, Resource Explorer, Role Assignments and Performance Metrics pages. Scan ID, entity selector and paging rules are in Conventions.

List the subscriptions you can see

getScanResults?entityTypes=subscription is the quickest way to list every subscription inside your scope.

Identity and Scans

GET /api/whoami

Permission: any signed-in user

Check who you are signed in as and what you can do. Use it as the first call when troubleshooting. No parameters.

Response: { "success": true, "user": { … } }. The user fields:

whoami response fields
FieldMeaning
id, userIdYour Entra object ID
displayNameYour name, or "Unknown User"
permissions[]Your effective permission IDs, e.g. "data.read", "cost.read"
roles[]Always empty; use permissions
scopeContextThe scope applied to your calls: { mode: "all" | "include", allowedSubscriptionIds?, allowedManagementGroupIds? }
roleBasedScopeContextYour admin-granted scope; the same as scopeContext for API calls
accessChannel"external" for API tokens
externalClientIdThe trusted client you called from
externalApiAccessWhether any of your grants carries the External API access flag
grantingSources[]{ type: "direct" | "group", groupId?, groupName? }: which grants give you access
createdAtTime of this request (not account creation)

Errors

  • 500Failed to retrieve user information.

Example

GET /api/whoami

GET /api/getAllScans

Permission: View Scans

List finished scans, newest first. No parameters. The response is a JSON array, not paged and not scope-narrowed. In-progress scans are excluded.

Each item

getAllScans item fields
FieldMeaning
scanId (= id)Scan ID
scanTimestampStart time
statusCompleted, Failed, CompletedWithNoResults, Cancelled
statusMessageFinal status text
completedTimestampFinish time (may be absent on failed or cancelled scans)
totalResourcesResources found
warningCount, hasErrorWarningsWarning summary; details via getScanWarnings
entitySummary{ managementGroups, subscriptions, resourceGroups, resources, total } (may be absent on old scans)
activityLogBackfillStatus, activityLogBackfillMgStatus, costBackfillStatus, resourceGraphBackfillStatusHistorical-data backfill status, e.g. "pending"; absent when none

Errors

  • 500Failed to retrieve scan list.

Example

GET /api/getAllScans

GET /api/getScanStatus

Permission: View Scans

Status and progress of one scan, including a running one.

Parameters

getScanStatus parameters
NameRequiredNotes
scanIdyesScan ID

Errors

  • 400Missing required parameter: scanId
  • 500Failed to retrieve scan status.(also for an unknown scan)

Response

getScanStatus response fields
FieldMeaning
scanId, statusstatus is InProgress, Completed, Failed, Cancelled or CompletedWithNoResults
statusMessageStatus text
scanTimestamp, completedTimestampcompletedTimestamp is null while running
totalResourcesResources found
triggeredBymanual, scheduled, unknown
lastUpdatedLast status update
errorError detail or null
progressRaw progress record (free-form)
standardizedProgressNull when finished. While running: { overall: { phaseIndex, totalPhases, percentComplete }, currentPhase: { name, displayName, startTime, status, progress: { primary: { current, total, label }, secondary, context } }, metadata }
isRemoteScanTrue when the scan runs in another container (simplified progress)
pendingBackfills{ activityLog, cost, resourceGraph } booleans; present only when one is pending

Example

GET /api/getScanStatus?scanId=scan-2026-10-14T02%3A00%3A00.000Z

GET /api/getScanWarnings

Permission: View Scans

The warnings a scan recorded, such as missing access or failed collectors. Not scope-narrowed. The response is a JSON array (possibly empty).

Parameters

getScanWarnings parameters
NameRequiredNotes
scanIdyesScan ID

Errors

  • 400Missing required parameter: scanId
  • 404Scan not found: <scanId>
  • 500Failed to retrieve scan warnings.

Each item

getScanWarnings item fields
FieldMeaning
typeWarning kind, e.g. resource_access_limited, arg_query_failure, defender_collection_failure, cost_collection_failures, principal_resolution_failed, policy_collection_failure, cve_catalog_sync_failure (about 20 values)
severityinfo, warning, error (optional)
detailsWhat went wrong
timestampWhen
resourceId, subscriptionIdWhat caused it (optional)
countErrors folded into this warning (optional)
errorCodeE.g. an HTTP status code (optional)
contextExtra detail (optional)

Example

GET /api/getScanWarnings?scanId=…

Inventory

getScanResults repeats the manifest on every page

The full scan manifest is sent with every page. Read it once.

GET /api/getScanResults

Permission: View Resources

The inventory discovered by a scan (management groups, subscriptions, resource groups, resources), paged.

Parameters

getScanResults parameters
NameRequiredValuesDefaultNotes
scanIdnoscan IDlatest completed scanPin it when paging. If omitted, each page re-resolves "latest"
entityTypesnoJSON array or CSV of managementGroup, subscription, resourceGroup, resourceallUnknown values just match nothing
loadPropertiesnotrueoffAdds each item's full Azure properties object
includeCostDatanotrueoffAdds costData to resource items
pageSizeno1-1000100 for API callers
continuationTokennotoken from the previous pageSend exactly as returned (URL-encoded)
viewModenoany stringEchoed back only

Errors

  • 400'entityTypes' must be a JSON array of non-empty strings or a comma-separated list.
  • 400'entityTypes' must contain at least one entity type.
  • 400'pageSize' must be an integer between 1 and 1000.
  • 500Failed to retrieve scan results.(unknown scan, no completed scans, or a malformed continuationToken)

Response

getScanResults response fields
FieldMeaning
manifestThe scan's full summary record, sent on every page. Useful fields: scanId, status, scanTimestamp, completedTimestamp, totalResources, entitySummary, tenantId, triggeredBy, statusMessage, warnings[], changeSummary (added/deleted/modified counts vs. the previous scan). Many more internal fields; ignore them
resources[]One item per entity (below)
resourceCountItems in this page
loadedPropertiesWhether properties was included
pagination{ pageSize, continuationToken?, hasMore }; continuationToken is absent on the last page
viewMetadata{ viewMode, entityTypes } when sent
messagePresent for empty, failed or cancelled scans

resources[] item

getScanResults resources item fields
FieldMeaning
idLower-case ARM ID
name, type, location?, resourceGroup?Identity
subscriptionId, subscriptionName, tenantIdOwning subscription and tenant
tagsObject; {} when none
entityTypemanagementGroup, subscription, resourceGroup, resource
rbacSummary{ hasDirectAssignments, directAssignmentCount, eligibleAssignmentCount? }
rbacAssignments{ collectionStatus: success | failed | insufficient_permissions, directAssignments[], eligibleAssignments[]?, summary, errorDetails? }. Each assignment: { roleDefinitionId, roleDefinitionName, principalId, principalType, principalDisplayName?, scope, roleAssignmentId, createdOn?, updatedOn?, pimAssignmentType?, pimStartDateTime?, pimEndDateTime?, pimMemberType? }
propertiesWith loadProperties=true only
costDataWith includeCostData=true, resources only: { hasData, costSnapshot?, lastUpdated? }

Notes

  • Pages may hold fewer rows than pageSize; keep going while hasMore is true.
  • Child resources (e.g. VM extensions) are not included for completed scans; use getChildResources.
  • Failed or cancelled scans return all partial rows in one response with no paging, and entityTypes is not applied.
  • A user scoped to subscriptions sees no management-group rows.

Example

GET /api/getScanResults?scanId=…&entityTypes=resource&pageSize=500   then append   &continuationToken=<url-encoded token>

GET /api/searchResources

Permission: depends on destination: explorer and performance need View Resources; costExplorer View Costs; defender View Defender Assessments; advisor View Advisor Recommendations; policyCompliance View Policy Data

Find entities by name.

Parameters

searchResources parameters
NameRequiredValuesDefault
queryyesAt least 2 characters; case-insensitive substring of the name
modenocurrent, allcurrent
scanIdnoscan IDlatest completed scan (current mode)
destinationnoexplorer, costExplorer, defender, advisor, policyCompliance, performanceexplorer
entityTypenoall, subscription, resourceGroup, resourceall

Errors

  • 400destination must be one of explorer, costExplorer, defender, advisor, policyCompliance, performance
  • 400entityType must be one of all, subscription, resourceGroup, resource
  • 403You do not have permission to search <destination>.
  • 400Query parameter 'query' is required.
  • 400Query must be at least 2 characters long.
  • 400Mode must be 'current' or 'all'.
  • 500Failed to execute search.(also for an unknown scan)

Response: { results[], totalCount, searchMode, currentScanId?, query }. Each result:

searchResources result fields
FieldMeaning
resourceIdLower-case ARM ID
resourceName, resourceTypeIdentity
subscriptionId, subscriptionNameOwning subscription
resourceGroup"" when not applicable
entityTypeEntity level
mostRecentScanId, mostRecentScanTimestampIn mode=all, the most recent scan holding the entity. In mode=current, mostRecentScanId is the selected scan and the timestamp is the request time. For costExplorer and performance, mostRecentScanId is an empty string, the timestamp is the request time, and existsInCurrentScan is always true
existsInCurrentScanWhether the entity is in the selected scan
latestCostMonthYYYY-MM, costExplorer only

Notes

  • At most 50 results, with no paging; totalCount is the number returned. If you get 50, refine the query.
  • mode=all with explorer can list the same entity more than once (one row per stored version).
  • Results are ordered by level (management group, subscription, resource group, resource), then by name. With mode=all and destination=explorer the second key is most recent scan, newest first.
  • destination=performance ignores mode and scanId; searchMode in the response is always current.
  • destination=costExplorer with mode=current means the entity has cost data for the current calendar month, not that it is in the selected scan; scanId is ignored.

Example

GET /api/searchResources?query=sqlprod&destination=explorer&entityType=resource

GET /api/getEntityDetails

Permission: View Resources (extra insight sections need their own permissions)

Full details of one entity in one scan, with top insights.

Parameters

getEntityDetails parameters
NameRequiredNotes
scanIdyes
entityIdyesFull ARM ID, any case
entityTypenomanagementGroup, subscription, resourceGroup, resource. Send entityType=managementGroup for management groups if your scope is restricted, or you get a 404

Errors

  • 400Please provide both 'scanId' and 'entityId' query parameters.
  • 400entityType must be one of: 'managementGroup', 'subscription', 'resourceGroup', 'resource'.
  • 404Entity with ID '<id>' not found in scan '<scanId>'.(also out of scope)
  • 500An error occurred while fetching entity details: Scan not found: <scanId>(unknown scan)

Response: { entity, entityType }. The entity fields:

getEntityDetails entity fields
FieldMeaning
id, name, type, location?, resourceGroup?Identity
subscriptionId, subscriptionName, tenantIdOwning subscription and tenant
tags, entityType, propertiesTags, level, full Azure properties
rbacSummary, rbacAssignmentsAs in getScanResults
_metadata{ firstScanTimestamp, lastScanTimestamp, firstScanSequence, lastScanSequence }: when this version of the entity first and last appeared
defenderInsights?With Defender permission: top 5 unhealthy assessments
advisorInsights?With Advisor permission: top 5 recommendations
costInsights?With Cost permission: { hasData, costSnapshot: { monthToDateCost, averageDailyCost, previousMonthCost }, recentDailyCosts?: [{ date, cost }], lastUpdated, currency? }
policyAssignmentsInsights?, policyComplianceInsights?With Policy permission: top 5 each

Notes

  • An insight section is absent when there is no data, or when it could not be loaded.
  • Management groups never get insight sections (defenderInsights, advisorInsights, costInsights, policy insights), whatever permissions the caller holds.

Example

GET /api/getEntityDetails?scanId=…&entityType=resource&entityId=%2Fsubscriptions%2F<sub>%2FresourceGroups%2Frg-app%2Fproviders%2FMicrosoft.Web%2Fsites%2Fapp1

GET /api/getEntityHistory

Permission: View Resources

One entity's state across every completed scan. A heavy call: one full copy of the entity per scan, with no paging.

Parameters

getEntityHistory parameters
NameRequiredNotes
entityIdyesFull ARM ID
entityTypenoSame values and management-group note as getEntityDetails

Errors

  • 400Please provide an 'entityId' query parameter.
  • 400entityType message as in getEntityDetails
  • 404This resource has not been discovered by any scans yet. …(also out of scope)
  • 500Failed to retrieve entity history: <detail>

Response: { entityId, entityType, totalScansWithEntity, historyLength, history[] }. history[] is oldest first; each entry:

getEntityHistory history entry fields
FieldMeaning
scanId, scanTimestampThe scan
entityProcessedTimestampNull on deleted entries
statuscreated, present, deleted
entityTypeLevel
entityNull when deleted; otherwise { id, name, type, location, resourceGroup, subscriptionId, subscriptionName, tenantId, tags, entityType, rbacAssignments, properties }
hasChildChanges?Whether child resources changed

Notes

  • present does not mean "unchanged" or "changed". Compare consecutive entries yourself.
  • A gap between appearances inserts a deleted entry, and the next appearance is created.

Example

GET /api/getEntityHistory?entityType=resource&entityId=…

GET /api/getChildResources

Permission: View Resources

Child resources of a resource (e.g. VM extensions), optionally compared with an older scan.

Parameters

getChildResources parameters
NameRequiredNotes
parentEntityIdyesARM ID
scanIdyes
olderScanIdnoTurns on comparison

Errors

  • 400Please provide both 'parentEntityId' and 'scanId' query parameters.
  • 500Scan not found: <id>

Response: { children[], hasChildrenWithChanges }. Each child:

getChildResources child fields
FieldMeaning
idInternal record ID, not the ARM ID
entityIdLower-case ARM ID
name, type, location?, properties, tags?The child
changeStatusComparison mode only: added, modified, deleted, unchanged
diffTreeOnly when modified: a nested before/after tree of property changes

Notes

  • An out-of-scope parent returns 200 with an empty list.
  • Children are sorted by name in comparison mode only.
  • The child diff does not apply ignore rules.

Example

GET /api/getChildResources?scanId=…&olderScanId=…&parentEntityId=%2Fsubscriptions%2F…%2Fvirtualmachines%2Fvm1

Role Assignments

Three terms these routes use:

Inherited
Received through Entra group membership. It does not mean inherited down the scope tree.
Role category
Derived from the role name. critical: contains "owner", "user access administrator" or "administrator". management: contains "contributor", "manager" or "operator". read: contains "reader", "viewer" or "monitoring". Otherwise other.
PIM status
permanent, active (activated through PIM), eligible.

Known limitation

These routes drop rows inherited through an Entra group when that group's membership lookup fails. The failure is logged server-side only.

GET /api/role-assignments-summary

Permission: View Resources

Role assignments per principal (user, group, service principal) in a scan.

Parameters

role-assignments-summary parameters
NameRequiredNotes
scanIdyes

Errors

  • 400scanId is required
  • 500Failed to retrieve role assignments summary(also for an unknown scan)

Response: { compactSummaries[], availableFilters, totalCount }. availableFilters is { principalTypes[], roleCategories[], scopeTypes[], roleNames[] }; totalCount is the total number of assignments, not principals. Each summary:

role-assignments-summary summary fields
FieldMeaning
principalId, principalDisplayName, principalTypeUser, Group, ServicePrincipal
totalAssignmentsDirect + inherited
criticalRoleCount, managementRoleCount, readRoleCount, otherRoleCountCounts per role category
roleCategoryCounts, scopeTypeCountsDictionaries
directAssignmentCount, inheritedAssignmentCountCounts per source
combinedCountsKey category|scopeType
sourceAwareCombinedCountsKey source|pimStatus|category|scopeType|roleName. The role name is last and may itself contain |

Example

GET /api/role-assignments-summary?scanId=…

GET /api/role-assignments-details

Permission: View Resources

Every assignment for one principal, with filters. Filters are encoded lists.

Parameters

role-assignments-details parameters
NameRequiredValues
scanIdyes
principalIdyesExact match
roleCategoryFilternoEncoded list of critical, management, read, other
scopeTypeFilternoEncoded list of managementGroup, subscription, resourceGroup, resource
assignmentSourceFilternoEncoded list of direct, inherited
pimStatusFilternoEncoded list of permanent, eligible, active
roleNameFilternoEncoded list of exact role names (encode twice)

Errors

  • 400scanId is required
  • 400principalId is required
  • 400<name> values must be one of <values>
  • 400<name> contains a value that is not valid percent-encoding
  • 400<name> must list at most 200 values
  • 500Failed to retrieve role assignments details

Response: { assignments[], totalCount }. An unknown principal returns an empty list. Each assignment:

role-assignments-details assignment fields
FieldMeaning
roleDefinitionName, roleDefinitionId, roleCategoryThe role
scopeARM scope path; use this, not entityId
entityIdInternal record ID of the scope entity
entityName, entityTypeScope entity name and level
subscriptionId?, subscriptionName?, resourceGroup?Location of the scope
createdOn, updatedOn?Dates
roleAssignmentIdAssignment ID
assignmentSourcedirect, inherited
grantedViaGroupId?, grantedViaGroupName?On inherited rows
pimStatus, pimAssignmentType? (Activated | Assigned), pimStartDateTime?, pimEndDateTime?, pimMemberType?PIM details

Example

GET /api/role-assignments-details?scanId=…&principalId=<guid>&roleCategoryFilter=critical,management&pimStatusFilter=eligible

Performance Metrics

GET /api/performance-metrics-summary

Permission: View Resources

Which resources have performance metrics, and which metrics. No parameters. No metric values are included; use the details route for values.

Response: { compactSummaries[], availableMetrics[], availableResourceTypes[] }. Each summary:

performance-metrics-summary summary fields
FieldMeaning
entityId, displayName, entityTypeLower-case resource ID, name, always resource
subscriptionId, subscriptionName, resourceGroupName, resourceTypeLocation and type
location?, tags?Optional
totalMetricDays, totalMetricHoursHow much data exists
collectionWindow{ daily: { startDate, endDate, totalDays, collectionTimestamp }, hourly?: { … } }
availableMetrics[]Metric names collected for this resource

Errors

  • 500Failed to retrieve performance metrics summary

Example

GET /api/performance-metrics-summary

GET /api/performance-metrics-details

Permission: View Resources

All collected metric values for one resource. The payload can be large.

Parameters

performance-metrics-details parameters
NameRequiredNotes
subscriptionIdyesMust match exactly as returned by the summary
resourceGroupNameyes
resourceNameyes

Errors

  • 400subscriptionId, resourceGroupName, and resourceName are required
  • 404No performance metrics found for specified resource(also when the subscription is out of scope)
  • 500Failed to retrieve performance metrics details

Response: { resource, skuMemoryBytes, vmSize }.

performance-metrics-details response fields
FieldMeaning
resource.resourceId, originalResourceId, resourceName, resourceType, resourceGroupName, subscriptionId, subscriptionNameIdentity
resource.collectionWindowAs in the summary
resource.dailyMetrics[]About 365 days: { date, metrics: { <metricName>: { average?, maximum?, minimum?, total? } } }
resource.hourlyMetrics?[]About 30 days: { timestamp, metrics }
skuMemoryBytes, vmSizeVMs and scale sets only (memory per instance); otherwise null

Example

GET /api/performance-metrics-details?subscriptionId=<guid>&resourceGroupName=rg-prod&resourceName=vm-web-01

Was this page helpful?