PAYATHON 2026

如何获取 Azure Subscription 的 Billing Cycle 日期

支付小周

结论

仅靠旧版 Microsoft.Commerce/UsageAggregates 和 RateCard API,无法可靠获取订阅当前账单周期的开始和结束日期。这两个 API 分别用于查询用量和价格,不返回账单周期。

如果要计算当前账单周期内尚未结算的费用,建议使用 Azure Cost Management Query API,并将 timeframe 设为 BillingMonthToDate,不必自行推算周期日期。

如果需要明确的起止日期,应从订阅所属的计费账户、账单配置文件或发票周期中查询。具体使用哪个接口,取决于订阅采用的计费协议,例如 Microsoft Customer Agreement、Enterprise Agreement 或旧式 Microsoft Online Services Program。

直接查询当前账单周期费用

调用 Cost Management Query API:

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": "BillingMonthToDate",
  "dataset": {
    "granularity": "None",
    "aggregation": {
      "totalCost": {
        "name": "Cost",
        "function": "Sum"
      }
    }
  }
}

如需查看每日费用,可改为:

{
  "type": "ActualCost",
  "timeframe": "BillingMonthToDate",
  "dataset": {
    "granularity": "Daily",
    "aggregation": {
      "totalCost": {
        "name": "Cost",
        "function": "Sum"
      }
    }
  }
}

BillingMonthToDate 查询的是 Azure 识别的当前计费月份,比按自然月手动设置 reportedStartTime 和 reportedEndTime 更合适。

如需包含已经产生、但可能尚未计入最终发票的费用,可以根据账户类型和业务含义选择:

"type": "ActualCost"

或:

"type": "AmortizedCost"

AmortizedCost 会把预留实例、Savings Plan 等部分预付费用按使用周期摊销,因此不能直接视为最终应付金额。

获取明确的账单周期日期

账单周期通常属于计费账户或账单配置文件,而不是订阅本身。可以按以下步骤处理:

  1. 确认订阅采用的计费协议及其计费账户。
  2. 获取订阅与 billing account、billing profile 或 invoice section 的关联关系。
  3. 查询相应计费范围的账单周期或发票信息。
  4. 从返回结果中读取周期的开始和结束日期。
  5. 使用该日期范围查询 Cost Management 数据。

对于支持 Azure Billing API 的账户,可以在 Microsoft.Billing 提供程序下查询 billing periods 或 invoices。部分账户和 API 版本支持类似下面的资源路径:

GET https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{billingAccountName}/billingPeriods?api-version={supported-api-version}

实际资源层级中可能还包含 billingProfiles 或 invoiceSections。应先通过 Billing API 列出当前身份可以访问的 billing accounts,再根据返回的账户结构选择接口。不能假设所有订阅都支持同一条 URL。

旧式订阅曾提供订阅级 billing periods 预览接口,例如:

GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Billing/billingPeriods?api-version=2018-03-01-preview

这是旧预览模型中的接口,不适合作为新系统的通用实现。它是否仍适用于某个订阅,应以该订阅当前支持的资源提供程序和 API 版本为准。

C# 查询当前账单周期费用示例

下面的代码主要展示请求结构。身份验证和错误处理需要接入应用已有的实现:

using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

string url =
    $"https://management.azure.com/subscriptions/{subscriptionId}" +
    $"/providers/Microsoft.CostManagement/query?api-version={apiVersion}";

string requestBody = """
{
  "type": "ActualCost",
  "timeframe": "BillingMonthToDate",
  "dataset": {
    "granularity": "None",
    "aggregation": {
      "totalCost": {
        "name": "Cost",
        "function": "Sum"
      }
    }
  }
}
""";

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", accessToken);

using var content = new StringContent(
    requestBody,
    Encoding.UTF8,
    "application/json");

HttpResponseMessage response = await client.PostAsync(url, content);
string responseBody = await response.Content.ReadAsStringAsync();

response.EnsureSuccessStatusCode();
Console.WriteLine(responseBody);

不要假设金额列在返回行中的位置固定。应先读取响应里的 properties.columns,根据列名确定 Cost、Currency 等字段的位置,再解析 properties.rows。

如果必须继续使用 Usage API

使用 UsageAggregates 时,应用必须自行提供 reportedStartTime 和 reportedEndTime。这些日期可以取自 Billing API 返回的账单周期,但不建议直接使用每月 1 日至月末,原因包括:

  • 账单周期不一定与自然月完全一致。
  • 周期可能由计费账户或 billing profile 决定。
  • 时间字段通常按 UTC 处理,换算为本地时区时可能出现一天的边界误差。
  • 延迟上报的用量可能在查询完成后继续出现。
  • Usage API 计算的估算金额不等于最终发票金额。

示例中的变量名与 URL 内容恰好相反:requestRateCardAPIurl 实际指向 UsageAggregates,requestUsageAPIurl 实际指向 RateCard。建议修改变量名,以免后续混淆价格数据和用量数据。

注意事项

当前周期费用只能作为估算或累计成本,通常无法保证与最终发票完全一致。税费、抵扣、Azure Credit、退款、舍入、预留折扣、第三方 Marketplace 费用和延迟到达的用量,都可能使结算金额发生变化。

调用者除了需要订阅权限,还可能需要计费范围或成本管理数据的读取权限。即使可以读取订阅资源,也未必可以读取 billing account、发票或成本数据。

备注:内容仅供参考。