Skip to main content

Reference: Reports

The same data as StratoLens Reports, as JSON. Every route is under /api/reporting-vnext/ and takes the shared filters below. Security and change reports need View Resources; cost reports need View Costs.

Shared Parameters

All filters are optional and combined with AND. URL-encode each value once, and always encode + as %2B.

Filters

Shared report filter parameters
ParameterFormatRules
filterScopesJSON array of { "type": "managementGroup" | "subscription" | "resourceGroup", "id": "…" }id is the management group ID (includes everything below it), the subscription GUID, or "<subscriptionGuid>/<rgName>" for a resource group. Several scopes are ORed. An unknown or out-of-scope ID gives an empty report, not an error
filterTypesJSON array of ARM typesCase-insensitive, e.g. "microsoft.compute/virtualmachines"
filterLocationsJSON array of regionsCase-sensitive, e.g. "eastus"
filterNamePlain stringCase-insensitive substring of the resource name
filterTagsJSON array of { "id": "<any>", "key": "<tag>", "value": "<v>", "operator": "equals" | "exists" | "missing" }Same shape as Cost Explorer tagFilters
filterTagModeand | orDefault and
  • Invalid elements are dropped without an error. A dimension with nothing valid left is ignored.
  • Once a type, location, name or tag filter is active, rows not tied to a specific resource (subscription-level charges or changes) are excluded.
  • Non-scope filters, and a filterScopes entry of type resourceGroup, make cost and change reports compute live: same numbers, slower. spend-accountability also computes live for any date range that is not one full calendar month or the current month to date.

Other parameters

Other shared report parameters
ParameterRules
windowDaysgovernance-audit allows 30, 60, 90. access-drift, security-config-drift and infrastructure-change allow 7, 30, 60, 90. Any other value is treated as 30
splitTagKeyA tag key to break costs down by. __none__ or an empty value means no split; with no split there is one "All resources" bucket. Resources missing the tag go to an "Unallocated" bucket. Defaults when omitted: spend-accountability uses the first tag key; governance-audit uses the configured budget tag; forecast and trend-variance use no split

Errors and caps

  • The only 400s in this group are spend-accountability's date errors. Each route's 500 message is listed with it.
  • Lists marked "(cap N)" return at most N items. Most have a sibling …Total field with the full count; the exceptions are noted per route. KPIs always use the full set.

Security and Access Reports

GET /api/reporting-vnext/public-exposure

Permission: View Resources

Resources reachable from the internet, by category and severity. Takes the filters.

Response

public-exposure response fields
FieldMeaning
generatedAtWhen
scanId, scanTimestamp, priorScanId, priorScanTimestampScans used
deltaAvailable, hasDataFlags
kpis{ totalExposed, bySeverity { critical, high, medium }, publicEndpoints, exposedDataStores, wideOpenRules, newSinceLastScan }
categorySummary[]All 6 categories: publicIp, nsgOpenRule, storagePublic, sqlPublic, keyVaultPublic, appServicePublic
resources[] (cap 300), resourcesTotalEach row: { resourceId, name, resourceType, category, reason, severity, subscriptionId?, subscriptionName?, resourceGroup?, location?, detail?, isNew }. Severities: critical, high, medium
notes[]Caveats

Notes

  • resources rows are findings, so one NSG can appear once per open rule. kpis.totalExposed counts distinct resources.
  • isNew is computed against the unfiltered prior scan, so a resource that only entered the current filter since the last scan is not marked new.

Errors

  • 500Failed to retrieve public exposure report

Example

GET /api/reporting-vnext/public-exposure

GET /api/reporting-vnext/privileged-access

Permission: View Resources

Standing (permanent) privileged assignments. PIM-activated ones are excluded and counted separately. Of the filters, only filterScopes applies.

Response

privileged-access response fields
FieldMeaning
generatedAt, scanId, scanTimestamp, hasDataContext
kpis{ privilegedIdentities, userCount, groupCount, servicePrincipalCount, criticalIdentities, managementGroupScopeAssignments, subscriptionScopeAssignments, totalPrivilegedAssignments, oldestStandingDays?, pimManagedActiveExcluded }
scopeTypeBreakdown[]4 rows
principals[] (cap 200), servicePrincipals[] (cap 100)Each with a …Total
notes[]Caveats

Principal row

privileged-access principal row fields
FieldMeaning
principalId, principalDisplayName, principalTypeWho
highestCategorycritical | management
topRoleNameThe most privileged role, for example Owner
criticalCount, managementCountCounts
Per-level scope countsAssignments per scope level
scopes[] (cap 40){ scopeType, entityId, entityName, roleName, roleCategory, createdOn?, subscriptionName? }. No …Total sibling: the four per-level scope counts give the full count
oldestCreatedOn?, standingDays?Age

Notes

  • A filterScopes entry of type resourceGroup also matches assignments granted at the resource group's parent subscription, because that access is inherited by the resource group.

Errors

  • 500Failed to retrieve privileged access report

Example

GET /api/reporting-vnext/privileged-access

GET /api/reporting-vnext/access-drift

Permission: View Resources

Grants and revocations over a window. Compares the latest scan with the latest scan at least windowDays older. Takes scope filters only, and windowDays. Unlike privileged-access, PIM-activated assignments are included.

Response

access-drift response fields
FieldMeaning
generatedAt, scanId, scanTimestamp, windowDaysContext
priorScanId, priorScanTimestampThe older scan
windowTruncatedTrue when no scan was old enough
deltaAvailable, hasDataWith only one scan, deltaAvailable is false
kpis{ newGrants, newCriticalGrants, newlyEmpoweredIdentities, revokedGrants, attributedGrants }
scopeBreakdown[]Per scope level
grants[], revocations[] (cap 200 each, with …Total)Each entry: { changeType: granted | revoked, principalId, principalDisplayName, principalType, roleName, roleCategory, scopeType, scopeName, subscriptionName?, createdOn?, actor?, actorAt? }
notes[]Caveats

Notes

  • A filterScopes entry of type resourceGroup also matches assignments granted at the resource group's parent subscription, because that access is inherited by the resource group.

Errors

  • 500Failed to retrieve access drift report

Example

GET /api/reporting-vnext/access-drift?windowDays=7

GET /api/reporting-vnext/security-config-drift

Permission: View Resources

Changes that weakened a tracked security setting. Takes the filters and windowDays.

Response

security-config-drift response fields
FieldMeaning
generatedAt, windowDays, windowStart, windowEnd, earliestChange, hasDataContext
updatesScannedChanges examined
kpis{ totalDrift, criticalDrift, highDrift, mediumDrift, affectedResources, unattributed }
categorySummary[]publicAccess, networkExposure, transportSecurity, dataProtection
findings[] (cap 100), findingsTotalEach finding: { resourceId, resourceName, resourceType, category, severity, title, setting, beforeValue, afterValue, reason, changeTime, actor?, actorKind, subscriptionName?, resourceGroupName? }
notes[]Caveats

Errors

  • 500Failed to retrieve security config drift report

Example

GET /api/reporting-vnext/security-config-drift?windowDays=60

Change and Waste Reports

GET /api/reporting-vnext/infrastructure-change

Permission: View Resources

Change volume, velocity and change-makers over a window. Takes the filters and windowDays.

Response

infrastructure-change response fields
FieldMeaning
generatedAt, window fields, earliestChange, hasDataContext
kpis{ totalChanges, createCount, updateCount, deleteCount, securityRelevantChanges, securityRelevantDeletions, activeChangeMakers, humanChangeMakers, automationChangeMakers, systemChangeMakers, attributedChanges }
velocity[], velocityGranularity{ start, counts { create, update, delete, total } } per day (windows ≤ 30 days) or per week
actorKindCountsHuman, automation, system
subscriptions[], resourceGroups[] (cap 12 each)Where changes happened
securityCategories[]Security-relevant changes by category
resourceTypes[] (cap 25)What changed
changeMakers[] (cap 15){ actor, actorKind, counts, securityRelevantCount }. Includes synthetic Unknown and Azure system rows for unattributed changes. The activeChangeMakers, humanChangeMakers, automationChangeMakers and systemChangeMakers KPIs count named actors only, so they do not add up to the row count
notes[]Caveats

Errors

  • 500Failed to retrieve infrastructure change report

Example

GET /api/reporting-vnext/infrastructure-change?windowDays=30

GET /api/reporting-vnext/orphan-waste

Permission: View Resources

Orphaned resources and the money they waste. Takes the filters. Unlike orphaned-resource-recommendations, this report excludes items hidden in the UI and metrics-based detections with activity in the last 30 days.

Response

orphan-waste response fields
FieldMeaning
generatedAt, hasData, lastScanId, lastScanTimestampContext
currency, mixedCurrencyCurrency
metricsGateDays, inventoryCount, metricsCountHow detections were gated
kpis{ orphanCount, costedCount, freeCount, totalMonthlyCost, totalAnnualCost, longIdleCount, oldestOrphanDays }
wastage, orphanedOrphans with a cost, and zero-cost orphans. Each holds resources[] (cap 100, with resourcesTotal), byType[] (cap 25, with byTypeTotal), bySubscription[] (cap 12, with bySubscriptionTotal), ageBands[] (lt30, d30to90, d90to180, gte180), count, totalMonthlyCost, totalAnnualCost
Resource row{ resourceName, resourceType, recommendationType, recommendationLabel, status, reason, detectionMethod, monthlyCost, annualCost, currency, orphanedDays, orphanedSince, subscriptionId, subscriptionName, resourceGroupName }
notes[]Caveats

Errors

  • 500Failed to retrieve orphans & waste report

Example

GET /api/reporting-vnext/orphan-waste

Cost Reports

GET /api/reporting-vnext/governance-audit

Permission: View Costs

Change accountability, budget enforcement and audit integrity in one report. Takes the filters, windowDays and splitTagKey.

Response

governance-audit response fields
FieldMeaning
currency?, mixedCurrency, asOfDate, generatedAtContext
windowDays, windowStart, windowEnd, earliestChangeearliestChange later than windowStart means less history than the window
availableTagKeys[]Tag keys you can split by
kpis{ totalChanges, createCount, updateCount, deleteCount, budgetBreachCount, budgetAtRiskCount, namedAccountabilityPercent, netMonthlyCostImpact }
changeActors[] (cap 12){ actor, createCount, updateCount, deleteCount, totalCount, costImpact }. No …Total sibling
changeToCost{ newResourceMonthlyCost, newResourceCount, retiredResourceMonthlyCost, retiredResourceCount, netMonthlyCostImpact, updateCount, costMatchedCount, changedResourceCount, note }
budgetEnforcement{ monthLabel, budgetTagKey, alertThresholdPercent, overCount, atRiskCount, underCount, noBudgetCount, totalBudget, totalProjected, totalVariance, anyBudgetSet, rows[] }. Always covers the current calendar month, regardless of windowDays. Row shape is as in trend-variance
auditIntegrity{ namedAccountabilityPercent, changesWithNamedActor, totalChanges, unattributedChangeCount, auditEntryCount, auditByType[] }

Notes

  • auditEntryCount and auditByType are product audit-log counts for the whole installation, not narrowed by scope. They are null unless the caller also holds View Audit Logs. auditByType counts the newest 2000 entries in the window; auditEntryCount is the full total.

Errors

  • 500Failed to retrieve governance & audit report

Example

GET /api/reporting-vnext/governance-audit?windowDays=90&splitTagKey=CostCenter

GET /api/reporting-vnext/forecast

Permission: View Costs

Spend forecast from a trailing 14-day run rate with seasonality. Takes the filters and splitTagKey.

Response

forecast response fields
FieldMeaning
currency?, mixedCurrency, asOfDate, method, trailingWindowDays, seasonalityApplied, historyMonthsContext
month{ label, monthKey, monthToDate, daysElapsed, daysInMonth, trailingDailyAvg, projectedTotal, projectedLow, projectedHigh, priorMonthActual? }
quarter, year{ label, startDate, endDate, actualToDate, projectedTotal, projectedLow, projectedHigh, monthsRemaining, daysElapsed, daysInPeriod, priorPeriodActual?, series[], breakdown }
rolling{ next30, next90, next365 }
annualizedRunRateYearly run rate
series[]{ date, actual?, forecast?, low?, high? }
breakdown{ splitTagKey, displayName, buckets[]: { value, isUnallocated, monthToDate, projectedTotal } }
splitTagKey, availableTagKeys[]Split in effect, and alternatives

Errors

  • 500Failed to retrieve forecast

Example

GET /api/reporting-vnext/forecast?splitTagKey=BusinessUnit

GET /api/reporting-vnext/trend-variance

Permission: View Costs

Month-over-month trend, budget vs. actual and a cost bridge. Takes the filters and splitTagKey.

Response

trend-variance response fields
FieldMeaning
currency?, mixedCurrency, asOfDateContext
budgetTagKey, alertThresholdPercent, splitTagKey, availableTagKeys[]Configuration in effect
trend{ series[]: { monthKey, label, actual?, projected?, isCurrent }, momPercent?, momLabel?, qoqPercent?, qoqLabel? }: up to 12 months
budgetVsActual{ monthLabel, totalBudget, totalActualMTD, totalProjected, totalVariance, rows[], anyBudgetSet, budgetCoversAllBuckets, filterNarrowsActuals }
Budget row{ value, isUnallocated, budget, hasBudget, actualMTD, projectedMonthEnd, variance, variancePercent, status: over | at-risk | under | no-budget }
bridgeNull, or { fromLabel, toLabel, fromTotal, toTotal, segments[]: { key: start | newResources | retiredResources | skuConfig | usageRate | end, label, amount, runningTotal }, note? }
subscriptionVariance[]{ currency, subscriptions[]: { subscriptionId, subscriptionName, monthlyCosts, monthlyVariancePercent, totalCost }, monthlyTotals, grandTotal }
subscriptionVarianceMonthRange[]Months covered

Errors

  • 500Failed to retrieve trend & variance report

Example

GET /api/reporting-vnext/trend-variance?splitTagKey=__none__

GET /api/reporting-vnext/spend-accountability

Permission: View Costs

Spend broken down by a tag key, with the unallocated share. Takes startDate/endDate (both or neither; default month to date; max 366 days), the filters and splitTagKey.

Errors

  • 400Both startDate and endDate are required.
  • 400Invalid date format. Use YYYY-MM-DD format.
  • 400startDate must not be after endDate
  • 400Invalid calendar date.
  • 400Date range exceeds maximum supported span of 366 days
  • 500Failed to retrieve spend accountability report

Response

spend-accountability response fields
FieldMeaning
periodStart, periodEndThe range used
currency?, mixedCurrencyCurrency
totalCost, totalAmortizedCost, totalResourceCountTotals
breakdown{ splitTagKey, displayName, buckets[], unallocatedCost, unallocatedPercent, allocatedPercent }. Each bucket: { value, isUnallocated, cost, amortizedCost, percentOfTotal, resourceCount, subscriptions[]: { subscriptionId, subscriptionName, cost, amortizedCost } }, highest cost first
splitTagKey, availableTagKeys[], generatedAtSplit in effect, alternatives, and when

Example

GET /api/reporting-vnext/spend-accountability?startDate=2026-09-01&endDate=2026-09-30&splitTagKey=CostCenter

Was this page helpful?