8 min read

Azure Plans - Azure Consumption APIs and Partner Earned Credits

Azure Plans - Azure Consumption APIs and Partner Earned Credits

To follow up on my previous post where I illustrated how you could go about creating a subscription under an Azure Plan using the REST APIs, I spend a few evenings familiarizing myself with them a bit more.

Up until now the consumption APIs were only of use to Enterprise Enrollments. However, with the Microsoft Customer Agreement and the Azure Plans, Cloud Service Providers (CPSs) can now leverage (almost) the same capabilities. And in some cases you kind of have to.

Billing Accounts

Once you have a customer that has signed the Microsoft Customer Agreement, you can create or transition a current subscription to an Azure Plan. Once this done, you have at least one "Billing Account". From a technical perspective, the billing account is one of the scopes under a Microsoft Customer Agreement. There are multiple scopes , billing account being one of them. In my previous post we used the "Customer" scope to create a subscription. If you're interested, read up on them here.

The billing account is where the magic happens. The account comes with a unique identifier which we call the  "billing account ID"  You can request your Billing account Ids by querying "/providers/Microsoft.Billing/billingAccounts/". You are returned an insanely large GUID. At first this GUID seems to make no sense at all. However, there's some logic to it and it's actually build from two properties, separated by the double colon:

  • accountId
  • organizationId

When querying the API you're often required to provide a scope. Depending on how you set up your query (include or exclude the path of the Resource Provider) this can be either the Billing Account ID or the Billing Account Name. To clarify:

Billing account ID: /providers/Microsoft.Billing/billingAccounts/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_xxxx-xx-xx

Billling account name: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_xxxx-xx-xx

You can find the properties by either browsing to the "Cost Management + Billing" blade within the Azure Portal or querying the API and requesting a list of the Billing Accounts.

Or through the API:

"https://management.azure.com/providers/Microsoft.Billing/billingAccounts?api-version=2019-10-01-preview"

Look for the scope with a displayName of "partner center customer or commerce root ..." this is the one you need. If you request the properties either through the Portal or the API look for the "Account Type" of Partner and you know you're in the right place.

Whatever you're going to do, this is the information you need to get started. We can request the usage details, Azure Reservations, Transactions and much more. More information on the availability of the APIs and their functionality here.

Querying Customer information and Usage Details

As an example, let's start with a list of the customers and then build on that. First we start with the authentication header (as we usually do). Make sure you're logged into Azure PowerShell and run the following code or use it as the start for your script to build. It will structure the authentication header for the requests we will execute and also set the variable for the Billing Account Name for later use.

# Build the authentication header
$azContext = Get-AzContext
$azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
$profileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($azProfile)
$token = $profileClient.AcquireAccessToken($azContext.Subscription.TenantId)
$authHeader = @{
    'Content-Type'='application/json'
    'Authorization'='Bearer ' + $token.AccessToken
}

$restUriBillingAccounts = "https://management.azure.com/providers/Microsoft.Billing/billingAccounts?api-version=2019-10-01-preview"

# Retreive the Billing Accounts you have access to
$restUriBillingAccountsResponse = Invoke-RestMethod -Uri $restUriBillingAccounts -Method Get -Headers $authHeader

# Filter Billing Account Name for the Microsoft Customer Agreement / Partner
$billingAccountName = ($restUriBillingAccountsResponse.value| Where-Object {$_.properties.agreementType -like "MicrosoftCustomerAgreement"}).name

Now there are two ways to get a list of all the customers. We can query the /customers endpoint like so:

$restUriCustomers = "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$billingAccountName/customers?api-version=2019-10-01-preview"
$restUriCustomersResponse = Invoke-RestMethod -Uri $restUriCustomers -Method Get -Headers $authHeader

But this comes with a limitation. Querying the customers endpoint only gives you an overview of the customers that signed the Microsoft Customer Agreement and is not directly linked to their usage or invoicing.

If you have customers that have not yet transitioned to the Azure Plan it's very likely that they're already using some kind of Azure Plan indirectly, for instance by using a third party market place offering. They will not show up when querying the customers endpoint. Technically, they're still not actually using an Azure Plan but this information can be important if you want to figure out your Partner Earned Credits and whether they are applied or not.

Additionally, if you want to request all the subscriptions within the Azure Plan under a specific MCA, you would need to write some logic and loop through the subscriptions and report the contents you need. Which is not that hard to achieve but probably takes more effort than one would like if you just want a quick overview. If you're going to build multiple reports and automate against multiple APIs I do recommended starting with the /customers endpoint as it doesn't return as much information and is much quicker than  requesting all the usage data and work from that.

Another way to go about this, is by querying the usageDetails endpoint. This endpoint has been around for a while but can now be leveraged by CSPs.

Once a subscription starts reporting usage, the customer and their subscriptions will  show up within the usageDetails API. This can take up to a few hours after the subscription is transitioned into an Azure Plan. If you want to immediately verify whether they have transitioned I recommend using the previous methods and APIs.

Let's query the /usageDetails endpoint within our Billing Account. Note that this will generate a lot of data and you might want to start filtering stuff in your initial query. But for now, let's go with everything :)

$restUriCostManagement = "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$billingAccountName/providers/Microsoft.Consumption/usageDetails?api-version=2019-10-01"

# Retreive the Billing Accounts you have access to
$restUriCostManagementResponse = Invoke-RestMethod -Uri $restUriCostManagement -Method Get -Headers $authHeader -TimeoutSec 300

This might take a bit to finish executing. But once it's done we've got all the usage details stored in $restUriCostManagementReponse. Let's focus on a specific customer "Cloud Adventures".

$customerName = "Cloud Adventures"
$restUriCostManagementResponse.value | Where-Object  {$_.properties.customerName -like "$customerName"}

This still results in a bunch of data that isn't that pleasant to read. In the end, it's the properties that matter and that will provide us with the details we're looking for.

($restUriCostManagementResponse.value | Where-Object  {$_.properties.customerName -like "$customerName"}).properties

This will still give us a lot of information but we're getting some insights into the properties.

And these are properties we can work with and build some reporting on by requesting specific properties.

Partner Earned Credits

Something particularly interesting to check is whether the property "partnerEarnedCreditsApplied" is set to "1". If you're providing managed services for a subscription, you probably want this to be set as it will give your recognition over provided services for a specific resource.

There's a lot of documentation on Partner Earned Credits (here) but going into details about the inner workings is beyond scope of this post. To quote docs.microsoft.com:

"Partner earned credit for managed services (PEC) recognizes and rewards partners that own the 24x7 IT operational control and management of parts of, or the entire, Azure environment of their customers"

Talk to the people responsible for commerce within your company and they should know what it means and probably want to make sure you, as a company, get recognized. Read up on the documentation to learn when you're receiving PEC and what it takes here:

Alright, let's look this up. Building on the previous query we can look this up for our "Cloud Adventures" customer. As PEC is applied on an individual resource, we want to check every subscription and every resource of that customer. In the following example Partner Earned Credits are applied:

What I ended up with was a pretty raw script that grabs all the resources that have the property "partnerEarnedCreditApplied" set to "0" and put them into an array that we can use.

$customersWithoutPec = @()
foreach ($customer in $restUriCostManagementResponse.value)
{

    if ($customer.properties.partnerEarnedCreditApplied -eq "0")
    {
        $customersWithoutPec+=$customer
       
    }
}

This stores all the resources that have the property "partnerEarnedCreditApplied" set to "0" in our $customersWithoutPec array. This allows us to create an overview of all the customers, subscriptions and resources that you're not receiving Partner Earned Credits for. Note that this does not mean you should receive them as it's very possible that a market place item is deployed which a third party is receiving recognition for or if there's another MSP providing managed services as well. But if neither is the case, you probably want to make sure you are the one receiving recognition :)

Let's build a fairly simple report using the array we populated earlier.

$customersWithoutPec.properties `
|Sort-Object -Property @{Expression = {$_.customerName}; Ascending = $false}, subscriptionName -Unique `
|Select-Object @{N='Customer'; E={$_.customerName}}, @{N='Subscription'; E={$_.subscriptionName}}, @{N='Subscription ID'; E={$_.subscriptionGuid}}

This results in an overview of all subscriptions that have 1 or more resources where the partnerEarnedCreditApplied property is set to "0".  

Additionally we can create an overview containing the specific resources we're talking about.

$customersWithoutPec.properties `
|Sort-Object -Property @{Expression = {$_.customerName}; Ascending = $false}, subscriptionName `
|Select-Object @{N='Customer'; E={$_.customerName}}, @{N='Subscription'; E={$_.subscriptionName}}, @{N='Subscription ID'; E={$_.subscriptionGuid}}, @{N='Service'; E={$_.ConsumedService}}, @{N='Product'; E={$_.ProductOrderName}}, @{N='Marketplace Item'; E={$_.meterName}}, @{N='Resource ID'; E={$_.InstanceName}} 

Again.. a lot of data but with some HTML magic we can create a pretty straight forward report to share with our peers.

You can find the code for the report here: https://github.com/whaakman/azureplan-billing-and-cost-management-api/blob/master/getMCAPecIsZero.ps1

Similar scripts in the same repository here: https://github.com/whaakman/azureplan-billing-and-cost-management-api/

A useful API that will definitely help automate some cost management processes. Build on top of that, a combination of Azure Functions and Logic Apps can help you automate these processes. Either way, it's good to familiarize yourself with these APIs, especially if you're a Cloud Service Provider as this more or less touches the very core of your commercial business.