PAYATHON 2026

Azure Invoices - List By Billing Subscription 请求为何返回 404?

支付阿杰

结论

这个 404 通常不是普通的 Azure RBAC 权限问题。更可能的原因是请求路径中的资源标识有误,或者当前计费账户类型不支持该接口。

需要检查以下几点:

  1. billingSubscriptionName 不是 Azure Subscription 的名称,通常也不是 Azure Subscription GUID。它应当是 Microsoft Billing 资源中 billing subscription 的 name。
  2. billingAccountName 必须使用 Billing API 返回的资源名称,不能使用门户中的账户显示名称,也不能使用未经确认的属性值。
  3. 示例中的日期参数顺序有误:periodStartDate=2022-06-30 晚于 periodEndDate=2022-06-01。
  4. Invoices - List By Billing Subscription 只适用于该 API 支持的计费协议类型。个人订阅、传统 Pay-As-You-Go 和部分 Enterprise Agreement 账户,即使订阅 Owner 拥有者权限,也未必能调用这个路径。
  5. Azure Subscription 的 Owner 与计费范围中的 Billing Reader 属于两套不同的授权体系。计费权限必须授予到请求所指向的 billing account 或相应计费范围。

正确获取资源名称

不要根据门户中的显示名称拼接 URL。先通过 Billing API 列出当前用户可以访问的计费账户:

GET https://management.azure.com/providers/Microsoft.Billing/billingAccounts?api-version=2019-10-01-preview
Authorization: Bearer <access-token>

从响应中读取计费账户资源的 name:

{
  "value": [
    {
      "id": "/providers/Microsoft.Billing/billingAccounts/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "name": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "type": "Microsoft.Billing/billingAccounts"
    }
  ]
}

这里的 name 才是请求中的 billingAccountName。某些计费协议下的名称可能包含多个部分或特殊字符,应原样使用,并在构造 URL 时进行必要的 URL 编码。

接着列出该账户下的 billing subscriptions:

GET https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{billingAccountName}/billingSubscriptions?api-version=2019-10-01-preview
Authorization: Bearer <access-token>

假设响应如下:

{
  "value": [
    {
      "id": "/providers/Microsoft.Billing/billingAccounts/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/billingSubscriptions/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
      "name": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
      "type": "Microsoft.Billing/billingAccounts/billingSubscriptions",
      "properties": {
        "displayName": "Production Subscription"
      }
    }
  ]
}

此时应使用顶层的:

name = yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy

作为 billingSubscriptionName,不要使用:

properties.displayName

也不要直接认定它等于门户中的 Azure Subscription ID。即使这两个值在某种账户类型下恰好相同,仍应以 Billing API 返回的 name 为准。

修正日期参数

原请求中的日期顺序为:

periodEndDate=2022-06-01
periodStartDate=2022-06-30

开始日期晚于结束日期,应改为:

periodStartDate=2022-06-01
periodEndDate=2022-06-30

完整请求示例:

GET https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{billingAccountName}/billingSubscriptions/{billingSubscriptionName}/invoices?api-version=2019-10-01-preview&periodStartDate=2022-06-01&periodEndDate=2022-06-30
Authorization: Bearer <access-token>

日期必须采用 YYYY-MM-DD 格式,并满足:

periodStartDate <= periodEndDate

查询区间还应覆盖已经产生发票的账期。如果日期正确,但区间内没有发票,正常结果通常是空集合。具体响应仍取决于账户类型和该预览版 API 的实现。

为什么 Owner 或 Billing Reader 仍可能返回 404

Azure Subscription Owner 主要控制订阅资源,例如虚拟机、网络和存储,不会自动获得计费账户数据的访问权限。

Billing Reader 也必须授予在正确的计费范围上。例如,请求路径访问的是:

/providers/Microsoft.Billing/billingAccounts/{billingAccountName}

调用者就必须能够访问这个 billing account 及其对应的 billing subscription。最直接的验证方法不是查看角色名称,而是执行前面的两个列表请求:

  • 如果无法列出目标 billing account,说明登录租户、账户关系或计费权限不匹配。
  • 如果能列出 billing account,却无法列出目标 billing subscription,可能是该资源不属于这个账户、使用了错误的标识,或者授权范围不足。
  • 如果两者都能列出,就把响应中的 name 原样填入发票请求。

部分 Azure Billing API 会在计费资源不存在或调用者不可见时返回 404,而不是明确的 403。因此,不能简单地把 404 理解为 URL 本身不存在。

检查计费协议类型

该路径不适用于所有 Azure 订阅。需要检查 billing account 响应中的协议类型,例如:

{
  "properties": {
    "agreementType": "MicrosoftCustomerAgreement"
  }
}

Invoices - List By Billing Subscription 主要用于具有 billing subscription 层级的计费模型,例如 Microsoft Customer Agreement。具体支持范围应以所用 API 版本的官方说明为准。

如果账户采用其他协议,例如传统个人订阅或某些 Enterprise Agreement 结构,其资源层级可能是 enrollment account、billing profile 或 invoice section,而不是该接口要求的 billing subscription。这种情况下,不能只替换一个 ID 继续调用该接口,而应改用与实际计费协议和资源层级对应的 Invoices API。

建议的排查顺序

  1. 确认访问令牌所属 tenant 与计费账户所在 tenant 一致。
  2. 调用 billingAccounts 列表接口,复制响应中的 name。
  3. 调用该账户的 billingSubscriptions 列表接口,复制目标对象的 name。
  4. 检查 billing account 的 agreementType 是否支持该操作。
  5. 确认 Billing Reader 等计费角色授予在正确的计费范围,而不只是在 Azure Subscription 上。
  6. 将日期调整为开始日期早于或等于结束日期。
  7. 使用已经确认的两个 name 重新构造请求。不要使用门户显示名称,也不要自行认定 Azure Subscription ID 就是 billingSubscriptionName。

这个请求至少有一个明确问题,即日期顺序错误。至于 404,更常见的原因是把 Azure Subscription ID 当成了 billingSubscriptionName,或者计费账户并不支持该接口要求的资源层级。

备注:内容仅供参考。