microsoft / microsoft/finops-toolkit
Ability to export Microsoft Azure Consumption Commitment (MACC) data and integrate into the FinOps Hub solution
@MSBrett is already working on this.
Since Jul 3, 2025.
- Dominant language
- PowerShell
- Stars
- 603
- Forks
- 248
- Avg merge
- 7d 11h
- Merged PRs (30d)
- 11
Description
Scenario
Export Microsoft Azure Consumption Commitment (MACC) data to FinOps hubs.
Also ingest Savings Plan benefit recommendations.
This data lets users:
- Track remaining MACC commitment.
- Analyze MACC decrement events.
- Compare MACC-eligible spend with FOCUS cost data.
- Review commitment dates, amounts, balances, and status.
- Review Savings Plan benefit recommendations.
Goal
Adapt the existing Azure Resource Graph app to create a sister Azure REST app.
Reuse the existing query, pipeline, storage, and manifest pattern.
The REST app stays generic.
This iteration supplies three query definitions:
- MACC Lots.
- MACC Events.
- Savings Plan benefit recommendations.
The app supports GET only.
Session setup
Start a fresh session from dev.
Rename its branch once:
MSBrett/issue-1721-azure-rest-ingestion
Do not reuse features/research-custom-resource-graph.
Non-goals
- Do not add quota APIs.
- Do not add capacity APIs.
- Do not discover subscriptions, billing accounts, or other scopes.
- Do not add
POST,PUT,PATCH, orDELETE. - Do not add a provider-specific endpoint registry.
- Do not put API versions in the REST engine.
- Do not add a new orchestration framework.
What this deletes or consolidates
- Remove the old 18-API scope.
- Remove all quota and capacity work from this iteration.
- Remove all scope-discovery work.
- Reuse the existing query dispatcher and ingestion pipeline.
- Reuse the existing ARM linked service and managed identity.
- Reuse the existing Parquet, manifest, monitoring, and failure behavior.
Scope selection
settings.json is the only source for scopes.
The existing file already supports multiple scopes.
The app reads every scopes[].scope value.
This app evaluates the Microsoft.Billing subset:
/providers/Microsoft.Billing/
Each query declares its compatible Azure resource types:
| Dataset | Compatible setting scope types |
|---|---|
| MACC Lots | Microsoft.Billing/billingAccounts |
| MACC Events | Microsoft.Billing/billingAccounts |
| Savings Plan benefit recommendations | Microsoft.Billing/billingAccounts, Microsoft.Billing/billingAccounts/billingProfiles |
The app performs these steps:
- Load
settings.json. - Read every
scopes[].scopevalue. - Validate each scope as an Azure resource ID.
- Select the Microsoft.Billing subset.
- Derive the Azure resource type.
- Run each query for every compatible scope.
The match is not case-sensitive.
The app does not add another scope list.
The app does not infer or discover a scope.
The accepted resource types are query configuration.
The REST engine contains no Microsoft.Billing endpoint rules.
Exact initial API requests
{arm} is the Azure Resource Manager authority for the current cloud.
{scope} is a compatible scope from settings.json.
MACC Lots
GET {arm}{scope}/providers/Microsoft.Consumption/lots?api-version=2026-06-01&$filter=source eq 'ConsumptionCommitment'
- Compatible scope: billing account.
- Items:
value. - Next page:
nextLink.
MACC Events
GET {arm}{scope}/providers/Microsoft.Consumption/events?api-version=2026-06-01&$filter=lotSource eq 'ConsumptionCommitment'
- Compatible scope: billing account.
- Items:
value. - Next page:
nextLink. - Do not send
startDateorendDate.
Savings Plan benefit recommendations
GET {arm}{scope}/providers/Microsoft.CostManagement/benefitRecommendations?api-version=2025-03-01&$filter=properties/lookBackPeriod eq 'Last7Days' AND properties/term eq 'P3Y'&$expand=properties/usage,properties/allRecommendationDetails
- Compatible scopes: billing account and billing profile.
- Items:
value. - Next page:
nextLink. - Lookback period:
Last7Days. - Term:
P3Y. - Recommendation scope:
Shared, by API default.
The API version is query configuration.
The output schema version is a different value.
Call each validated nextLink with GET.
Do not add or replace parameters in a continuation URL.
Existing pattern to reuse
Reuse these existing components:
Microsoft.FinOpsHubs.IngestionQueriesfor query loading and dispatch.Microsoft.FinOpsHubs.AzureResourceGraphas the sister-engine pattern.- The Core ARM REST linked service.
- The existing Parquet sink and manifest flow.
- The existing bounded query execution.
Do not design a new system.
Change only the REST engine behavior and required query contract fields.
Implementation steps
-
Add a sister Azure REST app.
Copy the Azure Resource Graph app structure. -
Add a parameterized REST dataset.
Accept a validated ARM-relative path.
Accept the API version as a separate parameter. -
Extend the existing query contract.
Add the path, version, scope source, compatible resource types, query parameters, item selector, and continuation selector. -
Extend the existing dispatcher.
Load scopes fromsettings.json.
Create one work item for each compatible scope and query. -
Preserve current query behavior.
Existing Azure Resource Graph queries must run without configuration changes. -
Keep bounded parallel work.
Reuse the existing pipeline pattern.
Do not add a queue or scheduler. -
Validate each request before authentication.
Accept onlyGET.
Accept only an ARM-relative path. -
Validate every continuation URL.
Require the current Azure Resource Manager authority.
Never send the managed identity token to another authority. -
Add three query files and three schema translators.
Keep all API-specific values in those files. -
Reuse the current output flow.
Keep API failures as failures. -
Add focused tests.
Test scope selection, request validation, paging, translation, and existing-query behavior. -
Add the required changelog entry.
Link the pull request to this issue.
Security rules
- Treat the setting scope as untrusted.
- Treat the configured path as untrusted.
- Attach authentication only after validation.
- Reject an absolute input URL.
- Reject a scheme-relative input URL.
- Reject user information.
- Reject fragments.
- Reject backslashes.
- Reject a malformed Azure resource ID.
- Validate each continuation URL.
- Require the current Azure Resource Manager authority.
Live test and prototype gate
Use only the user-approved EA billing account for live Azure work.
Supply its identifier through private test configuration.
Do not publish the EA identifier in:
- This issue.
- A pull request.
- Committed files.
- Logs.
- Test evidence.
Before each live run, check the selected scope set.
Stop unless the only selected scope is the user-approved EA.
Do not call, inspect, enumerate, or test an MCA scope.
Do not request MCA permissions.
Do not use a billing profile in a live request.
MCA work requires explicit user approval.
Ask only after the user accepts the EA result.
Until that approval, MCA behavior is unverified.
Local contract tests do not call Azure.
API version status
- Consumption
2024-08-01is the latest version in the merged public specification. - Live provider metadata advertises Consumption
2026-06-01as non-preview. - Azure REST API Specs PR #43855 contains the
2026-06-01contract. - PR #43855 is not merged.
- Query configuration can change the version without an engine change.
Acceptance criteria
- The REST engine contains no Microsoft.Billing endpoint rule.
- The app evaluates all Microsoft.Billing scopes in
settings.json. - Each query runs for every compatible setting scope.
- The app adds no second scope setting.
- The app makes no scope-discovery request.
- The app supports only
GET. - The three query files contain the exact requests shown above.
- API versions come from query configuration.
- The app ingests all pages from
valueandnextLink. - A request cannot leave the Azure Resource Manager authority.
- A failure does not become an empty successful dataset.
- Existing Azure Resource Graph queries work without configuration changes.
- No quota or capacity API is present.
- Live Azure work uses only the privately configured EA.
- No MCA request occurs without explicit approval.
- Public artifacts contain no EA billing-account identifier.
- The pull request contains a changelog entry and links this issue.
Requirements traceability matrix
| ID | Requirement | Plan coverage | Required proof |
|---|---|---|---|
| R1 | Adapt the existing app for REST. | Goal; existing pattern; steps 1 and 10 | App deployment and pipeline tests |
| R2 | Keep the REST app generic. | Scope selection; steps 2, 3, and 9 | Engine contains no provider-specific endpoint |
| R3 | Read all scopes from settings.json. |
Scope selection; step 4 | Tests with multiple setting scopes |
| R4 | Evaluate the Microsoft.Billing subset. | Scope selection | Tests with compatible and incompatible resource types |
| R5 | Support only the three named APIs. | Exact requests; step 9 | Query contract lists exactly three requests |
| R6 | Exclude quota and capacity work. | Non-goals; acceptance criteria | Query contract and repository search |
| R7 | Support GET only. |
Goal; security rules | Method validation tests |
| R8 | Keep API versions in configuration. | API requests; steps 2 and 3 | Version parameter tests |
| R9 | Treat paths and continuations as untrusted. | Steps 7 and 8; security rules | Malicious path and continuation tests |
| R10 | Preserve the current ingestion flow. | Existing pattern; steps 5, 6, and 10 | Azure Resource Graph regression tests |
| R11 | Record the exact initial requests. | Exact initial API requests | Request contract tests |
| R12 | Use the approved EA for live work. | Live test gate | Private scope preflight |
| R13 | Do not touch MCA without approval. | Live test gate | No MCA access in live evidence |
| R14 | Keep the EA identifier private. | Live test gate | Public-artifact scan |
| R15 | Meet repository delivery rules. | Step 12 | Changelog entry and issue link |
References
- Lots: https://learn.microsoft.com/rest/api/consumption/lots/list-by-billing-account?view=rest-consumption-2024-08-01
- Events: https://learn.microsoft.com/rest/api/consumption/events/list-by-billing-account?view=rest-consumption-2024-08-01
- Benefit recommendations: https://learn.microsoft.com/rest/api/cost-management/benefit-recommendations/list?view=rest-cost-management-2025-03-01
- AZCapman benefit recommendation script: https://github.com/microsoft/azcapman/blob/main/scripts/rate/Get-BenefitRecommendations.ps1
- Consumption REST specification: https://github.com/Azure/azure-rest-api-specs/tree/main/specification/consumption/resource-manager/Microsoft.Consumption/Consumption
- Consumption
2026-06-01PR: https://github.com/Azure/azure-rest-api-specs/pull/43855
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.