PAYATHON 2026

Azure API 获取当前费用、资源实际成本和 Billing cycle

支付阿杰

结论

可以直接通过 Azure Cost Management API 查询订阅中已经入账的费用,并按资源汇总,不需要结合 RateCard 与 Utilization API 自行复算价格。常用接口包括:

  • Cost Management Query API:按订阅、资源组、资源等维度查询 ActualCost 或 AmortizedCost。
  • Cost Management Exports / Cost Details:适合批量获取明细、定期导出和财务对账。

计算月度成本时,不建议先获取 Billing cycle,再自行套用阶梯价格。Cost Management Query API 支持 MonthToDate、BillingMonthToDate 等时间范围,Azure 会根据实际计费规则处理阶梯价格、免费额度、折扣和计费周期。

这些接口返回的是 Azure 计费系统已经处理并入账的数据,并非完全实时的瞬时费用。新产生的使用量通常会有一定延迟,具体取决于服务和计费协议。

查询每个资源的实际成本

可以调用订阅范围的 Cost Management Query API:

POST https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.CostManagement/query?api-version=2023-03-01
Authorization: Bearer {access-token}
Content-Type: application/json

请求体示例:

{
  "type": "ActualCost",
  "timeframe": "MonthToDate",
  "dataset": {
    "granularity": "None",
    "aggregation": {
      "totalCost": {
        "name": "Cost",
        "function": "Sum"
      }
    },
    "grouping": [
      {
        "type": "Dimension",
        "name": "ResourceId"
      }
    ]
  }
}

响应通常由列定义和行数据组成:

{
  "properties": {
    "columns": [
      {
        "name": "Cost",
        "type": "Number"
      },
      {
        "name": "ResourceId",
        "type": "String"
      },
      {
        "name": "Currency",
        "type": "String"
      }
    ],
    "rows": [
      [
        18.42,
        "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/demo-rg/providers/Microsoft.Compute/virtualMachines/vm01",
        "USD"
      ]
    ]
  }
}

实际代码不应依赖固定的数组位置。应先读取 properties.columns,再根据列名解析 rows 中的数据,因为不同的查询条件可能改变列顺序。

使用 Azure CLI 获取访问令牌

先登录 Azure,并获取 ARM 访问令牌:

az login
az account set --subscription "<subscription-id>"

ACCESS_TOKEN=$(az account get-access-token \
  --resource https://management.azure.com/ \
  --query accessToken \
  --output tsv)

然后调用查询接口:

curl --request POST \
  "https://management.azure.com/subscriptions/<subscription-id>/providers/Microsoft.CostManagement/query?api-version=2023-03-01" \
  --header "Authorization: Bearer ${ACCESS_TOKEN}" \
  --header "Content-Type: application/json" \
  --data '{
    "type": "ActualCost",
    "timeframe": "MonthToDate",
    "dataset": {
      "granularity": "None",
      "aggregation": {
        "totalCost": {
          "name": "Cost",
          "function": "Sum"
        }
      },
      "grouping": [
        {
          "type": "Dimension",
          "name": "ResourceId"
        }
      ]
    }
  }'

如需查看每日 burn rate,可以把粒度改为 Daily:

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

也可以同时按日期和资源汇总:

{
  "type": "ActualCost",
  "timeframe": "MonthToDate",
  "dataset": {
    "granularity": "Daily",
    "aggregation": {
      "totalCost": {
        "name": "Cost",
        "function": "Sum"
      }
    },
    "grouping": [
      {
        "type": "Dimension",
        "name": "ResourceId"
      }
    ]
  }
}

ActualCost 与 AmortizedCost 的区别

ActualCost 更接近账单的实际记账方式。例如,Reservation 或 Savings Plan 的购买费用可能集中计入购买日期。

AmortizedCost 会将预付或承诺类费用分摊到实际使用期间,通常更适合分析资源的日常成本:

{
  "type": "AmortizedCost",
  "timeframe": "MonthToDate",
  "dataset": {
    "granularity": "None",
    "aggregation": {
      "totalCost": {
        "name": "Cost",
        "function": "Sum"
      }
    },
    "grouping": [
      {
        "type": "Dimension",
        "name": "ResourceId"
      }
    ]
  }
}

如果要与发票或账单的记账结果核对,通常先查看 ActualCost。如果要衡量某个资源在一段时间内实际消耗的成本,通常还要查看 AmortizedCost。两者的含义不同,数值也不一定相等。

Billing cycle 的处理方式

如果只需查询当前计费周期的成本,最好让 Cost Management API 直接处理时间边界:

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

BillingMonthToDate 能否用于具体范围和账户类型,应以订阅对应的 Azure 计费协议及 API 返回结果为准。如果当前场景不支持该时间范围,可以使用 MonthToDate,也可以传入明确的自定义起止时间:

{
  "type": "ActualCost",
  "timeframe": "Custom",
  "timePeriod": {
    "from": "2026-08-01T00:00:00Z",
    "to": "2026-08-29T23:59:59Z"
  },
  "dataset": {
    "granularity": "Daily",
    "aggregation": {
      "totalCost": {
        "name": "Cost",
        "function": "Sum"
      }
    }
  }
}

Azure 曾提供 Billing Periods 相关接口,但接口的可用性和返回范围取决于订阅所属的计费协议。Enterprise Agreement、Microsoft Customer Agreement 和其他账户类型之间并不完全一致,因此不能把某个 Billing Periods 接口当作适用于所有订阅的统一方案。

如果必须获取正式账期,应先确认订阅对应的以下信息:

  • Billing account
  • Billing profile
  • Invoice section
  • 计费协议类型

确认后,再通过 Microsoft Billing API 查询相应的 billing profile、invoice 或 billing period 信息。对于 Microsoft Customer Agreement,通常更适合根据 billing profile 和 invoice 数据判断账期,而不是只从 subscription 本身推导。

为什么不建议继续用 RateCard 自行计算

结合 RateCard 和使用量得到的结果很难稳定复现最终账单,主要有以下原因:

  • 阶梯价格需要累计同一计费周期内的使用量。
  • 免费额度可能按订阅、账户、服务或计量项累计。
  • Reservation、Savings Plan、Azure Hybrid Benefit 等会改变有效成本。
  • Enterprise Agreement 或 Microsoft Customer Agreement 可能包含协商价格。
  • Credits、refund、adjustment、tax 和 marketplace charge 不一定能通过公开单价推导。
  • 部分费用无法准确归属到单个 Azure Resource ID。
  • 用量记录时间、价格生效时间和最终入账时间可能不同。

RateCard 更适合估算价格,Cost Management 数据则适合查询已经计算完成的实际成本。

注意事项

  • Cost Management 数据存在入账延迟,不能作为实时计量接口使用。
  • 某些费用的 ResourceId 可能为空,例如购买项、支持费用、退款或无法分配到单个资源的费用。
  • 删除资源后,该资源仍可能出现在后续成本数据中,因为费用记录不会随资源一起删除。
  • Marketplace、税费、credits 和 adjustments 是否包含在查询结果中,取决于查询范围、数据集类型和计费协议。
  • 查询大量数据时需要处理分页信息,不能假设一次响应会返回全部记录。
  • 调用身份需要拥有相应范围的 Cost Management 读取权限,例如 Cost Management Reader。仅有普通资源读取权限时,不一定能够查看成本。
  • Portal 中显示的金额可能经过筛选、舍入、币种转换或权限裁剪。要准确对比 API 查询结果,必须使用相同的范围、时间段、成本类型和筛选条件。
  • API 版本会持续更新。生产环境应使用 Azure 当前文档中该接口支持的稳定版本,不要在未经验证的情况下直接替换版本号。

备注:内容仅供参考。