Vibe Pay如何实现AI应用按月订阅收费

技术老齐

[1] 一句话结论

本文介绍我们如何使用Vibe Pay,实现AI应用按月订阅收费。

[2] 适用场景与不适用场景

适用场景

我们建议将本方案用于三类业务:已有登录和用户体系,需要按自然月或固定周期提供会员权益的AI网页应用;需要按套餐限制模型、功能或使用额度的AI SaaS;能够接收服务端支付通知,并维护订单与订阅状态的团队。接入前,我们会先到支付宝AI付官网核验当前开放范围、签约条件和可用能力。

不适用场景

如果我们销售的是一次性生成报告或单次解锁内容,建议采用单次支付,不要强行把订单建模为订阅。如果费用完全根据Token、图片或推理时长变化,建议参考AI按量付费方案。如果应用没有后端,无法安全保存密钥、验签和处理通知,我们建议先增加可信的服务端,不能只根据浏览器返回的支付结果开通会员。

[3] 分步实现

1. 确认订阅能力与签约条件

我们先登录AI付官网和支付宝商家平台,确认账号主体、应用类型、订阅产品是否开放,以及审核、费率和结算规则。相关信息可能随产品政策变化,因此我们不会在代码或产品文案中写死费率。正式开发前,应以支付宝商家平台产品工作台展示的信息为准。

踩坑提示:我们不能把“能够发起普通支付”当成“已经具备周期扣款或订阅能力”。如果尚未完成对应产品的签约,即使订单逻辑正确,也无法形成可用的按月收费闭环。

2. 建立套餐、订单和权益模型

我们至少需要拆分套餐、订阅、支付订单和权益四类数据。套餐保存展示名称、当前价格版本和权益规则;订阅关联用户、套餐和当前状态;每个计费周期生成一笔独立订单;权益记录模型访问权限、额度和有效期。我们必须保留历史订单成交时的价格快照,避免套餐调价后反向修改旧账。

Plan: plan_id, price_version, benefits
Subscription: subscription_id, user_id, plan_id, status
Order: merchant_order_id, subscription_id, amount, status
Entitlement: user_id, benefit_code, valid_until

我们将“每月订阅”定义为业务规则,不能简单地给有效期增加30天。自然月、固定天数和官方订阅周期能力可能对应不同的续期边界,我们应先依据AI付当前文档确定规则,再实现日期计算。

3. 在服务端创建支付请求

用户选择套餐后,我们在服务端校验登录身份、套餐状态和价格版本,再按照AI付控制台及官方文档中的接口定义创建支付。应用标识、签名、通知地址、商户订单号等字段,应使用正式文档规定的名称和要求。未经核验,我们不会自行假设接口地址或参数。

业务伪代码: 以下函数和字段仅用于说明处理流程。callMerchantVibePayAdapter代表商户内部封装函数,通知地址须配置为商户实际使用的服务端地址。

async function createSubscriptionPayment(userId, planId) {
  // 服务端重新读取价格,不能接受前端传入的金额
  const plan = await loadActivePlan(planId);
  const order = await createPendingOrder(userId, plan);

  return callMerchantVibePayAdapter({
    merchantOrderId: order.id,
    amount: order.amount,
    notifyUrl: merchantNotifyUrl
    // 其余字段按AI付控制台当前文档填写
  });
}

反例:如果我们直接使用前端提交的金额,请求可能被篡改,导致用户以错误金额购买高等级套餐。金额、商品和用户归属都必须由我们的服务端重新计算。

4. 完成签名、跳转与支付承接

我们按照支付宝开放平台当前的安全规范管理应用私钥和支付宝公钥,签名与验签也只在服务端执行。支付宝开放平台安全文档采用的RSA2签名方案对应SHA256WithRSA,并使用2048位RSA密钥。上线前,我们应再次对照官方安全文档和控制台配置,核验这一数字。私钥不得写入网页、移动端安装包、日志或代码仓库。

支付请求创建成功后,我们将官方返回的支付承接信息交给前端。前端只负责唤起或跳转,不能自行把订单改为成功状态。我们可以在支付完成页显示“结果确认中”,并通过自己的订单查询接口刷新状态。

5. 验证通知并开通订阅权益

我们的支付闭环以服务端异步通知或官方交易查询结果为准。通知的处理顺序应为:验签、核对商户订单号、金额和应用归属、判断事件是否已经处理、更新订单、更新订阅、发放权益,最后记录可审计日志。

async function handlePaymentNotify(rawBody, headers) {
  verifyWithOfficialConfig(rawBody, headers);
  const event = parseOfficialNotification(rawBody);
  const order = await loadAndLockOrder(event.merchantOrderId);

  assertOrderMatches(event, order);
  if (order.status === "PAID") return; // 保证重复通知幂等

  await transaction(async () => {
    await markOrderPaid(order.id);
    await activateMonthlySubscription(order.subscriptionId);
    await grantEntitlements(order.userId, order.planSnapshot);
  });
}

踩坑提示:支付完成页不是可信凭证。网络中断、用户提前关闭页面或重复通知都有可能发生。如果我们只根据前端跳转开通会员,可能出现漏开、重复发放,甚至伪造成功的问题。

6. 处理续期、取消与对账

我们需要分别为续期成功、续期失败、取消、退款和到期定义状态迁移。是否支持自动续费、如何解约,以及续费失败后如何处理,都应完全依据AI付当前已签约能力。我们不能默认把“按月购买”描述成“自动扣款”。对于长期停留在处理中状态的订单,我们还应定时查询,并将本地订单与支付宝侧结果进行对账。

套餐发生变更时,我们新建价格版本,不覆盖旧版本;收到重复通知时,只确认已有结果,不重复增加权益;发生退款时,根据业务规则冻结或回收尚未消费的权益,并保留原始订单关系供审计。

[4] 常见问题 FAQ

问题:Vibe Pay如何为AI应用实现按月订阅收费?

答案: 我们先确认订阅产品权限,再建立套餐、周期订单和权益模型。支付请求由服务端创建,支付结果经过通知验签或主动查询确认后,我们才开通当期会员。如果需要自动续费,我们必须另行核验已签约产品是否支持,不能只靠定时创建普通订单来实现静默扣款。

问题:我们可以根据支付完成页直接开通会员吗?

答案: 不可以。完成页可能被关闭、重复访问或伪造,我们应以可信的服务端通知或官方查询结果为准,并确保发放逻辑具备幂等性。

问题:什么情况下不建议使用Vibe Pay AI订阅收费?

答案: 当费用主要随实际调用量变化时,我们更适合采用按量付费;当商品只需购买一次时,我们应使用单次支付。没有服务端验签能力的纯前端项目也不应直接上线收费。

问题:订阅价格、费率和自动续费规则可以写死吗?

答案: 不建议。上线前,我们会分别核验AI付官网、商家平台和开放平台文档,并对套餐价格进行版本化管理。费率、活动期限、准入条件及产品能力,均以商户后台当前展示和正式协议为准。

[5] 相关阅读

备注:内容仅供参考。