如何使用 Azure Billing API 获取订阅的总账单金额
结论
不需要再通过 RateCard × Usage 手工计算。指定订阅和时间范围后,可以使用 Azure Cost Management Query API 对 PreTaxCost 求和,直接得到类似 500 USD 的汇总金额。
这里需要区分两类金额:
- 订阅成本汇总:通过 Cost Management Query API 获取,适合展示当月累计成本或指定期间的成本。
- 最终应付账单:通过 Azure Billing Invoices API 查询已结算的发票。发票通常归属于 billing account、billing profile 或 invoice section,不一定与单个 subscription 一一对应。
Microsoft.Commerce/UsageAggregates 和 RateCard 是较早的预览接口,主要用于获取用量和费率明细,不适合用于新的账单汇总实现。
查询订阅的成本总额
将请求范围设置为 subscription,并且只配置一项求和聚合:
POST https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.CostManagement/query?api-version={supported-api-version}
Authorization: Bearer {access-token}
Content-Type: application/json
请求体示例:
{
"type": "ActualCost",
"timeframe": "Custom",
"timePeriod": {
"from": "2026-08-01T00:00:00Z",
"to": "2026-08-29T23:59:59Z"
},
"dataset": {
"granularity": "None",
"aggregation": {
"totalCost": {
"name": "PreTaxCost",
"function": "Sum"
}
}
}
}
配置时需要注意:
- 将
granularity设为None,避免返回每日明细。 - 不设置
grouping,避免按资源、meter 或服务拆分结果。 - 对
PreTaxCost使用Sum,由服务端完成汇总。 type设为ActualCost时,查询的是实际成本。部分计费协议还支持AmortizedCost,可按使用期间摊销预留实例等费用。
返回结果通常包含列定义和一行汇总数据,例如:
{
"properties": {
"columns": [
{
"name": "PreTaxCost",
"type": "Number"
},
{
"name": "Currency",
"type": "String"
}
],
"rows": [
[
500.0,
"USD"
]
]
}
}
代码应根据 columns 确定各字段的位置,不宜一直假设金额位于第 0 列。
C# 示例
下面的代码会提交聚合查询,再按列名读取金额和币种。请将 apiVersion 替换为当前环境支持的 Cost Management Query API 版本。
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public static async Task<(decimal Amount, string Currency)> GetSubscriptionCostAsync(
string subscriptionId,
string accessToken,
DateTimeOffset from,
DateTimeOffset to,
string apiVersion)
{
string requestUrl =
$"https://management.azure.com/subscriptions/{subscriptionId}" +
$"/providers/Microsoft.CostManagement/query?api-version={apiVersion}";
var requestBody = new
{
type = "ActualCost",
timeframe = "Custom",
timePeriod = new
{
from = from.UtcDateTime.ToString("O"),
to = to.UtcDateTime.ToString("O")
},
dataset = new
{
granularity = "None",
aggregation = new
{
totalCost = new
{
name = "PreTaxCost",
function = "Sum"
}
}
}
};
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
string json = JsonSerializer.Serialize(requestBody);
using var response = await client.PostAsync(
requestUrl,
new StringContent(json, Encoding.UTF8, "application/json"));
string responseBody = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
using JsonDocument document = JsonDocument.Parse(responseBody);
JsonElement properties = document.RootElement.GetProperty("properties");
JsonElement columns = properties.GetProperty("columns");
JsonElement rows = properties.GetProperty("rows");
if (rows.GetArrayLength() == 0)
{
return (0m, string.Empty);
}
string[] columnNames = columns
.EnumerateArray()
.Select(column => column.GetProperty("name").GetString() ?? string.Empty)
.ToArray();
int costIndex = Array.FindIndex(
columnNames,
name => string.Equals(name, "PreTaxCost", StringComparison.OrdinalIgnoreCase));
int currencyIndex = Array.FindIndex(
columnNames,
name => string.Equals(name, "Currency", StringComparison.OrdinalIgnoreCase));
if (costIndex < 0)
{
throw new InvalidOperationException(
"Cost Management response does not contain PreTaxCost.");
}
JsonElement row = rows[0];
decimal amount = row[costIndex].GetDecimal();
string currency = currencyIndex >= 0
? row[currencyIndex].GetString() ?? string.Empty
: string.Empty;
return (amount, currency);
}
调用示例:
var result = await GetSubscriptionCostAsync(
subscriptionId,
accessToken,
new DateTimeOffset(2026, 8, 1, 0, 0, 0, TimeSpan.Zero),
new DateTimeOffset(2026, 8, 29, 23, 59, 59, TimeSpan.Zero),
apiVersion);
Console.WriteLine($"{result.Amount:N2} {result.Currency}");
如果需要最终发票金额
Cost Management 返回的是成本数据,不能直接视为信用卡或银行账户的最终扣款金额。如果要查询“这张账单最终需要支付多少”,应使用 Azure Billing 的发票资源。
一张发票可能包含:
- 多个 subscriptions;
- 税费;
- 抵扣额或 Azure credits;
- Marketplace 费用;
- 调整项;
- 上期余额;
- 不同 invoice section 下的费用。
因此,发票总额通常不能直接作为某个 subscription 的总额。如果一张发票覆盖多个订阅,就需要根据成本明细或 invoice section 进行归集。只有计费结构明确为一张发票对应一个订阅时,才能直接将发票金额用于该订阅。
权限与数据时效
调用 API 前还要确认以下事项:
- 调用方必须拥有读取 subscription 成本数据的权限。仅有资源读取权限,不一定能查看成本。
- 企业协议、Microsoft Customer Agreement、合作伙伴订阅等计费模式可能采用不同的权限模型。
- 当月成本通常存在入账延迟,并非严格的实时数据。
PreTaxCost一般不含税费,而最终发票金额可能包含税费和调整项。- 免费额度、抵扣、预留实例、Savings Plan、退款和 Marketplace 项目,都可能导致成本汇总与实际付款额不同。
- 应使用 API 返回的
Currency,不要根据 RateCard 请求中的币种自行推断。 - 不应继续以早期的
Microsoft.Commerce/UsageAggregates和RateCard预览接口作为新实现的基础。
如果只是展示“该订阅本月累计成本”,使用 Cost Management Query API 执行无粒度、无分组的聚合查询即可。如果需要财务意义上的最终应付金额,则应通过 Billing Invoices API 获取已结算发票。
备注:内容仅供参考。
