PAYATHON 2026

WSO2 APIM 如何与 billing engine 集成并同步 usage plan

支付小周

结论

“sample billing engine”通常是用于演示 WSO2 API Manager(APIM)货币化扩展点的参考实现。它不是面向 API Subscriber 的正式门户,也不适合直接用于生产环境。页面要求登录很正常,因为计费计划、价格和账单配置都属于受保护的管理操作。

Subscriber 应在 APIM Developer Portal 中选择 subscription policy。旧版文档可能将其称为 throttling tier 或 usage plan,而不是进入 billing engine 手工定义计划。

billing engine 仍然需要配置 billing plan,是因为 APIM policy 和计费系统中的 plan 是两类不同的对象:

  • APIM policy 负责请求配额、限流和订阅权限。
  • Billing plan 负责价格、币种、计费周期、税费、折扣、试用期和账单。
  • 两者需要建立映射,但 Subscriber 不应重复配置。

在生产环境中,数据通常由自定义 monetization connector、事件处理服务或定时对账任务同步。只部署 sample billing engine,一般无法获得完整的生产级同步能力。

正确的业务流程

整个集成可以拆成三条独立的数据链路:

  1. 计划目录同步

    Publisher 在 APIM 中创建或更新 subscription policy 后,将对应的计费产品和价格同步到 billing engine。

  2. 订阅生命周期同步

    Subscriber 在 Developer Portal 中选择 policy 并订阅 API。集成服务根据这次操作,在 billing engine 中创建、变更或取消 billing subscription。

  3. 实际用量同步

    APIM Gateway 或 Analytics 汇总实际调用量,并按计费周期发送给 billing engine。billing engine 再根据价格模型生成账单。

典型流程如下:

Publisher
   │
   ├─ 创建 APIM subscription policy
   │
   └─ 创建或映射 billing plan
                     │
Subscriber           │
   │                 │
   └─ 在 Devportal 订阅 API
          │
          ▼
     APIM Subscription
          │
          ▼
  Integration Service
          │
          ├─ customer mapping
          ├─ plan mapping
          └─ create/update/cancel billing subscription
                     │
                     ▼
               Billing Engine

Gateway / Analytics
          │
          └─ aggregated usage ──► Billing Engine

为什么需要两套计划

假设 APIM 中有以下 policy:

Policy name: Gold
Quota: 100000 requests/month
Burst limit: 100 requests/second

计费系统中可能需要保存这些信息:

External plan ID: price_gold_cny_monthly
Currency: CNY
Billing period: monthly
Base fee: 999.00
Included usage: 100000 requests
Overage price: 0.01 CNY/request
Tax behavior: exclusive

APIM 执行 100000 requests/month 之类的访问规则,但它本身并不包含税率、付款方式或开票规则。billing engine 负责收费,却通常无法代替 Gateway 执行限流。

因此,两个系统中同名的“Gold”只是业务上的对应关系,并不是同一个数据对象。生产集成必须保存稳定的 ID 映射,不能只按显示名称关联。

例如:

CREATE TABLE billing_plan_mapping (
    apim_policy_id       VARCHAR(128) NOT NULL,
    apim_policy_name     VARCHAR(128) NOT NULL,
    billing_plan_id      VARCHAR(128) NOT NULL,
    currency             VARCHAR(3)   NOT NULL,
    mapping_version      INTEGER      NOT NULL,
    updated_at           TIMESTAMP    NOT NULL,
    PRIMARY KEY (apim_policy_id, currency)
);

如何实现自动同步

1. 先确定唯一标识

至少需要维护以下映射:

APIM tenant/domain        -> Billing account
APIM application ID      -> Billing customer ID
APIM subscription ID     -> Billing subscription ID
APIM subscription policy -> Billing plan/price ID
API or API product ID    -> Billing product ID

不要使用用户名、API 名称或 policy 显示名称作为唯一键。这些字段可能被修改,也可能在不同 tenant 中重复。

2. 同步计费计划

Publisher 发布可货币化的 policy 后,管理服务在 billing engine 中创建对应的 plan,并保存返回的外部 ID。

下面是示意性的内部接口,并不表示某个 WSO2 版本提供了完全相同的 URL:

POST /internal/monetization/plans
Content-Type: application/json
Authorization: Bearer <service-token>
Idempotency-Key: apim-policy-8f27-v3
{
  "apimPolicyId": "8f27",
  "name": "Gold",
  "quota": {
    "unit": "request",
    "limit": 100000,
    "period": "month"
  },
  "price": {
    "currency": "CNY",
    "baseAmount": "999.00",
    "includedUnits": 100000,
    "overageUnitAmount": "0.01"
  }
}

计费系统返回:

{
  "billingPlanId": "price_gold_cny_monthly",
  "status": "active"
}

能否从 APIM policy 自动推导价格,取决于具体的业务模型。限流额度可以同步,价格、税费和折扣通常仍由财务或运营系统维护。

3. 同步 Subscriber 的选择

APIM 成功创建订阅后,集成服务读取 subscription ID、application ID、API ID 和 policy ID,再通过映射表找到对应的 billing plan。

示意事件如下:

{
  "eventType": "SUBSCRIPTION_CREATED",
  "eventId": "evt-01JABC123",
  "tenant": "carbon.super",
  "subscriptionId": "sub-72d9",
  "applicationId": "app-1842",
  "apiId": "api-f8e1",
  "policyId": "8f27",
  "subscriberId": "user-913"
}

处理逻辑可以写成:

public void handleSubscriptionCreated(SubscriptionEvent event) {
    if (eventRepository.wasProcessed(event.eventId())) {
        return;
    }

    CustomerMapping customer =
        customerMappingRepository.findByApplicationId(event.applicationId());

    PlanMapping plan =
        planMappingRepository.findByPolicyId(event.policyId());

    BillingSubscription result = billingClient.createSubscription(
        customer.billingCustomerId(),
        plan.billingPlanId(),
        event.subscriptionId()
    );

    subscriptionMappingRepository.save(
        event.subscriptionId(),
        result.id()
    );

    eventRepository.markProcessed(event.eventId());
}

这部分必须支持幂等处理。APIM 或消息系统可能会重试事件。如果没有 eventId、subscriptionId 或 idempotency key,billing engine 中可能出现重复订阅。

4. 处理变更和取消

同步范围不能只有创建操作,至少要覆盖:

SUBSCRIPTION_CREATED
SUBSCRIPTION_POLICY_CHANGED
SUBSCRIPTION_BLOCKED
SUBSCRIPTION_UNBLOCKED
SUBSCRIPTION_DELETED
APPLICATION_DELETED

具体的事件名称和获取方式取决于 WSO2 APIM 版本。部分版本可以通过扩展点或事件机制接入。如果目标版本没有合适的事件,也可以通过 APIM REST API 定时拉取订阅状态,进行增量对账。

变更 policy 时,还要明确以下计费规则:

  • 升级立即生效,还是到下个账期生效;
  • 是否按比例计费;
  • 降级后如何处理已经使用的额度;
  • APIM 更新成功但 billing engine 更新失败时,是否暂时阻止调用。

这些都属于业务规则,不能仅靠字段同步解决。

实际用量如何进入 billing engine

“订阅了哪个 plan”和“实际用了多少”是两件不同的事。即使订阅已经同步,按量计费仍然需要单独上报 usage。

比较稳妥的做法是先在 APIM 侧聚合,再发送计费数据:

{
  "subscriptionId": "sub-72d9",
  "billingPeriod": "2026-08",
  "metric": "api_request",
  "quantity": 126430,
  "from": "2026-08-01T00:00:00Z",
  "to": "2026-09-01T00:00:00Z"
}

不要默认将每一次 Gateway 请求实时发送给 billing engine。这种方式容易造成性能瓶颈、重复计费和较高的网络开销。更稳妥的方案是按小时或按天聚合,并使用可以重复计算的复合键,例如:

subscriptionId + metric + periodStart + periodEnd

计费系统应支持幂等覆盖,或者拒绝重复记录。

还要注意,APIM 的限流计数不一定等于最终的可计费用量。失败请求、缓存命中、重试、内部调用,以及被 Gateway 拒绝的请求是否收费,都需要提前定义。

关于登录和找不到 URL

示例中的管理页面通常需要认证,因为这些页面涉及价格和账单配置。Subscriber 不应直接访问此类管理 URL。

如果文档中的 URL 在本地环境中不存在,常见原因有:

  • 文档对应的 WSO2 APIM 版本与本地版本不同;
  • sample billing engine 是单独部署的示例组件,没有包含在 APIM 默认部署中;
  • 示例应用的 context path、端口或反向代理路径发生了变化;
  • 目标版本已经改用 REST API、扩展实现或其他货币化方案;
  • 当前用户缺少相应的管理角色或 scope。

不要根据旧文章中的路径猜测 URL。应以当前 APIM 版本附带的 OpenAPI/Swagger 文档、产品文档和部署配置为准。不同版本使用的 Publisher API、Devportal API、认证 scope 和扩展接口可能并不相同。

生产环境建议

sample billing engine 适合用于验证概念。正式环境更适合增加一层独立的 monetization integration service,由它负责:

  • 调用 APIM API 获取 policy 和 subscription;
  • 调用 billing provider API;
  • 保存 APIM ID 与外部计费 ID 的映射;
  • 处理认证、重试、幂等和死信;
  • 汇总并上报 usage;
  • 执行周期性全量对账;
  • 记录审计日志和同步状态。

同步状态至少可以包含:

PENDING
ACTIVE
UPDATE_PENDING
CANCEL_PENDING
FAILED
SUSPENDED

关键操作可以采用“事件同步 + 定时对账”的组合。事件同步用于降低延迟,定时任务则用于修复漏发事件、临时网络故障和人工修改造成的数据偏差。

billing engine 创建失败后,不能让这一状态处于不可见状态。如果 APIM 订阅已经生效,而计费订阅创建失败,系统可能允许用户免费调用。生产实现应根据业务要求回滚 APIM 订阅、暂时阻止订阅,或者将其转入一个明确且可监控的待处理状态。

备注:内容仅供参考。