The Azure Retail Prices API provides programmatic access to official list prices for all Azure services, enabling accurate cost estimation, pricing comparisons, and rate card exports without Azure Portal access. This guide shows you how to retrieve, filter, and export pricing data for SKUs, regions, and meters using REST API calls.
Overview
Understanding Azure pricing is essential for:
- Cost estimation before deploying resources
- Budget planning with accurate list prices
- Multi-region pricing comparison to optimize deployment location
- Reserved Instance vs pay-as-you-go analysis for savings calculations
- Vendor RFP responses requiring official pricing documentation
- FinOps tooling that needs current rate cards for cost modeling
The Azure Retail Prices API provides:
- Pay-as-you-go list prices for all Azure services
- Regional pricing variations across 60+ Azure regions
- SKU-level pricing details with unit of measure and meter information
- Real-time updates as Microsoft adjusts pricing
- No authentication required for public pricing data
Unlike the Azure Pricing Calculator (web-based), the API enables automated pricing lookups, bulk exports, and integration with custom cost estimation tools.
Prerequisites
Before you begin, ensure you have:
- No Azure subscription required - The API is publicly accessible
- A tool for making HTTP requests:
curlorwget(command-line)- Postman or Insomnia (GUI)
- Python with
requestslibrary - PowerShell with
Invoke-RestMethod
- (Optional)
jqfor JSON parsing in command-line examples - (Optional) Excel or CSV processing tool for large exports
- Basic understanding of Azure service names and SKUs
Verify Tools Installation
# Check curl installation
curl --version
# Check jq installation (for JSON parsing)
jq --version
# If jq not installed:
# macOS: brew install jq
# Ubuntu/Debian: sudo apt-get install jq
# Windows: Download from https://stedolan.github.io/jq/download/
Understanding the Retail Prices API
API Endpoint
https://prices.azure.com/api/retail/prices
Key Query Parameters
| Parameter | Description | Example |
|---|---|---|
$filter | OData filter expression | serviceName eq 'Virtual Machines' |
$skip | Number of results to skip (pagination) | $skip=100 |
currencyCode | Currency for pricing | currencyCode='USD' |
api-version | API version | api-version=2023-01-01-preview |
Available Filters
armRegionName- Azure region (e.g., 'eastus', 'westeurope')serviceName- Service name (e.g., 'Virtual Machines', 'Storage')productName- Product/SKU name (e.g., 'Standard_D4s_v3')skuName- SKU tier (e.g., 'Standard', 'Premium')meterName- Billing meter (e.g., 'D4s v3', 'LRS Data Stored')type- Price type ('Consumption', 'Reservation', 'DevTestConsumption')isPrimaryMeterRegion- Boolean, true for primary pricing region
Method 1: Query Pricing with curl
The simplest way to retrieve pricing data is using curl for ad-hoc queries.
Example 1: Get Virtual Machine Pricing
# Get pricing for all VMs in East US
curl -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "api-version=2023-01-01-preview" \
--data-urlencode "\$filter=serviceName eq 'Virtual Machines' and armRegionName eq 'eastus' and priceType eq 'Consumption'" \
| jq '.Items[] | {productName: .productName, meterName: .meterName, unitPrice: .unitPrice, currencyCode: .currencyCode}'
Example output:
{
"productName": "Virtual Machines Dv3 Series",
"meterName": "D2 v3",
"unitPrice": 0.096,
"currencyCode": "USD"
}
{
"productName": "Virtual Machines Dv3 Series",
"meterName": "D4 v3",
"unitPrice": 0.192,
"currencyCode": "USD"
}
Example 2: Get Storage Pricing
# Get Standard LRS storage pricing
curl -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "api-version=2023-01-01-preview" \
--data-urlencode "\$filter=serviceName eq 'Storage' and productName eq 'Standard LRS' and armRegionName eq 'eastus'" \
| jq '.Items[] | {meterName: .meterName, unitPrice: .unitPrice, unitOfMeasure: .unitOfMeasure}'
Example 3: Get SQL Database Pricing
# Get Azure SQL Database pricing for a specific SKU
curl -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "api-version=2023-01-01-preview" \
--data-urlencode "\$filter=serviceName eq 'SQL Database' and armRegionName eq 'eastus' and skuName eq 'Standard' and priceType eq 'Consumption'" \
| jq '.Items[0:10] | .[] | {meterName: .meterName, unitPrice: .unitPrice}'
Example 4: Compare Pricing Across Regions
# Compare D4s_v3 VM pricing across multiple regions
for region in eastus westus westeurope southeastasia; do
echo "Region: $region"
curl -s -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "api-version=2023-01-01-preview" \
--data-urlencode "\$filter=serviceName eq 'Virtual Machines' and armRegionName eq '$region' and meterName eq 'D4s v3'" \
| jq -r '.Items[0] | "\(.armRegionName): \(.unitPrice) \(.currencyCode)"'
echo ""
done
Method 2: Export Pricing Data with Python
For larger datasets and automated workflows, use Python with the requests library.
Example 1: Basic Pricing Query
import requests
import json
from urllib.parse import urlencode
def get_azure_pricing(service_name, region=None):
"""Fetch Azure pricing for a specific service"""
base_url = "https://prices.azure.com/api/retail/prices"
# Build filter
filters = [f"serviceName eq '{service_name}'"]
if region:
filters.append(f"armRegionName eq '{region}'")
filters.append("priceType eq 'Consumption'")
params = {
'api-version': '2023-01-01-preview',
'$filter': ' and '.join(filters)
}
response = requests.get(base_url, params=params)
response.raise_for_status()
return response.json()
# Get VM pricing
pricing_data = get_azure_pricing('Virtual Machines', 'eastus')
# Display first 5 results
for item in pricing_data['Items'][:5]:
print(f"{item['meterName']}: ${item['unitPrice']}/{item['unitOfMeasure']}")
Example 2: Export to CSV
import requests
import csv
from urllib.parse import urlencode
def export_pricing_to_csv(service_name, region, output_file):
"""Export Azure pricing to CSV file"""
base_url = "https://prices.azure.com/api/retail/prices"
params = {
'api-version': '2023-01-01-preview',
'$filter': f"serviceName eq '{service_name}' and armRegionName eq '{region}' and priceType eq 'Consumption'"
}
all_items = []
# Handle pagination
while True:
response = requests.get(base_url, params=params)
response.raise_for_status()
data = response.json()
all_items.extend(data['Items'])
# Check for next page
if 'NextPageLink' in data and data['NextPageLink']:
base_url = data['NextPageLink']
params = {} # NextPageLink includes all params
else:
break
# Write to CSV
if all_items:
with open(output_file, 'w', newline='', encoding='utf-8') as csvfile:
fieldnames = [
'productName', 'skuName', 'meterName',
'unitPrice', 'unitOfMeasure', 'currencyCode',
'armRegionName', 'type', 'effectiveStartDate'
]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore')
writer.writeheader()
for item in all_items:
writer.writerow(item)
print(f"Exported {len(all_items)} pricing records to {output_file}")
else:
print("No pricing data found")
# Export VM pricing for East US
export_pricing_to_csv('Virtual Machines', 'eastus', 'vm_pricing_eastus.csv')
Example 3: Multi-Region Comparison
import requests
import pandas as pd
def compare_pricing_across_regions(service_name, meter_name, regions):
"""Compare pricing for a specific SKU across regions"""
base_url = "https://prices.azure.com/api/retail/prices"
results = []
for region in regions:
params = {
'api-version': '2023-01-01-preview',
'$filter': f"serviceName eq '{service_name}' and meterName eq '{meter_name}' and armRegionName eq '{region}' and priceType eq 'Consumption'"
}
response = requests.get(base_url, params=params)
data = response.json()
if data['Items']:
item = data['Items'][0]
results.append({
'Region': region,
'Price': item['unitPrice'],
'Currency': item['currencyCode'],
'Unit': item['unitOfMeasure']
})
# Create DataFrame for easy comparison
df = pd.DataFrame(results)
df = df.sort_values('Price')
return df
# Compare D4s v3 pricing across regions
regions = ['eastus', 'westus', 'westeurope', 'southeastasia', 'australiaeast']
comparison = compare_pricing_across_regions('Virtual Machines', 'D4s v3', regions)
print(comparison.to_string(index=False))
# Find cheapest region
cheapest = comparison.iloc[0]
print(f"\nCheapest region: {cheapest['Region']} at ${cheapest['Price']}/{cheapest['Unit']}")
Example 4: Reserved Instance Pricing
import requests
def get_reserved_instance_pricing(service_name, meter_name, region, term='1 Year'):
"""Get Reserved Instance pricing for comparison with pay-as-you-go"""
base_url = "https://prices.azure.com/api/retail/prices"
# Get consumption (PAYG) pricing
payg_params = {
'api-version': '2023-01-01-preview',
'$filter': f"serviceName eq '{service_name}' and meterName eq '{meter_name}' and armRegionName eq '{region}' and priceType eq 'Consumption'"
}
payg_response = requests.get(base_url, params=payg_params)
payg_data = payg_response.json()
# Get reservation pricing
ri_params = {
'api-version': '2023-01-01-preview',
'$filter': f"serviceName eq '{service_name}' and meterName eq '{meter_name}' and armRegionName eq '{region}' and priceType eq 'Reservation' and reservationTerm eq '{term}'"
}
ri_response = requests.get(base_url, params=ri_params)
ri_data = ri_response.json()
if payg_data['Items'] and ri_data['Items']:
payg_price = payg_data['Items'][0]['unitPrice']
ri_price = ri_data['Items'][0]['unitPrice']
# Calculate savings
hours_per_year = 8760 if term == '1 Year' else 8760 * 3
payg_annual_cost = payg_price * hours_per_year
ri_upfront_cost = ri_price # This is often total upfront cost
savings_percent = ((payg_annual_cost - ri_upfront_cost) / payg_annual_cost) * 100
print(f"Service: {service_name}")
print(f"SKU: {meter_name}")
print(f"Region: {region}")
print(f"Pay-as-you-go: ${payg_price}/hour (${payg_annual_cost:.2f}/year)")
print(f"Reserved ({term}): ${ri_upfront_cost:.2f}")
print(f"Savings: {savings_percent:.1f}%")
else:
print("Pricing data not available")
# Compare D4s_v3 PAYG vs 1-year RI pricing
get_reserved_instance_pricing('Virtual Machines', 'D4s v3', 'eastus', '1 Year')
Method 3: Query Pricing with PowerShell
PowerShell provides native REST API support for Windows environments.
Example 1: Basic Query
# Function to get Azure pricing
function Get-AzurePricing {
param(
[string]$ServiceName,
[string]$Region,
[string]$MeterName
)
$baseUrl = "https://prices.azure.com/api/retail/prices"
$apiVersion = "2023-01-01-preview"
# Build filter
$filterParts = @(
"serviceName eq '$ServiceName'",
"priceType eq 'Consumption'"
)
if ($Region) {
$filterParts += "armRegionName eq '$Region'"
}
if ($MeterName) {
$filterParts += "meterName eq '$MeterName'"
}
$filter = $filterParts -join ' and '
$params = @{
Uri = "$baseUrl`?api-version=$apiVersion&`$filter=$filter"
Method = 'GET'
ContentType = 'application/json'
}
$response = Invoke-RestMethod @params
return $response.Items
}
# Get VM pricing
$vmPricing = Get-AzurePricing -ServiceName "Virtual Machines" -Region "eastus"
$vmPricing | Select-Object meterName, unitPrice, unitOfMeasure | Format-Table
Example 2: Export to CSV
function Export-AzurePricing {
param(
[string]$ServiceName,
[string]$Region,
[string]$OutputFile
)
$baseUrl = "https://prices.azure.com/api/retail/prices"
$apiVersion = "2023-01-01-preview"
$filter = "serviceName eq '$ServiceName' and armRegionName eq '$Region' and priceType eq 'Consumption'"
$allItems = @()
$nextPageLink = "$baseUrl`?api-version=$apiVersion&`$filter=$filter"
# Handle pagination
while ($nextPageLink) {
$response = Invoke-RestMethod -Uri $nextPageLink -Method Get
$allItems += $response.Items
$nextPageLink = $response.NextPageLink
}
# Export to CSV
$allItems | Select-Object `
productName, skuName, meterName, unitPrice, unitOfMeasure, `
currencyCode, armRegionName, type, effectiveStartDate `
| Export-Csv -Path $OutputFile -NoTypeInformation
Write-Host "Exported $($allItems.Count) pricing records to $OutputFile"
}
# Export SQL Database pricing
Export-AzurePricing -ServiceName "SQL Database" -Region "eastus" -OutputFile "sql_pricing.csv"
Example 3: Regional Price Comparison
function Compare-RegionalPricing {
param(
[string]$ServiceName,
[string]$MeterName,
[string[]]$Regions
)
$baseUrl = "https://prices.azure.com/api/retail/prices"
$apiVersion = "2023-01-01-preview"
$results = @()
foreach ($region in $Regions) {
$filter = "serviceName eq '$ServiceName' and meterName eq '$MeterName' and armRegionName eq '$region' and priceType eq 'Consumption'"
$uri = "$baseUrl`?api-version=$apiVersion&`$filter=$filter"
$response = Invoke-RestMethod -Uri $uri -Method Get
if ($response.Items.Count -gt 0) {
$item = $response.Items[0]
$results += [PSCustomObject]@{
Region = $region
Price = $item.unitPrice
Currency = $item.currencyCode
Unit = $item.unitOfMeasure
}
}
}
# Sort by price
$results = $results | Sort-Object Price
return $results
}
# Compare D4s v3 across regions
$regions = @('eastus', 'westus', 'westeurope', 'southeastasia')
$comparison = Compare-RegionalPricing -ServiceName "Virtual Machines" -MeterName "D4s v3" -Regions $regions
$comparison | Format-Table -AutoSize
# Find cheapest
$cheapest = $comparison | Select-Object -First 1
Write-Host "`nCheapest region: $($cheapest.Region) at $($cheapest.Price) $($cheapest.Currency)/$($cheapest.Unit)"
Method 4: Batch Export All Pricing Data
For complete price catalogs, export all pricing data for a service.
Example: Complete Service Export (Python)
import requests
import csv
from datetime import datetime
import time
def export_complete_service_pricing(service_name, output_file):
"""Export all pricing data for a service with pagination handling"""
base_url = "https://prices.azure.com/api/retail/prices"
params = {
'api-version': '2023-01-01-preview',
'$filter': f"serviceName eq '{service_name}'"
}
all_items = []
page_count = 0
print(f"Exporting pricing for {service_name}...")
while True:
try:
response = requests.get(base_url, params=params, timeout=30)
response.raise_for_status()
data = response.json()
items_in_page = len(data['Items'])
all_items.extend(data['Items'])
page_count += 1
print(f"Page {page_count}: {items_in_page} items (total: {len(all_items)})")
# Check for next page
if 'NextPageLink' in data and data['NextPageLink']:
base_url = data['NextPageLink']
params = {} # NextPageLink includes all params
time.sleep(0.5) # Rate limiting courtesy
else:
break
except requests.RequestException as e:
print(f"Error fetching data: {e}")
break
# Write to CSV
if all_items:
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
output_path = f"{output_file}_{timestamp}.csv"
with open(output_path, 'w', newline='', encoding='utf-8') as csvfile:
fieldnames = list(all_items[0].keys())
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(all_items)
print(f"\nExport complete!")
print(f"Total items: {len(all_items)}")
print(f"Output file: {output_path}")
print(f"File size: {os.path.getsize(output_path) / (1024*1024):.2f} MB")
else:
print("No pricing data found")
# Export all VM pricing
export_complete_service_pricing('Virtual Machines', 'azure_vm_pricing')
# Export all storage pricing
export_complete_service_pricing('Storage', 'azure_storage_pricing')
Common Pricing Queries
Get All Azure Services
# List all available services
curl -s -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "api-version=2023-01-01-preview" \
| jq -r '.Items[].serviceName' | sort -u
Get All Regions for a Service
# List all regions where a service is available
curl -s -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "api-version=2023-01-01-preview" \
--data-urlencode "\$filter=serviceName eq 'Virtual Machines'" \
| jq -r '.Items[].armRegionName' | sort -u
Get Specific SKU Pricing
# Get pricing for a specific VM SKU
curl -s -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "api-version=2023-01-01-preview" \
--data-urlencode "\$filter=serviceName eq 'Virtual Machines' and armSkuName eq 'Standard_D4s_v3' and armRegionName eq 'eastus'" \
| jq '.Items[] | {skuName: .skuName, unitPrice: .unitPrice}'
Get Spot VM Pricing
# Get Spot VM pricing (usually much cheaper)
curl -s -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "api-version=2023-01-01-preview" \
--data-urlencode "\$filter=serviceName eq 'Virtual Machines' and armRegionName eq 'eastus' and priceType eq 'Consumption' and meterName contains 'Spot'" \
| jq '.Items[0:5] | .[] | {meterName: .meterName, unitPrice: .unitPrice}'
Best Practices
1. Handle Pagination
The API returns results in pages (default 100 items). Always check for NextPageLink:
all_items = []
next_url = initial_url
while next_url:
response = requests.get(next_url)
data = response.json()
all_items.extend(data['Items'])
next_url = data.get('NextPageLink')
2. Use Specific Filters
Narrow results with precise filters to reduce API calls and processing:
# Too broad (thousands of results)
$filter=serviceName eq 'Virtual Machines'
# Better (specific SKU and region)
$filter=serviceName eq 'Virtual Machines' and meterName eq 'D4s v3' and armRegionName eq 'eastus'
3. Cache Pricing Data
Pricing doesn't change frequently. Cache results to minimize API calls:
import json
from datetime import datetime, timedelta
import os
def get_cached_pricing(cache_file, service_name, region, cache_hours=24):
"""Get pricing from cache or API"""
cache_valid = False
if os.path.exists(cache_file):
cache_age = datetime.now() - datetime.fromtimestamp(os.path.getmtime(cache_file))
if cache_age < timedelta(hours=cache_hours):
cache_valid = True
if cache_valid:
with open(cache_file, 'r') as f:
return json.load(f)
else:
# Fetch from API
pricing_data = get_azure_pricing(service_name, region)
# Save to cache
with open(cache_file, 'w') as f:
json.dump(pricing_data, f)
return pricing_data
4. Compare Currency Codes
When comparing prices globally, ensure consistent currency:
# Specify currency code
curl -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "currencyCode='EUR'" \
--data-urlencode "\$filter=serviceName eq 'Virtual Machines' and armRegionName eq 'westeurope'"
5. Filter by Effective Date
Get current pricing by filtering out future-dated prices:
from datetime import datetime
current_date = datetime.now().isoformat()
filter_str = f"serviceName eq 'Virtual Machines' and effectiveStartDate le '{current_date}'"
6. Use Primary Meter Region
For consistent comparisons, filter by primary meter region:
curl -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "\$filter=serviceName eq 'Virtual Machines' and isPrimaryMeterRegion eq true"
Troubleshooting
Issue: Empty Results
Symptoms: API returns empty Items array
Solution:
- Verify service name spelling (case-sensitive)
- Check if service is available in specified region
- Simplify filter to broaden results
# Test with minimal filter
curl -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "api-version=2023-01-01-preview" \
--data-urlencode "\$filter=serviceName eq 'Virtual Machines'" \
| jq '.Items | length'
Issue: Timeout Errors
Symptoms: Request times out or takes too long
Solution:
- Add more specific filters to reduce result set
- Implement pagination handling
- Increase timeout value
response = requests.get(url, params=params, timeout=60) # 60 second timeout
Issue: Rate Limiting
Symptoms: HTTP 429 errors or throttling
Solution:
- Add delays between requests
- Implement exponential backoff
- Cache results to reduce API calls
import time
for page in range(num_pages):
response = requests.get(url)
# Process response
time.sleep(1) # 1 second delay between requests
Issue: Inconsistent Pricing Data
Symptoms: Prices don't match Azure Portal or calculator
Solution:
- Check
effectiveStartDate- may be future pricing - Verify
priceType(Consumption vs Reservation vs DevTest) - Confirm
isPrimaryMeterRegionis true - Check for promotional/discounted pricing in Portal
# Get only current consumption pricing in primary region
curl -G "https://prices.azure.com/api/retail/prices" \
--data-urlencode "\$filter=serviceName eq 'Virtual Machines' and priceType eq 'Consumption' and isPrimaryMeterRegion eq true" \
| jq '.Items[0]'
Next Steps
After exporting Azure pricing data:
-
Build Cost Estimation Tools: Create custom calculators
- TCO models for migration planning
- What-if analysis for architecture changes
- Multi-cloud pricing comparisons
-
Automate Budget Planning: Use pricing API in financial workflows
- Quarterly budget updates with current rates
- Cost projections based on planned deployments
- Reserve instance vs PAYG ROI calculations
-
Integrate with FinOps Platforms: Feed pricing data to cost management tools
- Import to spreadsheet models
- Populate cost databases
- Update rate cards in enterprise systems
-
Monitor Pricing Changes: Track price fluctuations over time
- Historical pricing analysis
- Alert on significant price changes
- Optimize based on regional pricing differences
-
Combine with Usage Data: Calculate actual costs
- See: How to Enable Cost Management Export to Azure Storage
- Join pricing with consumption metrics
- Build accurate cost attribution models
Related Resources
Frequently Asked Questions
Find answers to common questions
To manage pagination, continuously check for the 'NextPageLink' in the API response. Start by making your initial request, then append the 'NextPageLink' to your base URL for subsequent calls. For example, in Python, you can use a loop to keep fetching data until 'NextPageLink' is absent. This ensures that all pricing records are retrieved without missing any data. Be mindful of rate limits, and consider implementing delays between requests to avoid throttling.
Need Professional Help?
Our team of experts can help you implement and configure these solutions for your organization.