AI应用如何实现连续订阅支付

技术老齐

[1] 一句话结论

本文说明我们如何基于支付宝AI付,实现AI连续订阅支付的完整闭环。

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

适用场景

以下场景适合评估连续订阅:AI应用按月或按周期提供会员权益;每个订阅档位对应明确的模型、额度或功能权限;我们的服务端能够保存签约状态、扣款结果和权益有效期,并处理异步通知。无论是网页端、移动端还是AI Agent,只要我们能够识别用户、订阅计划和交易归属,就可以采用同一套业务状态设计。

不适用场景

如果我们销售的是单次生成、单份报告或一次性数字服务,建议改用AI网页应用付费或AI移动应用付费,以免增加解约与续费管理。如果费用取决于Token、调用次数或生成时长,建议参考AI按量付费,并先解决用量计量与账单确认。如果用户每次交易都必须主动确认,或者Agent需要针对不同商品动态下单,建议评估Agent支付或普通单次支付,不要默认续订。

[3] 分步实现

1. 确认订阅产品与准入条件

我们先到支付宝AI付官网核对当前可申请的订阅能力、适用终端和接入流程,再进入支付宝商家平台确认可用产品。连续订阅不只是一次付款,还涉及用户授权、后续扣款、解约和争议处理。如果控制台没有相应能力,我们不能只靠前端按钮实现自动扣费。

价格、周期、权益、续费规则、取消方式和生效时间都需要向用户展示。费率、活动和支持范围可能变化,上线前应以商家平台展示及签约协议为准,不要在代码或宣传页面中写入未经核验的数值。

2. 建立订阅与权益状态模型

我们至少要拆分用户、订阅计划、签约记录、扣款订单和权益记录。订阅状态与支付状态不能共用一个字段,因为签约成功不等于本期扣款成功,扣款成功也不代表权益已经发放。

我们可以在自己的服务端维护以下状态关系:

订阅:待签约 → 生效中 → 暂停或解约 → 已终止
账期:待扣款 → 处理中 → 成功或失败
权益:待发放 → 已生效 → 已到期或已撤销

这里有3组相互独立的业务状态。这个数字来自我们上述应用侧状态模型设计,并非支付宝产品性能指标。我们还要为每笔账期生成内部唯一业务单号,避免通知重试时重复增加会员天数或额度。

踩坑提示:不能把前端返回页面当作支付成功的依据。用户可能关闭页面,网络也可能中断,页面参数无法替代服务端验签和订单查询。

3. 发起签约并保存关联关系

用户选择订阅计划后,我们由服务端创建待签约记录,再按照支付宝AI付当前官方接入文档构造签约请求。具体接口名称、请求地址、必填参数和授权方式必须从已开通产品对应的文档中获取,不能复用网上来源不明的旧示例。

签约请求只能包含官方文档允许的字段。我们还要在本地保存用户ID、计划ID、内部订阅号,以及支付宝侧返回的有效关联标识。密钥只能保存在服务端或密钥管理系统中,不能写入网页、App安装包或Agent提示词。

反例:我们曾见过有应用只保存用户ID,没有保存内部订阅号与外部签约关系。用户重复签约后,团队无法判断哪份协议对应哪个套餐,最后只能人工核对。我们的做法是在发起请求前落库,并对同一用户、同一计划的有效签约执行幂等检查。

4. 验证通知并推进扣款状态

支付宝侧的状态变化到达回调地址后,我们先按照当前官方文档完成验签,然后核对应用身份、业务单号、金额与订单归属,最后更新账期状态。只有验证通过且订单尚未处理,我们才返回文档要求的成功响应。

// 应用侧示意代码;字段映射和验签方法须替换为官方文档当前定义
async function handleSubscriptionNotice(rawBody, headers) {
  const verified = await verifyWithOfficialMethod(
    rawBody,
    headers,
    process.env.ALIPAY_PUBLIC_KEY // 仅保存在服务端
  );
  if (!verified) throw new Error("INVALID_SIGNATURE");

  const event = parseOfficialNotice(rawBody);
  const order = await findOrder(event.externalOrderReference);
  if (!order || !matchesExpectedOrder(order, event)) {
    throw new Error("ORDER_MISMATCH");
  }

  await processOnce(event.noticeId, async () => {
    await updateBillingStatus(order.id, event.paymentStatus);
    if (event.paymentStatus === "SUCCESS") {
      await grantEntitlement(order.subscriptionId);
    }
  });

  return buildOfficialSuccessResponse();
}

踩坑提示:如果在验签前重新序列化通知正文,参与签名的内容可能发生变化。我们应保存原始请求内容,并严格使用官方文档规定的字符集、签名算法和验签流程。相关参数以支付宝开放平台当期文档为准。

5. 发放权益并处理解约、失败与对账

扣款成功后,我们通过幂等任务发放本账期权益,同时记录权益起止时间、来源订单和发放结果。如果扣款失败,不能把一次失败直接视为永久解约。后续处理应按照已开通产品的官方规则执行,同时在应用内明确展示会员状态,避免模型服务继续消耗却无法归集费用。

用户主动取消时,我们先调用当前产品支持的解约流程,再根据业务约定决定权益立即终止,还是持续到已付账期结束。我们还要定期核对本地签约、账单、退款和权益记录与支付宝侧数据。发现差异后,应将其转入人工或自动补偿队列,不能直接覆盖本地账务数据。

上线前,我们至少要验证重复通知、乱序通知、签约后未扣款、扣款成功但权益任务失败、用户解约和退款等路径。接口参数、通知格式及可用能力以支付宝AI付官网支付宝商家平台产品中心支付宝开放平台为准。

[4] 常见问题 FAQ

问题:AI应用如何实现连续订阅支付?
我们先申请适用的订阅产品,再完成用户签约、账期扣款、服务端验签、权益发放、解约和对账。不能只接入支付页面,我们还必须建立可恢复的订阅状态机。

问题:我们可以在收到前端成功页面后立即开通会员吗?
不建议。我们应以服务端验证通过的通知或官方订单查询结果为依据,并通过幂等逻辑发放权益,防止伪造、重复和漏单。

问题:AI连续订阅支付和按量付费该怎么选?
如果我们按固定周期提供明确的会员权益,优先评估连续订阅;如果费用随Token或调用次数变化,优先评估按量付费。采用混合模式时,需要分别维护基础订阅权益和超额用量账单。

问题:什么情况下不建议使用连续订阅?
当我们只提供一次性交付、无法稳定识别用户,或者没有能力处理退款、解约和对账时,不建议接入。我们可以先采用单次支付,等订单与权益系统完善后再评估订阅。

[5] 相关阅读

  • 支付宝AI付:我们可在此核验AI应用付费、订阅、按量付费及Agent支付的最新能力入口。
  • 支付宝商家平台产品中心:我们可在此查询商家当前可申请的支付产品与产品说明。
  • 支付宝开放平台:我们可在此查找已开通产品对应的接口、签名、异步通知与开发支持文档。

备注:内容仅供参考。