The Azure Cost Management Data Export API allows programmatic access to your billing and usage data, enabling automated cost analysis, custom reporting, and integration with third-party financial systems. This guide shows you how to verify your subscription eligibility, configure API access, and authenticate for programmatic cost data retrieval.
Overview
Unlike the Azure Portal's Cost Management interface, the Cost Management Data Export API provides:
- Automated cost data retrieval for scheduled reporting and analysis
- Integration capabilities with external systems (ERPs, FinOps platforms, custom dashboards)
- Programmatic export management for creating, updating, and triggering cost exports
- Granular data access with filtering, grouping, and aggregation options
- Real-time API queries without waiting for scheduled export files
The API is available through Azure REST API endpoints and can be accessed using:
- Azure CLI (az costmanagementcommands)
- PowerShell Az module (Az.CostManagementcmdlets)
- Direct REST API calls with OAuth2 authentication
- Azure SDKs (Python, .NET, Java, JavaScript)
This guide covers eligibility requirements, authentication setup, and common API operations.
Prerequisites
Before you begin, ensure you have:
- An Enterprise Agreement (EA), Microsoft Customer Agreement (MCA), or Pay-As-You-Go subscription
- Note: Not all API features are available for all subscription types (detailed below)
 
- Cost Management Contributor or Cost Management Reader role at the appropriate scope
- Azure CLI 2.30.0+ or PowerShell 7+ with Az modules installed
- For direct API access: Ability to create Azure AD App Registrations (Service Principal)
- Basic understanding of OAuth2 authentication and REST APIs
- (Optional) Familiarity with Azure Resource Manager scopes
Subscription Type Support Matrix
| Feature | EA | MCA | Pay-As-You-Go | CSP | 
|---|---|---|---|---|
| Usage Details API | ✓ | ✓ | ✓ | ✓ | 
| Cost Management Exports API | ✓ | ✓ | ✓ | Limited | 
| Budgets API | ✓ | ✓ | ✓ | ✗ | 
| Cost Allocation Rules API | ✓ | ✓ | ✗ | ✗ | 
| Pricing Sheet API | ✓ | ✓ | ✗ | ✗ | 
Verify Your Subscription Type
# Check subscription type
az account show --query "{Name:name, Type:tenantId, SubscriptionId:id}" -o table
# Check billing account type (for EA/MCA)
az billing account list --query "[].{Name:name, Type:agreementType}" -o table
# Expected output for EA:
# Name        Type
# 12345678    EnterpriseAgreement
# Expected output for MCA:
# Name                     Type
# abcd-1234-efgh-5678     MicrosoftCustomerAgreement
Method 1: Enable API Access Using Azure CLI
The simplest way to access the Cost Management API is through Azure CLI.
Step 1: Verify Azure CLI Installation
# Check Azure CLI version (requires 2.30.0+)
az --version
# Upgrade if needed
# macOS: brew upgrade azure-cli
# Windows: Download from https://aka.ms/installazurecliwindows
# Linux: curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Login to Azure
az login
# Set default subscription
az account set --subscription "YOUR-SUBSCRIPTION-ID"
Step 2: Verify API Permissions
# Check your Cost Management role assignments
az role assignment list \
  --assignee $(az account show --query user.name -o tsv) \
  --scope "/subscriptions/$(az account show --query id -o tsv)" \
  --query "[?contains(roleDefinitionName, 'Cost')].{Role:roleDefinitionName, Scope:scope}" -o table
# Expected roles:
# - Cost Management Contributor (read/write access)
# - Cost Management Reader (read-only access)
Step 3: Test API Access with Usage Details Query
# Query usage details for current month
az costmanagement query \
  --type "Usage" \
  --scope "/subscriptions/$(az account show --query id -o tsv)" \
  --timeframe "MonthToDate" \
  --dataset-aggregation '{
    "totalCost": {
      "name": "PreTaxCost",
      "function": "Sum"
    }
  }' \
  --dataset-grouping '{
    "type": "Dimension",
    "name": "ResourceGroup"
  }'
Expected output:
{
  "id": "subscriptions/.../providers/Microsoft.CostManagement/query/...",
  "name": "...",
  "type": "Microsoft.CostManagement/query",
  "properties": {
    "nextLink": null,
    "columns": [
      {"name": "PreTaxCost", "type": "Number"},
      {"name": "ResourceGroup", "type": "String"},
      {"name": "UsageDate", "type": "Number"}
    ],
    "rows": [
      [123.45, "production-rg", 20250115],
      [67.89, "dev-rg", 20250115]
    ]
  }
}
Step 4: List Existing Exports
# List all cost exports at subscription scope
az costmanagement export list \
  --scope "/subscriptions/$(az account show --query id -o tsv)"
# List exports at billing account scope (EA/MCA only)
BILLING_ACCOUNT_ID=$(az billing account list --query "[0].id" -o tsv)
az costmanagement export list --scope "$BILLING_ACCOUNT_ID"
Method 2: Enable API Access Using PowerShell
PowerShell provides cmdlets for Cost Management API operations.
Step 1: Install Required Modules
# Install Az modules
Install-Module -Name Az.CostManagement -Repository PSGallery -Force
Install-Module -Name Az.Accounts -Repository PSGallery -Force
Install-Module -Name Az.Billing -Repository PSGallery -Force
# Connect to Azure
Connect-AzAccount
# Set subscription context
Set-AzContext -SubscriptionId "YOUR-SUBSCRIPTION-ID"
Step 2: Verify API Access
# Get current context
$context = Get-AzContext
Write-Host "Connected as: $($context.Account.Id)"
Write-Host "Subscription: $($context.Subscription.Name)"
# Check Cost Management permissions
$scope = "/subscriptions/$($context.Subscription.Id)"
$assignments = Get-AzRoleAssignment -Scope $scope -SignInName $context.Account.Id
$costRoles = $assignments | Where-Object { $_.RoleDefinitionName -like "*Cost*" }
$costRoles | Format-Table RoleDefinitionName, Scope
Step 3: Query Cost Data
# Define query parameters
$scope = "/subscriptions/$((Get-AzContext).Subscription.Id)"
$timePeriod = New-AzCostManagementQueryComparisonExpressionObject -Name 'UsageDate' -Operator 'In' -Value @('20250101', '20250131')
# Create aggregation
$aggregation = @{
    totalCost = @{
        name = 'PreTaxCost'
        function = 'Sum'
    }
}
# Create grouping
$grouping = @(
    @{
        type = 'Dimension'
        name = 'ResourceType'
    }
)
# Execute query
$result = Invoke-AzCostManagementQuery `
    -Scope $scope `
    -Timeframe 'MonthToDate' `
    -Type 'Usage' `
    -DatasetAggregation $aggregation `
    -DatasetGrouping $grouping
# Display results
$result.Row | ForEach-Object {
    [PSCustomObject]@{
        Cost = $_[0]
        ResourceType = $_[1]
        Date = $_[2]
    }
} | Format-Table
Step 4: Manage Exports via PowerShell
# List all exports
$exports = Get-AzCostManagementExport -Scope $scope
$exports | Format-Table Name, @{Label="Type";Expression={$_.DefinitionType}}, @{Label="Status";Expression={$_.ScheduleStatus}}
# Get specific export
$exportName = "daily-costs"
$export = Get-AzCostManagementExport -Scope $scope -Name $exportName
$export | Format-List
# Trigger manual export run
Invoke-AzCostManagementExecuteExport -ExportName $exportName -Scope $scope
Method 3: Enable API Access Using Service Principal
For automated systems and CI/CD pipelines, use Service Principal authentication.
Step 1: Create Service Principal
# Create service principal with Cost Management Reader role
SUBSCRIPTION_ID=$(az account show --query id -o tsv)
APP_NAME="cost-management-api-sp"
# Create the service principal and assign role
az ad sp create-for-rbac \
  --name "$APP_NAME" \
  --role "Cost Management Reader" \
  --scopes "/subscriptions/$SUBSCRIPTION_ID" \
  --query "{AppId:appId, Password:password, Tenant:tenant}" \
  -o json
# Save output (appId, password, tenant) securely
# Example output:
# {
#   "AppId": "12345678-1234-1234-1234-123456789012",
#   "Password": "abcdefgh-1234-5678-90ab-cdefghijklmn",
#   "Tenant": "87654321-4321-4321-4321-210987654321"
# }
Step 2: Grant Additional Permissions (if needed)
# Grant export management permissions
az role assignment create \
  --assignee "APP-ID-FROM-STEP-1" \
  --role "Cost Management Contributor" \
  --scope "/subscriptions/$SUBSCRIPTION_ID"
# Grant billing account access (for EA/MCA)
BILLING_ACCOUNT_ID=$(az billing account list --query "[0].id" -o tsv)
az role assignment create \
  --assignee "APP-ID-FROM-STEP-1" \
  --role "Cost Management Reader" \
  --scope "$BILLING_ACCOUNT_ID"
Step 3: Test Service Principal Authentication
# Login using service principal
az login \
  --service-principal \
  --username "APP-ID" \
  --password "PASSWORD" \
  --tenant "TENANT-ID"
# Verify access
az account show
# Test Cost Management query
az costmanagement query \
  --type "Usage" \
  --scope "/subscriptions/$SUBSCRIPTION_ID" \
  --timeframe "MonthToDate"
Step 4: Use Service Principal in Applications
Python Example:
from azure.identity import ClientSecretCredential
from azure.mgmt.costmanagement import CostManagementClient
from azure.mgmt.costmanagement.models import (
    QueryDefinition,
    QueryTimePeriod,
    QueryDataset,
    QueryAggregation,
    QueryGrouping
)
import os
from datetime import datetime, timedelta
# Service Principal credentials
tenant_id = os.getenv("AZURE_TENANT_ID")
client_id = os.getenv("AZURE_CLIENT_ID")
client_secret = os.getenv("AZURE_CLIENT_SECRET")
subscription_id = os.getenv("AZURE_SUBSCRIPTION_ID")
# Authenticate
credential = ClientSecretCredential(
    tenant_id=tenant_id,
    client_id=client_id,
    client_secret=client_secret
)
# Create Cost Management client
client = CostManagementClient(credential)
# Define query
scope = f"/subscriptions/{subscription_id}"
# Calculate date range (last 7 days)
end_date = datetime.now()
start_date = end_date - timedelta(days=7)
query = QueryDefinition(
    type="Usage",
    timeframe="Custom",
    time_period=QueryTimePeriod(
        from_property=start_date.strftime("%Y-%m-%dT00:00:00Z"),
        to=end_date.strftime("%Y-%m-%dT23:59:59Z")
    ),
    dataset=QueryDataset(
        granularity="Daily",
        aggregation={
            "totalCost": QueryAggregation(
                name="PreTaxCost",
                function="Sum"
            )
        },
        grouping=[
            QueryGrouping(
                type="Dimension",
                name="ResourceGroup"
            )
        ]
    )
)
# Execute query
result = client.query.usage(scope, query)
# Process results
for row in result.rows:
    cost = row[0]
    resource_group = row[1]
    date = row[2]
    print(f"Date: {date}, Resource Group: {resource_group}, Cost: ${cost:.2f}")
PowerShell Example:
# Service Principal credentials (from environment variables or Key Vault)
$tenantId = $env:AZURE_TENANT_ID
$clientId = $env:AZURE_CLIENT_ID
$clientSecret = $env:AZURE_CLIENT_SECRET | ConvertTo-SecureString -AsPlainText -Force
# Create credential
$credential = New-Object System.Management.Automation.PSCredential($clientId, $clientSecret)
# Connect using service principal
Connect-AzAccount -ServicePrincipal -TenantId $tenantId -Credential $credential
# Query cost data
$scope = "/subscriptions/$env:AZURE_SUBSCRIPTION_ID"
$result = Invoke-AzCostManagementQuery `
    -Scope $scope `
    -Timeframe 'MonthToDate' `
    -Type 'Usage'
# Process results
$result.Row | ForEach-Object {
    Write-Host "Cost: $($_[0]), Resource: $($_[1])"
}
Method 4: Direct REST API Access
For maximum flexibility, use the REST API directly with OAuth2 tokens.
Step 1: Obtain Access Token
# Get access token using Azure CLI
ACCESS_TOKEN=$(az account get-access-token --resource https://management.azure.com --query accessToken -o tsv)
# Verify token (should return valid JWT)
echo $ACCESS_TOKEN | cut -d '.' -f 2 | base64 -d 2>/dev/null | jq .
Step 2: Make API Request
# Define variables
SUBSCRIPTION_ID=$(az account show --query id -o tsv)
API_VERSION="2023-03-01"
SCOPE="/subscriptions/$SUBSCRIPTION_ID"
# Query usage details
curl -X POST \
  "https://management.azure.com${SCOPE}/providers/Microsoft.CostManagement/query?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "Usage",
    "timeframe": "MonthToDate",
    "dataset": {
      "granularity": "Daily",
      "aggregation": {
        "totalCost": {
          "name": "PreTaxCost",
          "function": "Sum"
        }
      },
      "grouping": [
        {
          "type": "Dimension",
          "name": "ResourceType"
        }
      ]
    }
  }' | jq .
Step 3: List Exports via REST API
# List all exports
curl -X GET \
  "https://management.azure.com${SCOPE}/providers/Microsoft.CostManagement/exports?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" | jq .
# Get specific export
EXPORT_NAME="daily-costs"
curl -X GET \
  "https://management.azure.com${SCOPE}/providers/Microsoft.CostManagement/exports/${EXPORT_NAME}?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" | jq .
Step 4: Create Export via REST API
# Create new export
curl -X PUT \
  "https://management.azure.com${SCOPE}/providers/Microsoft.CostManagement/exports/api-created-export?api-version=${API_VERSION}" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "properties": {
      "schedule": {
        "status": "Active",
        "recurrence": "Daily",
        "recurrencePeriod": {
          "from": "2025-01-01T00:00:00Z",
          "to": "2025-12-31T23:59:59Z"
        }
      },
      "format": "Csv",
      "deliveryInfo": {
        "destination": {
          "resourceId": "/subscriptions/SUB-ID/resourceGroups/RG/providers/Microsoft.Storage/storageAccounts/STORAGE",
          "container": "cost-exports",
          "rootFolderPath": "api-exports"
        }
      },
      "definition": {
        "type": "ActualCost",
        "timeframe": "MonthToDate",
        "dataSet": {
          "granularity": "Daily"
        }
      }
    }
  }' | jq .
Common API Operations
Query Cost Data with Filters
# Query costs for specific resource group
az costmanagement query \
  --type "Usage" \
  --scope "/subscriptions/$(az account show --query id -o tsv)" \
  --timeframe "MonthToDate" \
  --dataset-filter '{
    "dimensions": {
      "name": "ResourceGroup",
      "operator": "In",
      "values": ["production-rg", "staging-rg"]
    }
  }'
# Query costs with tag filter
az costmanagement query \
  --type "Usage" \
  --scope "/subscriptions/$(az account show --query id -o tsv)" \
  --timeframe "MonthToDate" \
  --dataset-filter '{
    "tags": {
      "name": "Environment",
      "operator": "In",
      "values": ["Production"]
    }
  }'
Get Pricing Information (EA/MCA only)
# Get price sheet for EA billing account
BILLING_ACCOUNT_ID=$(az billing account list --query "[0].name" -o tsv)
az costmanagement query \
  --type "Usage" \
  --scope "/providers/Microsoft.Billing/billingAccounts/$BILLING_ACCOUNT_ID" \
  --timeframe "MonthToDate"
Trigger Export Execution
# Manually run an export
az costmanagement export execute \
  --export-name "daily-costs" \
  --scope "/subscriptions/$(az account show --query id -o tsv)"
# Check export run history
az rest --method GET \
  --uri "https://management.azure.com/subscriptions/$(az account show --query id -o tsv)/providers/Microsoft.CostManagement/exports/daily-costs/runHistory?api-version=2023-03-01"
Best Practices
1. Use Managed Identities When Possible
For Azure-hosted applications, use Managed Identity instead of Service Principals:
from azure.identity import ManagedIdentityCredential
from azure.mgmt.costmanagement import CostManagementClient
# Use Managed Identity (no credentials needed)
credential = ManagedIdentityCredential()
client = CostManagementClient(credential)
2. Implement Token Caching
Cache access tokens to reduce authentication overhead:
from azure.identity import ClientSecretCredential
from azure.core.credentials import AccessToken
from datetime import datetime, timedelta
class TokenCache:
    def __init__(self, credential):
        self._credential = credential
        self._token = None
        self._expires_on = None
    def get_token(self):
        if self._token is None or datetime.now() >= self._expires_on:
            token = self._credential.get_token("https://management.azure.com/.default")
            self._token = token.token
            self._expires_on = datetime.fromtimestamp(token.expires_on) - timedelta(minutes=5)
        return self._token
3. Handle API Rate Limits
Implement exponential backoff for API throttling:
import time
from azure.core.exceptions import HttpResponseError
def query_with_retry(client, scope, query, max_retries=3):
    for attempt in range(max_retries):
        try:
            return client.query.usage(scope, query)
        except HttpResponseError as e:
            if e.status_code == 429:  # Too Many Requests
                wait_time = (2 ** attempt) * 5  # Exponential backoff
                print(f"Rate limited. Waiting {wait_time} seconds...")
                time.sleep(wait_time)
            else:
                raise
    raise Exception("Max retries exceeded")
4. Use Appropriate Scopes
Choose the right scope for your queries:
# Subscription scope
SCOPE="/subscriptions/SUB-ID"
# Resource group scope
SCOPE="/subscriptions/SUB-ID/resourceGroups/RG-NAME"
# Management group scope
SCOPE="/providers/Microsoft.Management/managementGroups/MG-ID"
# Billing account scope (EA/MCA)
SCOPE="/providers/Microsoft.Billing/billingAccounts/BILLING-ID"
5. Optimize Query Performance
- Use appropriate date ranges (avoid querying years of data at once)
- Apply filters to reduce result set size
- Use pagination for large result sets
- Cache results when appropriate
# Query with specific date range instead of "MonthToDate"
az costmanagement query \
  --type "Usage" \
  --scope "/subscriptions/$(az account show --query id -o tsv)" \
  --timeframe "Custom" \
  --time-period '{
    "from": "2025-01-01T00:00:00Z",
    "to": "2025-01-07T23:59:59Z"
  }'
6. Secure Credentials
Never hardcode credentials:
# Use environment variables
export AZURE_TENANT_ID="your-tenant-id"
export AZURE_CLIENT_ID="your-client-id"
export AZURE_CLIENT_SECRET="your-client-secret"
# Or use Azure Key Vault
az keyvault secret set \
  --vault-name "cost-api-vault" \
  --name "service-principal-secret" \
  --value "YOUR-SECRET"
# Retrieve in application
SECRET=$(az keyvault secret show \
  --vault-name "cost-api-vault" \
  --name "service-principal-secret" \
  --query value -o tsv)
Troubleshooting
Issue: 403 Forbidden Error
Symptoms: API requests fail with "AuthorizationFailed" or "Forbidden"
Solution:
- Verify you have correct role assignment
- Check scope matches your permission level
- Ensure subscription type supports the API feature
# Check role assignments
az role assignment list \
  --assignee $(az account show --query user.name -o tsv) \
  --all
# Test with more permissive role
az role assignment create \
  --assignee "[email protected]" \
  --role "Cost Management Contributor" \
  --scope "/subscriptions/$(az account show --query id -o tsv)"
Issue: 404 Not Found Error
Symptoms: API returns "ResourceNotFound"
Solution:
- Verify scope format is correct
- Check subscription ID is accurate
- Ensure export name matches existing export
# Verify subscription ID
az account show --query id -o tsv
# List available scopes
az account list --query "[].{Name:name, Id:id}" -o table
# List existing exports
az costmanagement export list \
  --scope "/subscriptions/$(az account show --query id -o tsv)" \
  --query "[].name" -o table
Issue: Token Expiration
Symptoms: Authentication works initially but fails after some time
Solution:
- Implement token refresh logic
- Check token expiration before each request
- Use SDK automatic token management
from azure.identity import ClientSecretCredential
from azure.core.credentials import AccessToken
credential = ClientSecretCredential(tenant_id, client_id, client_secret)
# SDK automatically refreshes tokens
# Manual check if needed:
token = credential.get_token("https://management.azure.com/.default")
print(f"Token expires at: {token.expires_on}")
Issue: Empty or Incomplete Data
Symptoms: API returns success but with no data rows
Solution:
- Check date range includes billable period
- Verify scope contains resources with costs
- Review filters aren't excluding all data
- Wait 24-48 hours for recent cost data to finalize
# Check if subscription has any costs
az costmanagement query \
  --type "Usage" \
  --scope "/subscriptions/$(az account show --query id -o tsv)" \
  --timeframe "TheLastMonth" \
  --query "properties.rows" -o table
# If empty, try wider date range
az costmanagement query \
  --type "Usage" \
  --scope "/subscriptions/$(az account show --query id -o tsv)" \
  --timeframe "MonthToDate"
Next Steps
After enabling Cost Management API access:
- 
Build Custom Dashboards: Integrate cost data into existing reporting tools - Connect to Power BI, Tableau, or Grafana
- Create real-time cost monitoring dashboards
- Implement anomaly detection
 
- 
Automate Cost Governance: Use API for proactive cost management - Automated tagging enforcement
- Budget threshold alerts
- Resource cleanup automation
 
- 
Create Cost Analytics Pipelines: Build data pipelines for advanced analysis - Azure Data Factory integration
- Azure Synapse Analytics for large-scale analysis
- Machine learning for cost prediction
 
- 
Set Up Scheduled Exports: Automate cost data delivery 
- 
Implement Cost Allocation: Programmatically manage cost allocation rules 
Related Resources
Frequently Asked Questions
Find answers to common questions
Need Professional Help?
Our team of experts can help you implement and configure these solutions for your organization.