# Billing data

> Get your negotiated Azure prices into LevelFour with billing reader on an Enterprise Agreement or Microsoft Customer Agreement, or read cost from a daily export on pay-as-you-go.

Source: https://docs.levelfour.ai/connectors/azure/billing-data


LevelFour prices every figure on what Azure charged you, actual and amortized, and never on list or retail prices. Where it reads that cost depends on how you buy Azure.

| How you buy Azure                  | Where LevelFour reads cost                                            | What you do                                             |
| ---------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------- |
| Enterprise Agreement (EA)          | Your enrollment, once LevelFour holds **Enrollment reader**           | Grant the billing role, below                           |
| Microsoft Customer Agreement (MCA) | Your billing account, once LevelFour holds **Billing account reader** | Grant the billing role, below                           |
| Pay-as-you-go                      | A daily export in your own storage                                    | Nothing beyond the [connect command](/connectors/azure) |
| Cloud Solution Provider (CSP)      | Each subscription, as your partner allows                             | Ask your partner, below                                 |

To check yours, run `az billing account list --query "[].agreementType" -o tsv` in Cloud Shell.

## Negotiated prices on EA and MCA

Until LevelFour holds a billing role, it reads cost per subscription. That cost misses what Azure records only at the billing account.

> **Warning**
>
> Without a billing role, your Azure costs leave out reservation and savings plan purchases and Marketplace charges, and on an EA a subscription shows no cost at all unless your enrollment lets account owners view charges. Grant the billing role to see the whole invoice.

The [connect command](/connectors/azure) grants the billing role on its own when the person running it holds billing rights. Most engineers do not, so finance usually adds it afterwards.

### The finance follow-up

Hand this to someone who manages your billing account: an Enterprise Administrator on an EA, or a Billing account owner or contributor on an MCA.

### Get the command for a billing admin

In LevelFour, open **Connect Providers > Azure** and, on the Azure account, click **Get the command for a billing admin**. The command belongs to the same connection, so nothing you connected before changes.

### Run it in Cloud Shell

The billing admin pastes the command into [Azure Cloud Shell](https://shell.azure.com) and picks the same subscriptions as the first run. The script finds the existing `LevelFour` app, adds a fresh secret, and grants the billing role on every billing account the admin manages.

On an MCA, run it in the directory that holds the billing account. Azure gives billing roles only to identities from that directory.

### Check the output

The script ends with `Connected.` If **Enrollment reader** or **Billing account reader** shows under **Not granted** on the LevelFour page, the admin lacks the right to assign it. Have the account owner run it, or grant the role by hand.

### Granting the role by hand

Find the `LevelFour` service principal's object ID first:

```bash
az ad sp list --display-name LevelFour --query "[0].id" -o tsv
```

**Microsoft Customer Agreement**

In the Azure portal, open **Cost Management + Billing**, select your billing account, open **Access control (IAM)**, and add `LevelFour` as **Billing account reader**.

**Enterprise Agreement**

The Azure portal cannot give an EA billing role to a service principal. Assign **Enrollment reader** through the billing API instead, as an Enterprise Administrator:

```bash
ENROLLMENT="YOUR_ENROLLMENT_NUMBER"
PRINCIPAL_ID="THE_OBJECT_ID_ABOVE"
TENANT_ID="$(az account show --query tenantId -o tsv)"
az rest --method put \
  --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$ENROLLMENT/billingRoleAssignments/$(cat /proc/sys/kernel/random/uuid)?api-version=2019-10-01-preview" \
  --body "{\"properties\": {\"principalId\": \"$PRINCIPAL_ID\", \"principalTenantId\": \"$TENANT_ID\", \"roleDefinitionId\": \"/providers/Microsoft.Billing/billingAccounts/$ENROLLMENT/billingRoleDefinitions/24f8edb6-1668-4659-b5e2-40bb5f3a7d7e\"}}"
```

The role ID `24f8edb6-1668-4659-b5e2-40bb5f3a7d7e` is Azure's built-in **Enrollment reader**.

LevelFour picks up the role on its next check, and the following sync reads cost from the billing account.

## Pay-as-you-go: the daily cost export

Azure offers no line-by-line cost report for a pay-as-you-go subscription, so the connect command sets up an export in your own subscription and LevelFour reads it from there. It creates:

| What                                                                      | Name                                                                                            |
| ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| A resource group, in the region you choose                                | `levelfour-cost-export`                                                                         |
| A storage account, standard and locally redundant, with public access off | `lf` followed by 20 letters and digits                                                          |
| A private container                                                       | `levelfour-cost`                                                                                |
| Two daily exports per subscription, actual and amortized cost             | `levelfour-actualcost` and `levelfour-amortizedcost`, writing under `exports/<subscription ID>` |
| **Storage Blob Data Reader** for `LevelFour`, on that container only      |                                                                                                 |

The command asks which region should store the export, and suggests the one that holds most of your resource groups. Set `LEVELFOUR_EXPORT_REGION` before you paste the command to answer up front. The storage holds a few CSV files a day and costs cents a month.

The exports cover the subscriptions you chose to connect. For a management group, that means each subscription under it when the command runs, so run the command again from the LevelFour page after you add a pay-as-you-go subscription to the group.

Each export writes from the current month on. The command also asks Azure to run each export once for each of the 13 months before this one. Azure queues those runs, and LevelFour reads each month as its files land. It asks only once LevelFour has accepted the connection. If Cloud Shell listed past months Azure refused, run the command again from the LevelFour page, or export those months from the Azure portal under **Cost Management > Exports**.

> **Note**
>
> Azure leaves Marketplace and commitment purchases out of pay-as-you-go cost data, so they do not appear in LevelFour either.

To set the export up by hand instead, create the same storage and exports in **Cost Management > Exports**, give `LevelFour` **Storage Blob Data Reader** on the container, then run the connect command once so LevelFour learns where the export writes.

## Cloud Solution Provider

If you buy Azure through a CSP partner, Azure shows cost at retail rates, without the partner's discounts or credits, and only after your partner turns on cost visibility for your directory. Reservation usage shows at zero. Treat these figures as retail, and ask your partner for the invoice they bill you.

## Confirming it worked

After the next sync, your Azure cost includes reservation, savings plan and Marketplace purchases, and the month's total matches your invoice. On a pay-as-you-go account, the first export lands within a day, and cost for the current month appears after the sync that follows.

## Removing access

**Billing role.** On an MCA, remove `LevelFour` under **Cost Management + Billing > Access control (IAM)**. On an EA, list the enrollment's role assignments with `az rest --method get --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$ENROLLMENT/billingRoleAssignments?api-version=2019-10-01-preview"`, then send `az rest --method delete` to the one whose `principalId` is the `LevelFour` object ID.

**Pay-as-you-go export.** Delete both exports on each subscription the command exported, then the resource group that holds the storage. That group lives only in the subscription you ran the command in:

```bash
for SUBSCRIPTION in YOUR_SUBSCRIPTION_ID ANOTHER_SUBSCRIPTION_ID; do
  for EXPORT in levelfour-actualcost levelfour-amortizedcost; do
    az rest --method delete \
      --url "https://management.azure.com/subscriptions/$SUBSCRIPTION/providers/Microsoft.CostManagement/exports/$EXPORT?api-version=2023-07-01-preview"
  done
done
az group delete --name levelfour-cost-export --subscription "SUBSCRIPTION_YOU_RAN_THE_COMMAND_IN"
```

## Troubleshooting

**`Not granted: Billing account reader` or `Not granted: Enrollment reader`.**
The person who ran the command cannot assign billing roles. Have a billing account owner or Enterprise Administrator run it, or grant the role by hand.

**Costs on an EA are zero or missing.**
Your enrollment hides charges from account owners and LevelFour holds no billing role. Grant **Enrollment reader**.

**Pay-as-you-go costs never arrive.**
Check the run history of `levelfour-actualcost` in **Cost Management > Exports**. A failed run usually means the `Microsoft.CostManagementExports` resource provider is not registered on the subscription. Register it with `az provider register --namespace Microsoft.CostManagementExports` and run the export again.

**A `Not granted: Cost export storage` line.**
You lack rights to create a resource group or storage account in the subscription Cloud Shell is set to. Switch to one you own with `az account set --subscription <id>`, then run the command again from the LevelFour page.

## Next

* [Commitments](/connectors/azure/commitments) reads your reservations and savings plans through the same billing role
* [Connect Azure](/connectors/azure) covers the connect command and every role it grants
