top of page
Search

Stop Guessing: How to Actually Identify Your Azure Billing Structure

  • Writer: Shannon
    Shannon
  • Jan 30
  • 9 min read

Note, the companion code and corresponding full GitHub repository is located here.


Azure costs are tricky enough without licensing contracts adding another layer of confusion on top. One of my long-running jokes from my time working at Microsoft was that you needed an advanced degree just to understand Azure billing, and then a second one to understand how that billing intersects with real-world consumption in Azure. What tends to catch teams off guard is that the agreement your organization has in place with Microsoft directly affects how you view costs, how you report costs, what scopes your dashboards should use, and how commitments are measured over time.


Ask a room full of engineers, architects, and finance partners what agreement they are under and you will usually hear answers like EA, MACC, CSP, or Pay As You Go. None of those answers are entirely wrong, but most of them are answering different questions. That overlap is exactly how teams end up with dashboards that look right but don't reconcile, renewal forecasts that drift, and Finance is usually left wondering why the numbers seem to change depending on which portal view someone is using.


This post is about ending the guessing because guessing is leading to more confusion. I'll level set the language, explain where each of these terms actually lives, then prove what you have using Azure CLI and PowerShell. From there, we'll turn that understanding into something operational so FinOps stops being a debate and starts acting as a system.


Before We Touch Any Scripts: Level Setting the Language

The most important thing to understand about Azure billing is that these terms don't all live at the same layer. Azure billing has an agreement layer, a commitment layer, and a subscription offer layer. Most confusion comes from casually using words from all three layers as if they were interchangeable (they're not interchangeable).


Here's how it breaks down:

  • Agreements define the legal and commercial contract you have with Microsoft.

  • Commitments define whether you've promised to spend a certain amount of money over time and how Microsoft tracks that promise.

  • Subscription offers define how individual subscriptions are created, priced, and sometimes credited.


Once you separate those layers mentally, everything else in this post becomes much easier to follow.


Enterprise Agreement (EA)

An Enterprise Agreement is the traditional enterprise contract model that many organizations have been running for years. If your company adopted Azure early or entered through a large Microsoft enterprise deal, there's a good chance at least part of your environment still sits under an EA. From a billing perspective, EA introduces enrollments and enrollment accounts, and those concepts show up directly when you scope Cost Management queries or exports.


What trips teams up is that EA often becomes shorthand for everything related to Azure billing. In reality, EA only answers one question: what agreement type does this billing account use? It doesn't automatically tell you whether you have a consumption commitment, how Marketplace purchases behave, or how newer subscriptions are billed.


It's also increasingly rare to see environments that are purely EA. Many organizations have older subscriptions under EA and newer subscriptions created under a different agreement. That mixed state is often the root cause of inconsistent reporting.


Microsoft Customer Agreement (MCA)

The Microsoft Customer Agreement is the modern contract Microsoft uses for most new Azure customers. If you're buying Azure directly from Microsoft today, there's a very strong chance you're under MCA. This agreement introduces billing accounts, billing profiles, and invoice groupings that differ from the EA model.


MCA matters because it's the foundation for modern Azure billing constructs. If you have a Microsoft Azure Consumption Commitment, it exists because you're under an MCA. When you query a billing account and see the agreement type returned as MicrosoftCustomerAgreement, that tells you which billing hierarchy and APIs apply, regardless of how your subscriptions were created or named.


This is also where people get surprised. Pay As You Go subscriptions, Visual Studio Enterprise subscriptions, and many CSP scenarios ultimately roll up to MCA billing constructs. The subscription label doesn't change the agreement underneath it.


Microsoft Azure Consumption Commitment (MACC)

MACC is the term that causes the most confusion, largely because it's talked about as if it were an agreement or a subscription type. It's neither.


A Microsoft Azure Consumption Commitment is exactly what it sounds like: a promise to consume a certain dollar amount of Azure services over a defined period of time, usually one to three years. It lives at the billing account or billing profile level, not at the subscription level. MACC doesn't change pricing by itself. Discounts still come from negotiated rates, Reserved Instances, and Savings Plans. MACC simply tracks how quickly you're burning down a committed spend.


This distinction matters because MACC burn down doesn't always behave the way people expect. Credits, Azure prepayment, and certain Marketplace purchases can all affect what decrements the commitment. When someone says "the numbers don't match," MACC behavior is often the reason.


PAYG, CSP, and Subscription Offers

Pay As You Go (PAYG) is not an agreement. It's a subscription offer. PAYG subscriptions are billed monthly based on usage and typically sit under an MCA billing account. An organization can have PAYG subscriptions and still have a MACC at the billing account level. Treating PAYG as synonymous with "no commitments exist" is a very common mistake.


CSP is also not an agreement. CSP describes the commercial channel through which you buy Azure. Under the hood, CSP subscriptions often still rely on MCA billing constructs, but billing scopes, permissions, invoicing, and Marketplace eligibility vary by partner. This is why two CSP customers can have completely different FinOps experiences even though both say "we are CSP."


Visual Studio Enterprise, DevTest, sponsorships, and trial subscriptions all live at the subscription offer layer. These offers affect pricing or credits, but they don't change what agreement you're under or whether a commitment exists. Visual Studio credits are a classic example where usage exists but MACC burn down doesn't move, which is confusing until you understand the layering.


Why You Should Figure This Out Before Building Dashboards

If you don't know what agreement you're under, you don't know which billing scopes to use for exports and queries. If you don't know whether a MACC exists, you can build a beautiful burn down chart that is fundamentally meaningless. If you don't detect CSP correctly, Marketplace assumptions tend to sneak in and reporting becomes "mostly right," which is the worst kind of wrong.


Clarity at this layer is what makes everything downstream stable.


Step 1: Make Sure You Have the Right Billing Role

Before running any scripts represented in this blog, you need permissions at the billing account scope. Subscription Owner or Contributor is usually not enough because billing access is separate from resource access. A good baseline is Billing Account Reader on the billing account.


If your scripts return nothing or fail without a clear error, permissions are the first thing to check.


Step 2: Identify Agreement Type Using Azure CLI or PowerShell

Rather than guessing, start with the agreement layer and let Azure tell you the truth.


Azure CLI

az billing account list \
  --query "[].{BillingAccount:name, Agreement:agreementType, DisplayName:displayName}" \
  -o table

PowerShell

$accounts = az rest `
  --method get `
  --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts?api-version=2024-04-01" `
  | ConvertFrom-Json

$accounts.value | Select-Object name, `
  @{Name="AgreementType";Expression={$_.properties.agreementType}}, `
  @{Name="DisplayName";Expression={$_.properties.displayName}} | 
  Format-Table -AutoSize

If the agreement type is EnterpriseAgreement, you're under EA. If it's MicrosoftCustomerAgreement, you're under MCA.


Step 3: Check Whether a MACC Exists

Next, confirm whether a consumption commitment is actually being tracked.


Azure CLI

# Replace <billingAccountId> with your actual billing account ID
az rest \
  --method get \
  --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/<billingAccountId>/providers/Microsoft.Consumption/lots?api-version=2024-08-01" \
  --query "value[].{ID:name, Source:properties.source, Amount:properties.originalAmount.value, Currency:properties.originalAmount.currency, Status:properties.status}" \
  -o table

PowerShell

$billingAccountId = "<your-billing-account-id>"

$lots = az rest `
  --method get `
  --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$billingAccountId/providers/Microsoft.Consumption/lots?api-version=2024-08-01" `
  2>$null | ConvertFrom-Json

if ($lots.value -and $lots.value.Count -gt 0) {
    Write-Host "MACC detected!" -ForegroundColor Green
    $lots.value | Select-Object `
        @{Name="ID";Expression={$_.name}}, `
        @{Name="Source";Expression={$_.properties.source}}, `
        @{Name="Amount";Expression={$_.properties.originalAmount.value}}, `
        @{Name="Currency";Expression={$_.properties.originalAmount.currency}}, `
        @{Name="Status";Expression={$_.properties.status}} |
        Format-Table -AutoSize
} else {
    Write-Host "No MACC found" -ForegroundColor Yellow
}

If lots are returned with balances and dates, MACC exists. The source property will typically show ConsumptionCommitment.


Step 4: Start From a Subscription When That's All You Have

Most engineers start with a subscription ID. You can trace that back to billing.


Azure CLI

subscriptionId="<your-subscription-id>"

az rest \
  --method get \
  --url "https://management.azure.com/subscriptions/$subscriptionId?api-version=2020-01-01" \
  --query "{SubscriptionId:id, BillingScopeId:subscriptionPolicies.billingScopeId, Offer:subscriptionPolicies.quotaId}" \
  -o json

PowerShell

$subscriptionId = "<your-subscription-id>"

$sub = az rest `
  --method get `
  --url "https://management.azure.com/subscriptions/$subscriptionId?api-version=2020-01-01" `
  | ConvertFrom-Json

[PSCustomObject]@{
    SubscriptionId   = $sub.id
    SubscriptionName = $sub.displayName
    BillingScopeId   = $sub.subscriptionPolicies.billingScopeId
    OfferType        = $sub.subscriptionPolicies.quotaId
} | Format-List

The billingScopeId string tells you whether the subscription rolls up to an EA enrollment, an MCA billing profile, or a CSP customer. Here's what to look for:


  • EA: Contains /providers/Microsoft.Billing/billingAccounts/{enrollmentId}/enrollmentAccounts/{accountId}

  • MCA Direct: Contains /providers/Microsoft.Billing/billingAccounts/{accountId}/billingProfiles/{profileId}/invoiceSections/{sectionId}

  • CSP: Contains /customers/ in the scope path


Step 5: Detect CSP Explicitly

CSP doesn't have a single flag. You infer it by checking if the billing account has customers beneath it.


Azure CLI

billingAccountId="<your-billing-account-id>"

az rest \
  --method get \
  --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$billingAccountId/customers?api-version=2024-04-01" \
  --query "value[].{CustomerName:properties.displayName, CustomerId:name}" \
  -o table

PowerShell

$billingAccountId = "<your-billing-account-id>"

$customers = az rest `
  --method get `
  --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$billingAccountId/customers?api-version=2024-04-01" `
  2>$null | ConvertFrom-Json

if ($customers.value -and $customers.value.Count -gt 0) {
    Write-Host "CSP detected - this billing account has customers" -ForegroundColor Cyan
    $customers.value | Select-Object `
        @{Name="CustomerName";Expression={$_.properties.displayName}}, `
        @{Name="CustomerId";Expression={$_.name}} |
        Format-Table -AutoSize
} else {
    Write-Host "No CSP customers found" -ForegroundColor Yellow
}

If customers exist, CSP is involved. In a CSP model, each customer represents a separate entity that the partner manages.


Step 6: One Script to Classify Everything

At this point in the post, you have all the building blocks. You can list billing accounts, check agreement type, look for consumption commitment lots, and trace a subscription back to its billing scope. The problem is that doing those steps manually is fine for one subscription, but it gets old fast when you have dozens or hundreds. This is the point where people quietly give up and go back to assumptions.


So here's the practical version. One script. Run it once. It walks every subscription you can see, pulls the billing scope, infers whether it looks like CSP, maps the subscription back to its billing account, records the billing account's agreement type, and checks whether that billing account has consumption commitment lots. The output is a clean table, and it also exports a CSV so you can feed Power BI or hand it to Finance without having to explain what you did.



Understanding the Output

The "One Script to Classify Everything" script produces a CSV with the following columns:

Column

Description

SubscriptionName

The display name of the subscription

SubscriptionId

The subscription GUID

OfferType

The subscription offer (e.g., MS-AZR-0017P for PAYG, MS-AZR-0148P for Enterprise)

AgreementType

Either EnterpriseAgreement or MicrosoftCustomerAgreement

IsCSP

Boolean indicating if CSP indicators were detected

CSPEvidence

Details of why CSP was detected (if applicable)

HasMACC

Boolean indicating if consumption commitment lots exist

BillingAccountId

The billing account ID this subscription rolls up to

BillingScopeId

The full billing scope path

Common Patterns You'll See


After running the script, you'll typically see a few patterns emerge:


Pattern 1: Pure EA Environment

  • All subscriptions show EnterpriseAgreement

  • No CSP indicators

  • MACC is false (EA uses monetary commitment, not MACC)

  • Billing scopes contain /enrollmentAccounts/


Pattern 2: Modern MCA Environment

  • All subscriptions show MicrosoftCustomerAgreement

  • No CSP indicators

  • MACC may be true or false depending on your contract

  • Billing scopes contain /billingProfiles/ and /invoiceSections/


Pattern 3: CSP Environment

  • Agreement type shows MicrosoftCustomerAgreement

  • CSP is true

  • Billing scopes contain /customers/

  • Multiple customer IDs may be present


Pattern 4: Hybrid Environment (Most Common)

  • Mix of EnterpriseAgreement and MicrosoftCustomerAgreement

  • Some subscriptions may show CSP indicators

  • MACC detection varies by billing account

  • This is where reporting gets complicated without proper classification


What to Do With This Information

Once you know your billing structure, you can:


  1. Scope Cost Management queries correctly - Use enrollment accounts for EA, billing profiles for MCA

  2. Build accurate MACC burn-down dashboards - Only include subscriptions that actually decrement MACC

  3. Set up proper RBAC - Billing permissions work differently under EA vs MCA

  4. Configure exports appropriately - Export scopes differ based on agreement type

  5. Forecast renewals accurately - Understand what commitments exist and when they expire

  6. Troubleshoot billing anomalies - Know which portal and API to use for each subscription


Troubleshooting Common Issues


Issue: Script returns empty results

Solution: Check your permissions. You need at least Billing Account Reader role at the billing account scope, not just at the subscription level.


Issue: Some subscriptions show no billing account

Solution: This typically happens with trial subscriptions, sponsored subscriptions, or subscriptions that were created but not fully provisioned. These won't roll up to standard billing constructs.


Issue: CSP is detected but you don't think you're in CSP

Solution: You might be in an indirect CSP relationship. Check with your procurement team. Sometimes organizations buy through a CSP partner without the engineering team knowing.


Issue: MACC shows false but Finance says you have one

Solution: The commitment might be tracked outside of Azure (e.g., at the enterprise agreement level for EA customers). MACC specifically refers to MCA consumption commitments tracked via the lots API.


Closing Thoughts

EA and MCA are agreements. MACC is a commitment. PAYG, CSP, Visual Studio Enterprise, and DevTest are subscription level constructs layered on top. They're not competing labels or concepts. They're different parts of the same billing system, and Azure only becomes confusing when those layers get blurred together.


The moment you stop guessing and start proving, Azure billing stops being a procurement mystery and becomes a mechanical system you can automate. That's when dashboards reconcile, forecasts stabilize, and Finance + engineering finally start looking at the same reality.


If nothing else, take this with you: Assumptions are expensive. Scripts are cheap.


Additional Resources


Feedback and Contributions

Found this helpful? Have improvements? The scripts in this post are living documents on my GitHub page, with the repository located here (and referenced above). As Azure billing APIs evolve, so should these detection methods. If you find edge cases or improvements, I'd love to hear about them.

1 Comment


Cathy Harrington
Cathy Harrington
Feb 13

I read the post and it clearly explains how to break down your Azure billing so you stop guessing what costs come from where and make smarter budget decisions. When I was struggling with my own tech classes I once had to pay someone to complete sophia course work because I could not figure out complex cloud concepts on my own. That made me see that learning the basics first really helps with advanced topics.


Like

© 2020 Shannon B. Eldridge-Kuehn

  • LinkedIn
  • Twitter
bottom of page