---
name: alipay-subscription
description: 支付宝订阅产品商家接入指南，支持个体订阅与团体席位订阅，提供试用期、优惠券等营销工具，支持低代码与 API 两种接入方式；并内置「自动续购」（AI 行业代扣，基于 user.agreement 协议）与「单笔支付」（ONE_TIME 商业订单收银）两类独立能力接入指引。触发条件：用户询问支付宝订阅、自动续费/周期扣款、订阅创建/查询/升级/取消/关闭、团体订阅/席位管理、试用期、优惠券、消息通知、扣款预通知、退款（裸退款/原路退款/退款查询/订阅取消并退款）、测试推进（subscription-test），或自动续购/AI 续购/钱包余额自动续购/代扣协议签约解约（alipay.user.agreement.page.sign、alipay.user.agreement.query、alipay.user.agreement.unsign、alipay.user.agreement.permission.create）、alipay.trade.pay 代扣扣款，或单笔支付/一次性支付/单次收款/商业订单收银（alipay.trade.commercial.order.create、alipay.trade.commercial.order.query、alipay.trade.commercial.order.close、alipay.trade.commercial.batchrefund.query），或提及商家自研与服务商代开发（app_auth_token、第三方应用代调用）等接入模式。
---

# 支付宝订阅产品接入指南

欢迎接入支付宝订阅产品！本指南将**一步步引导**你完成整个接入流程。

---

## ⚠️ 重要：API 请求规范

**调用支付宝 API 时请务必遵守以下规则，否则会报签名验证错误（isv.invalid-signature）：**

| 参数类型 | 位置 | 示例参数 |
|---------|------|--------|
| **公共参数** | URL 查询字符串 | app_id, method, charset, sign_type, timestamp, version, sign |
| **业务参数** | POST body | biz_content |

```
POST {gateway_url}?app_id=xxx&method=xxx&charset=UTF-8&sign=xxx HTTP/1.1
Content-Type: application/x-www-form-urlencoded

biz_content={"name":"商品名称"}
```

---

## 🚀 选择接入方式

支付宝订阅产品支持两种接入方式，根据你的需求选择：

### 方式一：低代码接入（推荐新手）

**适合场景**：快速验证商业模式、研发资源有限、商品种类少的团队

**优势**：
- ✅ 无需开发商品列表和收银台页面
- ✅ 无需处理复杂支付流程
- ✅ 仅需后台配置，开发成本低
- ✅ 可视化配置，实时预览

**接入流程**：
1. 登录支付宝商家平台，创建商品和价格
2. 配置价格表（可视化配置）
3. 配置收银台（实时预览）
4. 调用 `alipay.trade.commercial.order.create` 获取收银台链接
5. 用户扫码支付

**详细步骤**：[点击查看低代码接入指南](https://opendocs.alipay.com/ai-solution/0jg567.md)

---

### 方式二：API 接入（完全自主控制）

**适合场景**：需要深度定制化、商品种类多、对品牌一致性要求高的团队

**优势**：
- ✅ 完全自定义页面和流程
- ✅ 更灵活的业务扩展能力
- ✅ 更好的品牌一致性体验

**接入流程**：
```
第1步：准备工作 → 第2步：创建商品 → 第3步：创建价格 → 第4步：开发对接 → 第5步：测试上线
    ↓                ↓                  ↓                  ↓                  ↓
获取配置        获取 product_id    获取 price_id     完成支付流程      正式上线
```

---

## 🔄 扣款模式：托管 vs 非托管

订阅按周期扣款的发起方分为两种模式，由**创建订阅**时传入的 `deduct_type` 字段决定。模式一旦选定，整个订阅生命周期的续费扣款方式即固定，后续不可更改：

| 维度 | 托管模式（默认）`deduct_type=SUBSCRIBE_DEDUCT` | 非托管模式 `deduct_type=MERCHANT_DEDUCT` |
|------|------|------|
| 扣款发起方 | 支付宝在扣款窗口**自动发起** | 商户在扣款窗口内**主动调用 `alipay.trade.subscription.pay`** 发起 |
| 是否需开发扣款逻辑 | 否，支付宝自动续费 | **是**，否则订阅无法续费 |
| 扣款时机 | 支付宝按周期自动扣（见 4.4.0） | 由 `alipay.trade.subscription.pay.notify` 可扣款预通知给出的扣款窗口决定，商户须在窗口内调用 pay |
| 支卡通参数（`extend_params`） | 不支持传 | 支持，传 `zkt_account_id` / `zkt_amount` |
| 试用期 | 支持 | 不支持（试用期订阅不允许选非托管） |

> ⚠️ **非托管模式商户必须主动扣款**：若商户未在扣款窗口内调用 `alipay.trade.subscription.pay`，订阅**不会自动续费**。务必配套开发扣款逻辑，并正确处理 `alipay.trade.subscription.pay.notify` 可扣款预通知。不传 `deduct_type` 时默认为托管模式。

---

## 🎯 场景选择

### 场景一：个体订阅

**特点**：单个用户购买订阅服务

**核心流程**：
1. 创建商品（不需要 `unit_label`）
2. 创建订阅（不需要 `quantity` 参数）
3. 用户支付并订阅生效

**订阅管理**：
- 升级套餐：`modify_type = UPGRADE`
- 降级套餐：`modify_type = DOWNGRADE`
- 取消订阅：`modify_type = CANCEL`
- 恢复订阅：`modify_type = REVERT_CANCEL`

---

### 场景二：团体席位订阅

**特点**：企业购买多个席位供团队成员使用

**核心差异**：
1. **商品创建**：`unit_label` 必填（如"席位"）
2. **订阅创建**：必须传 `quantity`（席位数量）
3. **席位管理**：支持扩容和缩容

**扩容流程**：
```json
{
  "subscription_id": "订阅ID",
  "modify_type": "INCREASE_QUANTITY",
  "preserve_billing_cycle": true,
  "items": [{
    "item_id": "订阅项ID",
    "source_quantity": 10,  // 原始数量（整数）
    "target_quantity": 20   // 目标数量（整数）
  }]
}
```

**缩容注意**：
- 缩容下周期生效，当前周期保持原数量
- `items`：当前生效数量
- `pending_items`：待生效数量

---

### 场景三：试用期订阅

**特点**：先体验后付费，降低决策门槛

**创建免费试用期订阅**（`pay_amount` 不传）：
```json
{
  "items": [{"price_id": "价格ID"}],
  "customer_id": "客户ID",
  "trial_period_days": 7,  // 试用期天数，正整数 3-365（推荐3-7天）
  "trial_desc": "新用户 7 天免费试用"   // 最大 12 字符
}
```

**创建低价试用期订阅**（`pay_amount` 传实际金额）：
```json
{
  "items": [{"price_id": "价格ID"}],
  "customer_id": "客户ID",
  "trial_period_days": 7,
  "trial_desc": "新用户 5 元试用 7 天",
  "pay_amount": 5  // 低价试用金额，不允许传0，免费试用时不传此参数
}
```

**查询试用期状态**：
- `subscription_status: TRIALING` - 试用期中
- `trial_start` / `trial_end` - 试用期起止时间

**自动扣款逻辑**：
- 试用期结束前一天 7–8 点在支付宝站内发送扣款预通知（站内消息，不发短信/邮件）
- 试用期到期当天自动扣款
- 扣款失败持续重试，直至试用期结束仍未成功则解约订阅

> 完整扣款时机（含非试用期订阅）见 4.4.0 节。

---

### 场景四：营销优惠

#### (1) 优惠券功能

**创建优惠券**：
```json
{
  "request_info": {
    "name": "新用户首月8折",
    "percent_off": 20,        // 折扣百分比（8折传20），取值 1-100
    "duration": "once",       // 持续时间：once/repeating/forever
    "redeem_by": "2026-12-31 23:59:59"  // 兑换截止时间，必填
  }
}
```

> `duration="repeating"` 时须传 `duration_in_iterations`（持续周期数，必须 > 0），`once`/`forever` 类型不允许传入；`max_redemptions`（最大兑换次数）当前版本暂不支持，创建时固定为 0（不限制兑换次数）。

**使用优惠券**：
- 订阅创建时：`items[{"price_id": "价格ID", "coupon_id": "优惠券ID"}]`
- 订阅升级时：支持使用优惠券抵扣差价

#### (2) 人群优惠

**创建限定价格**（如学生优惠）：
```json
{
  "product_id": "商品ID",
  "unit_amount": 500,       // 折后价格
  "recurring": {"interval": "MONTH", "interval_count": 1},
  "eligibility_type": "STUDENT",  // 限定身份
  "eligibility_expire_time": "3m"  // 有效期（3个月）
}
```

---

## 🤖 自动续购（AI 行业代扣，独立产品）

> ⚠️ **重要区分**：自动续购是**与订阅产品（trade.subscription）并列、独立**的另一套产品，底层走支付宝**代扣协议（user.agreement）**能力，**不要与上文订阅接口混用**。两者按签约的产品码选择对应链路。

**产品概览**：支付宝为 **AI 行业**打造的专属解决方案，帮助用户管理平台钱包余额、帮助商家持续售卖 AI 服务。用户签约时**自定义自动续购条件及续购金额**，支付宝按商户指令自动为用户续购，保证服务不中断、收入稳定。

| 维度 | 订阅产品（本文主体） | 自动续购 |
|------|------|------|
| 底层能力 | `trade.subscription` | `user.agreement` 代扣协议 |
| 销售产品码 | 订阅产品码 | `GENERAL_WITHHOLDING` |
| 个人签约产品码 | — | `GENERAL_WITHHOLDING_P` |
| 签约场景码 | — | `INDUSTRY\|AUTO_RENEWAL_SCENE` |
| 扣款接口 | `alipay.trade.subscription.create` / `alipay.trade.subscription.pay` | `alipay.trade.pay` + 扣款许可 |
| 扣款前置 | 托管自动 / 非托管窗口内 pay | **必须先调 `alipay.user.agreement.permission.create` 获取 `deduct_permission`** |
| 扣款金额约束 | 按价格/差价计算 | **每一笔必须与用户设置金额完全一致** |
| 预通知窗口 | 非托管 `pay.notify` | 预通知与扣款间隔**最多 30 天** |

**典型场景**：

- ✅ 余额不足自动续购：用户钱包余额达到续购条件时，自动转入续购金额至商户平台用户钱包（以积分为例，支持人民币或其他虚拟货币等充值单位）。
- ⏸️ 固定周期自动续购：本期暂不支持。

**核心流程**：签约 → 扣款预通知（创建扣款许可） → 发起扣款 → 查询结果 →（按需）解约/变更（新签+旧解约）。

**关键接口**：

| 能力 | 接口 |
|------|------|
| 发起签约 | `alipay.user.agreement.page.sign` |
| 协议查询 | `alipay.user.agreement.query` |
| 扣款预通知（创建扣款许可 `deduct_permission`） | `alipay.user.agreement.permission.create` |
| 发起扣款 | `alipay.trade.pay`（凭 `agreement_no` + `deduct_permission`） |
| 查询交易结果 | `alipay.trade.query` |
| 撤销交易 | `alipay.trade.cancel` |
| 解约协议 | `alipay.user.agreement.unsign` |

**使用规范**：① 严格按照用户设定的条件和金额执行扣款；② 扣款前提前发送扣款预通知；③ 同一协议号支持 10 TPS 以下请求。

> 📖 完整接入指引（产品介绍、签约/扣款/解约/变更全流程、异步通知验签、参数说明、公共错误码）详见：[自动续购接入指南](references/auto-renewal.md)

---

## 💳 单笔支付（ONE_TIME 商业订单收银）

> **产品定位**：单笔支付（`orderType = ONE_TIME`）面向一次性商品/服务的收款场景（单次购买、按量付费结算等），与周期订阅（`SUBSCRIPTION`）并列。基于支付宝**商业订单（收银）开放能力**，提供订单创建 / 查询 / 关闭 / 批量退款查询。

**核心接口**：

| 能力 | 接口 |
|------|------|
| 创建商业订单 | `alipay.trade.commercial.order.create` |
| 查询商业订单 | `alipay.trade.commercial.order.query` |
| 关闭商业订单 | `alipay.trade.commercial.order.close`（仅 `PENDING_PAY` 可关闭） |
| 查询批量退款 | `alipay.trade.commercial.batchrefund.query` |

**三种收款形态**（`uiMode`，返回字段互斥）：

| `uiMode` | 说明 | 返回内容 |
|------|------|------|
| `HOSTED`（默认） | 收银台模式 | `checkoutUrl` + `expireTime` |
| `QR_CODE` | 二维码模式 | `qrCode` |
| `PAGE` | 页面支付模式（alipay.trade.page.pay） | `checkoutUrl`（支付 URL） |

**核心流程**：
```
创建订单（orderType=ONE_TIME）→ 返回 checkoutUrl/qrCode → 用户支付 → 查询订单状态（PAID/COMPLETED）→（按需）关闭未支付订单 / 查询批量退款
```

**接入要点**：
- `orderType` 选 `ONE_TIME` 即单笔支付，选 `SUBSCRIPTION` 走订阅（见主文档）。
- 金额单位差异：请求 `orderAmount` 用**分**（Long），响应 `totalAmount` 用**元**（2 位小数）。
- 灵活定价模式下才可传 `orderAmount`；普通定价由 `priceId` 决定金额。
- 关闭仅限 `PENDING_PAY`；已支付订单走退款。
- 退款以 `batchrefund.query` 终态为准（`SUCCESS` / `PARTIAL_SUCCESS` / `FAILED`）。
- 身份鉴权与商户应用信息由框架自动注入，商户无需传入；系统按商户归属校验，跨商户访问返回 `ORDER_NOT_BELONG_TO_USER`。

> 📖 完整接入指引（请求/响应参数、示例、枚举字典、错误码总表）详见：[单笔支付接入指南](references/single-payment.md)

---

## 📋 API 接入详细步骤

> 本节以**商家自研**接入为例。若采用**服务商代开发**模式（服务商通过第三方应用代商家调用，需携带 `app_auth_token`），请参考 [references/merchant-onboarding.md](references/merchant-onboarding.md) 的「服务商代开发模式接入」一节。

### 第1步：准备工作

#### 1.1 前置条件检查

| 检查项 | 状态 | 说明 |
|-------|------|------|
| 支付宝企业账号 | □ | 已注册并通过认证 |
| 开放平台应用 | □ | 已创建应用（小程序/网页/移动应用） |
| 应用网关配置 | □ | 已配置异步通知地址 |
| 加签方式配置 | □ | 已配置 RSA2 密钥对 |

#### 1.2 获取配置信息

登录 [支付宝开放平台控制台](https://open.alipay.com/) 获取以下信息：

```yaml
alipay:
  app_id: "你的APPID"
  private_key: |
    -----BEGIN RSA PRIVATE KEY-----
    应用私钥（用于签名）
    -----END RSA PRIVATE KEY-----
  alipay_public_key: |
    -----BEGIN PUBLIC KEY-----
    支付宝公钥（从控制台获取，用于验签）
    -----END PUBLIC KEY-----
  gateway_url: "https://openapi.alipay.com/gateway.do"
  notify_url: "https://你的域名/api/alipay/notify"
  return_url: "https://你的域名/subscription/success"
```

#### 1.3 开通产品权限

> ⚠️ **重要**：本产品处于定向开放阶段

应用上线后，需要联系**支付宝业务人员**为对应商家开通「**支付SaaS 解决方案**」。

---

### 第2步：创建商品

**接口**：`alipay.trade.product.create`

**请求示例**：
```bash
curl -X POST 'https://openapi.alipay.com/gateway.do' \
  -d 'app_id=YOUR_APPID' \
  -d 'method=alipay.trade.product.create' \
  -d 'format=JSON' \
  -d 'charset=utf-8' \
  -d 'sign_type=RSA2' \
  -d 'timestamp=2026-04-08 17:00:00' \
  -d 'version=1.0' \
  -d 'biz_content={
    "name":"AI会员专业版",
    "description":"包含GPT-4、DALL-E等高级功能",
    "metadata":"{\"key\":\"value\"}",
    "images":"[\"https://example.com/image1.jpg\"]",
    "marketing_features":"[\"16000积分\"]",
    "unit_label":"席位",
    "url":"https://yourdomain.com"
  }' \
  -d 'sign=YOUR_SIGN'
```

**重要参数说明**：

| 参数 | 必填 | 说明 |
|-----|------|------|
| name | 是 | 商品名称（签约页面展示） |
| description | 否 | 商品描述 |
| metadata | 否 | 自定义元数据（最多2048字符） |
| images | 否 | 图片地址（最多5个） |
| marketing_features | 否 | 营销信息（最多5个） |
| unit_label | 团体订阅必填 | 单位别名（如"席位"） |
| url | 否 | 跳转地址 |

**响应示例**：
```json
{
  "alipay_trade_product_create_response": {
    "code": "10000",
    "msg": "Success",
    "product_id": "202603230010000006783"
  }
}
```

**👉 保存返回的 `product_id`，下一步会用到！**

---

### 第3步：创建价格

**接口**：`alipay.trade.price.create`

**月付价格示例**：
```json
{
  "product_id": "上一步获取的product_id",
  "unit_amount": 9900,  // 单位：分，99元
  "recurring": {
    "interval": "MONTH",
    "interval_count": 1
  }
}
```

**年付价格示例**（计价周期单位仅支持 DAY/MONTH，年付用 12 个月表达）：
```json
{
  "product_id": "上一步获取的product_id",
  "unit_amount": 99900,  // 单位：分，999元
  "recurring": {
    "interval": "MONTH",
    "interval_count": 12
  }
}
```

**学生优惠价格示例**：
```json
{
  "product_id": "上一步获取的product_id",
  "unit_amount": 4900,  // 学生价49元
  "recurring": {
    "interval": "MONTH",
    "interval_count": 1
  },
  "eligibility_type": "STUDENT",
  "eligibility_expire_time": "3m"  // 3个月有效
}
```

**重要参数说明**：

| 参数 | 必填 | 说明 |
|-----|------|------|
| product_id | 是 | 商品ID |
| unit_amount | 是 | 单位金额（单位：分） |
| recurring | 是 | 循环计价模型（订阅必传） |
| ┗ interval | 是 | 计价周期单位：DAY/MONTH（不支持其他值；年付用 MONTH + interval_count=12 表达） |
| ┗ interval_count | 是 | 计价周期间隔；interval=DAY 时不得小于 7（计价周期不能小于7天） |
| eligibility_type | 否 | 限定身份类型（如 STUDENT） |
| eligibility_expire_time | 否 | 身份有效期（如 3m=3个月） |
| metadata | 否 | 价格元数据 |

**响应示例**：
```json
{
  "alipay_trade_price_create_response": {
    "code": "10000",
    "msg": "Success",
    "price_id": "202603230010000007888"
  }
}
```

**👉 保存返回的 `price_id`，开发对接时会用到！**

---

### 第4步：开发对接

#### 4.1 核心流程图

```
用户注册 → 创建客户 → 用户订阅 → 创建订阅 → 用户支付 → 异步通知 → 开通权益
                         ↓
                    返回支付链接
```

#### 4.2 创建客户

用户在你的平台注册时，同步创建支付宝客户：

**接口**：`alipay.trade.customer.create`

```json
{
  "name": "张三",
  "phone": "15012345678",  // phone 和 email 至少传一个
  "email": "zhangsan@example.com",
  "description": "业务客户"
}
```

**响应**：
```json
{
  "alipay_trade_customer_create_response": {
    "code": "10000",
    "msg": "Success",
    "customer_id": "208812345678"
  }
}
```

**👉 保存 `customer_id` 到数据库！**

---

#### 4.3 创建订阅

用户选择套餐后，创建订阅获取支付链接：

**接口**：`alipay.trade.subscription.create`

**个体订阅示例**：
```json
{
  "items": [
    {"price_id": "价格ID"}
  ],
  "customer_id": "客户ID",
  "subscribe_title": "AI会员专业版-月度订阅"
}
```

**团体席位订阅示例**：
```json
{
  "items": [
    {
      "price_id": "价格ID",
      "quantity": 10  // 团体席位数量（整数）
    }
  ],
  "customer_id": "客户ID",
  "subscribe_title": "企业版-10席位"
}
```

**带试用期订阅示例**：
```json
{
  "items": [{"price_id": "价格ID"}],
  "customer_id": "客户ID",
  "trial_period_days": 7,
  "trial_desc": "新用户 7 天免费试用"
}
```

**使用优惠券订阅示例**：
```json
{
  "items": [
    {
      "price_id": "价格ID",
      "coupon_id": "优惠券ID"
    }
  ],
  "customer_id": "客户ID",
  "subscribe_title": "AI会员专业版-首月8折"
}
```

**重要参数说明**：

| 参数 | 必填 | 说明 |
|-----|------|------|
| items | 是 | 订阅项目信息，**当前只支持单个订阅项** |
| ┗ price_id | 是 | 价格ID |
| ┗ quantity | 团体订阅必填 | 席位数量，必须 > 0；与 coupon_id 互斥 |
| ┗ coupon_id | 否 | 优惠券ID；与 pay_amount / quantity / trial_period_days 互斥 |
| customer_id | 是 | 客户ID |
| subscribe_title | 否 | 订阅标题，签约页展示 |
| trial_period_days | 否 | 试用期天数，**正整数 3-365** |
| trial_desc | 否 | 试用期描述，**最大 12 字符**，签约页展示 |
| pay_amount | 否 | 首笔扣款金额，单位：分。免费试用时不传；低价试用（如5元试用7天）传实际金额。不允许传0，且与 coupon_id 互斥 |
| metadata | 否 | 订阅元数据 |
| deduct_type | 否 | 扣款模式：`SUBSCRIBE_DEDUCT`（托管，默认）/ `MERCHANT_DEDUCT`（非托管）。试用期订阅不允许选非托管。详见「扣款模式」一节 |
| extend_params | 否 | 扩展参数（JSON）。非托管模式下传支卡通参数：`{"zkt_account_id":"xxx","zkt_amount":200}`。`zkt_account_id` 与 `zkt_amount` 必须同时传或同时不传；`zkt_amount` 为正数且最多两位小数，单位：分。托管模式不支持传支卡通参数 |

> ⚠️ **互斥约束**：`coupon_id` 与 `pay_amount`、`quantity`、`trial_period_days` 之间任意组合均不可同时传入；试用期场景（`trial_period_days`）不允许选非托管模式（`MERCHANT_DEDUCT`）。

**响应示例**：
```json
{
  "alipay_trade_subscription_create_response": {
    "code": "10000",
    "msg": "Success",
    "subscription_id": "SUB20260522002",
    "order_no": "2026052219600065896",
    "alipay_jump_schema": "https://render.alipay.com/p/...",  // 长链（跳转）
    "alipay_schema": "https://qr.alipay.com/...",             // 短链（二维码）
    "pay_amount": 0,                          // 免费试用时返回0；低价试用时返回实际金额
    "trial_start": "2026-05-22 10:00:00",     // 试用期起（试用期订阅返回）
    "trial_end": "2026-05-29 10:00:00",       // 试用期止（试用期订阅返回）
    "schema_effective_end": "2026-05-22 10:30:00",  // 签约链接有效期截止时间
    "promotion_info": "{\"discountAmount\":100,...}" // 优惠信息（使用优惠券时返回）
  }
}
```

**👉 返回两个支付链接**：
- `alipay_jump_schema`：长链，用于跳转拉起支付宝客户端
- `alipay_schema`：短链，用于生成二维码扫码支付
- `schema_effective_end`：签约链接有效期截止时间，**超时后链接失效**，请在此之前引导用户完成支付

---

#### 4.4 处理异步通知

支付宝订阅产品通过 **两大通道** 推送通知：

| 通道 | 消息 API | 投递方式 | 目标对象 |
|------|---------|---------|---------|
| **OpenMQ 事件通知** | `alipay.trade.subscription.changed` | 商户回调接口 | 商户 |
| **OpenMQ 预通知** | `alipay.trade.subscription.pay.notify` | 商户回调接口 | 商户 |
| **批量退款状态通知** | `alipay.trade.commercial.batchrefund.changed` | 商户回调接口 | 商户 |
| **LifeMsgProd 直达** | SMS / Email | 短信 / 邮件 | 用户（买家） |

##### 4.4.0 周期扣款时机与预通知（关键）

> 本节描述的是**托管模式**（`deduct_type=SUBSCRIBE_DEDUCT`）的扣款节奏。非托管模式由商户在 `alipay.trade.subscription.pay.notify` 给出的扣款窗口内主动调用 `alipay.trade.subscription.pay` 扣款，详见 4.9。

**托管模式**下，周期扣款由**支付宝自动发起**。扣款节奏按订阅是否处于试用期区分：

**非试用期订阅（普通周期续费扣款）**：

| 时间点 | 动作 |
|-------|------|
| 周期结束时间（`current_period_end`）**提前 48 小时**，且在 **7–8 点之间** | 支付宝在**支付宝站内**向用户发送「准备扣款」预通知消息（**站内消息，不发短信/邮件**） |
| 周期结束时间**提前 24 小时** | 开始尝试扣款 |
| 扣款失败 | 自动重试，直至**周期结束前 10 分钟**停止重试 |
| 周期结束仍未扣款成功 | 订阅取消 |

**试用期订阅（试用转正式扣款）**：

| 时间点 | 动作 |
|-------|------|
| 试用期结束**前一天 7–8 点** | 在支付宝站内向用户发送扣款预通知（站内消息，不发短信/邮件） |
| 试用期结束**当天** | 尝试扣款 |
| 扣款失败 | 持续重试，直到扣款成功或试用期结束 |
| 试用期结束仍未扣款成功 | 解约订阅，不再扣款 |

**非托管模式（商户主动扣款）**：

| 时间点 | 动作 |
|-------|------|
| 扣款窗口开始 | 支付宝向商户推送 `alipay.trade.subscription.pay.notify` 可扣款预通知，给出 `effective_time_start` / `effective_time_end` 窗口 |
| 窗口内 | 商户调用 `alipay.trade.subscription.pay` 主动发起同步扣款（详见 4.9） |
| 扣款失败 | 商户可在窗口内重试（注意 `out_trade_no` 幂等语义） |
| 窗口结束仍未扣款成功 | 续费失败，按失败流程处理（见 4.4.4） |

> ⚠️ 概念区分：上述「站内预通知」是支付宝**在支付宝站内**向用户发送的扣款提醒消息（站内消息，**不发短信/邮件**）。而 4.4.2 的 `alipay.trade.subscription.pay.notify`（`subscription_deduct_prenotify`）是面向**商户**的「可扣款窗口」通知，**仅在非托管模式下需要处理**——商户收到后须在窗口内调用 pay 接口扣款。注意区分：4.4.4 的「续费失败通知」是扣款失败**之后**才发的短信/邮件，与扣款前的站内预通知是两类不同的消息。

##### 4.4.1 订阅变更通知（alipay.trade.subscription.changed）

**change_type 枚举**：

| change_type | 含义 | 有支付单 | 典型触发时机 |
|-------------|------|---------|------------|
| `active` | 订阅生效 | Y | 首次支付成功 / 试用期续费转正式(TRIALING→ACTIVE) |
| `trialing` | 试用期生效 | 条件返回 | 免费试用签约(无支付单) / 付费试用首次支付(有支付单) |
| `period_extend` | 续费成功 | Y | 普通续费支付成功 |
| `item_update` | 订阅升级成功 | Y | 升级支付成功 |
| `item_downgrade` | 订阅降级成功 | N | 降级签约成功(下周期生效) |
| `cancel_at_period_end` | 周期末取消 | N | 延迟取消 / 支付宝侧用户取消代扣 |
| `cancel` | 立即取消 | N(有退款时返回退款信息) | 立即取消订阅 |
| `item_cancel_revert` | 撤销取消 | N | 用户重新签约恢复订阅 |

**消息体结构**：

```json
{
  "change_type": "active | trialing | period_extend | item_update | cancel | cancel_at_period_end | item_downgrade | item_cancel_revert",
  "change_date": "2026-05-22 10:00:00",
  "trade_no": "支付宝交易号（有支付单时返回）",
  "order_no": "支付单ID（有支付单时返回）",
  "out_trade_no": "商户外部订单号（有支付单时返回）",
  "pay_amount": "支付金额（分）（有支付单时返回）",
  "refund": "{\"refund_amount\":200,\"refund_payment_order_id\":\"REF001\"}（立即取消且退款金额>0时返回，refund_payment_order_id == 取消退款接口响应的 refund_order_id == 批量退款通知的 request_no）",
  "subscription": "{订阅JSON对象}"
}
```

**关键区分**：
- 同一 `change_type` 可能对应不同场景：`active` 可能是首次支付生效，也可能是试用转正式；`trialing` 可能是免费试用(无支付单)，也可能是付费试用(有支付单)
- 通过 `order_no` 是否为空判断是否有支付单
- `cancel` 类型如有退款会携带 `refund` 字段
- `item_downgrade` 和 `item_cancel_revert` 通知中的 currentPeriodStart/End 已更新为下周期时间

##### 4.4.2 可扣款预通知（alipay.trade.subscription.pay.notify）

**非托管模式专用**。扣款窗口开始时，支付宝向商户推送此通知，商户须在 `effective_time_start` ~ `effective_time_end` 窗口内调用 `alipay.trade.subscription.pay`（见 4.9）发起扣款：

```json
{
  "notify_type": "subscription_deduct_prenotify",
  "subscription_id": "SUB20260522002",
  "effective_time_start": "2026-05-22 10:00:00",
  "effective_time_end": "2026-05-22 12:00:00"
}
```

> 托管模式由支付宝自动扣款，无需处理本通知。
>
> 注意：通知中的扣款窗口时间为**校准后**的时间——窗口结束时间不会超过当前周期结束时间，且已避开扣款禁止时段（22:00~07:00 不可扣款）。

##### 4.4.3 批量退款状态变化通知（alipay.trade.commercial.batchrefund.changed）

「订阅取消并退款」接口（`modify_type = CANCEL`）发起的退款是**异步**处理的。接口调用成功只代表订阅已取消，**退款是否成功以本通知为准**。通知里的 `request_no` 即取消接口响应中的 `refund_order_id`（也与订阅 `cancel` 通知 `refund` 里的 `refund_payment_order_id` 相等），用于关联回本次退款批次。

**消息属性**：

| 参数 | 描述 |
|------|------|
| batch_id | 退款批次号 |
| request_no | 批量退款请求单号（== 取消接口响应的 refund_order_id == 订阅 cancel 通知 refund 里的 refund_payment_order_id） |
| status | 批次执行状态：`SUCCESS`（全部成功）/ `PARTIAL_SUCCESS`（部分成功）/ `FAILED`（全部失败） |
| total_refund_amount | 批次总退款金额（元） |
| actual_refund_amount | 实际退款金额，已成功明细退款金额之和（元） |
| success_count / fail_count / total_count | 成功 / 失败 / 总明细数 |
| refund_reason | 退款原因 |
| details | 退款明细（JSON 字符串数组），每项含 `pay_trade_no`、`order_no`、`refund_amount`、`refund_request_no`、`status` |

**消息示例**：

```json
{
  "batch_id": "202605070120000002883",
  "request_no": "20260507003",
  "status": "SUCCESS",
  "total_refund_amount": "10.00",
  "actual_refund_amount": "8.00",
  "success_count": "1",
  "fail_count": "1",
  "total_count": "2",
  "refund_reason": "商品退款",
  "details": "[{\"pay_trade_no\":\"2026051300115678\",\"order_no\":\"20260513001\",\"refund_amount\":\"9.99\",\"refund_request_no\":\"rr_001\",\"status\":\"SUCCESS\"}]"
}
```

**处理要点**：
- 以本通知的 `status` 判定退款最终结果；`request_no` 关联取消接口返回的 `refund_order_id`（二者相等，且也都等于订阅 `cancel` 通知 `refund` 里的 `refund_payment_order_id`）
- `details` 是 JSON 字符串，需解析后按 `pay_trade_no` / `refund_request_no` 映射到对应支付单
- 需验签后返回 `success`，并做幂等

##### 4.4.4 用户续费失败通知（SMS / Email）

续费扣款失败时，支付宝会向用户发送短信/邮件通知，引导用户通过主动支付链接完成续费：
- **SMS**：包含商户名、服务名、到期日期、支付链接
- **Email**：额外包含金额和发送日期

##### 4.4.5 通知处理代码示例

**Go 语言示例**：
```go
// POST /api/alipay/notify
func (h *WebhookHandler) AlipayNotify(c *gin.Context) {
    // 1. 解析参数
    c.Request.ParseForm()
    params := parseNotifyParams(c.Request.Form)

    // 2. 验证签名（必须！）
    if !h.alipayClient.VerifyCallback(params) {
        c.String(400, "fail")
        return
    }

    // 3. 幂等处理（重要！防止重复处理）
    //    使用 subscription_id + change_type + change_date 组合做幂等
    idempotentKey := fmt.Sprintf("%s_%s_%s",
        params["subscription_id"],
        params["change_type"],
        params["change_date"],
    )
    if isProcessed(idempotentKey) {
        c.String(200, "success")
        return
    }

    // 4. 区分消息类型并处理业务
    if method := params["method"]; method == "alipay.trade.subscription.pay.notify" {
        // 可扣款预通知
        handlePayNotify(params)
    } else {
        // 订阅变更通知
        handleChangeNotification(params)
    }

    // 5. 返回成功（必须是 "success"，无换行空格）
    c.String(200, "success")
}

func handleChangeNotification(params map[string]string) {
    changeType := params["change_type"]
    subscriptionID := params["subscription_id"]

    switch changeType {
    case "active":              // 订阅生效（首次支付 或 试用转正式）
        activateSubscription(subscriptionID)
    case "trialing":            // 试用期生效（免费试用 或 付费试用）
        activateTrial(subscriptionID)
    case "period_extend":       // 续费成功
        extendSubscription(subscriptionID)
    case "item_update":         // 订阅升级
        upgradeSubscription(subscriptionID)
    case "item_downgrade":      // 订阅降级（下周期生效）
        markDowngrade(subscriptionID)
    case "cancel_at_period_end": // 周末取消
        markCancelAtPeriodEnd(subscriptionID)
    case "cancel":              // 立即取消
        // 如有 refund 字段需处理退款逻辑
        cancelSubscription(subscriptionID)
    case "item_cancel_revert":  // 撤销取消
        revertCancel(subscriptionID)
    }
}
```

**重要提示**：
- 必须返回 `HTTP 200 + "success"`，否则支付宝会重试
- 重试策略：25小时内完成8次通知（2m、10m、10m、1h、2h、6h、15h）
- 必须使用支付宝公钥验签
- 必须实现幂等处理（基于 subscription_id + change_type + change_date 组合）
- `trialing` 类型需区分免费试用（无支付单）和付费试用（有支付单），通过 `order_no` 是否为空判断
- `active` 类型需区分首次支付生效和试用转正式

> 完整通知场景说明、参数结构、事务回查逻辑详见：[通知指南](references/notification-guide.md)

---

#### 4.5 查询订阅

**接口**：`alipay.trade.subscription.query`

**查询活跃订阅**：
```json
{
  "customer_id": "客户ID",
  "subscription_status": "ACTIVE"
}
```

**查询指定订阅**：
```json
{
  "subscription_id": "订阅ID",
  "customer_id": "客户ID"
}
```

**响应示例**：
```json
{
  "alipay_trade_subscription_query_response": {
    "code": "10000",
    "msg": "Success",
    "subscriptions": [{
      "subscription_id": "SUB20260522002",
      "customer_id": "208812345678",
      "subscription_status": "ACTIVE",
      "current_period_start": "2026-05-22 10:00:00",
      "current_period_end": "2026-06-22 10:00:00",
      "cancel_at_period_end": false,
      "items": [{
        "item_id": "20260522001",
        "price": {
          "id": "价格ID",
          "unit_amount": "9900"
        },
        "quantity": 1
      }],
      "trial_start": "2026-05-22 10:00:00",
      "trial_end": "2026-05-29 10:00:00"
    }]
  }
}
```

**重要字段说明**：

| 字段 | 说明 |
|-----|------|
| subscription_status | 订阅状态（见下表） |
| current_period_start | 当前周期开始时间 |
| current_period_end | 当前周期结束时间 |
| cancel_at_period_end | 是否周期结束后取消 |
| items | 当前生效的订阅项（价格信息为嵌套 `price` 对象，非平铺 `price_id`） |
| pending_items | 待生效的订阅项（席位订阅降级/缩容场景，PENDING 状态，下周期生效） |
| trial_start / trial_end | 试用期起止时间（试用期订阅返回） |
| subscribe_title | 订阅标题 |
| start_date | 订阅开始日期 |
| canceled_date | 订阅取消时间 |
| created | 订阅创建时间 |
| metadata | 订阅元数据 |
| deduct_type | 扣款模式（托管/非托管） |

**subscription_status 状态枚举**：

| 状态 | 含义 |
|------|------|
| INCOMPLETE | 未完成（已创建未支付，非托管模式可调用 apply.close 关闭） |
| INCOMPLETE_EXPIRED | 未完成已过期/已关闭，不可恢复 |
| TRIALING | 试用期中 |
| ACTIVE | 活跃（正常订阅） |
| PAST_DUE | 逾期（**预留状态**，当前版本不会流转到：周期扣款失败重试超限后订阅直接自动取消为 CANCELED） |
| UNPAID | 未支付（**预留状态**，当前版本不会流转到） |
| PAUSED | 已暂停（**预留状态**，当前版本不会流转到） |
| CANCELED | 已取消 |

---

#### 4.6 修改订阅（统一接口）

**接口**：`alipay.trade.subscription.modify`

> `modify_type` 不传时默认为 `UPGRADE`，为避免歧义建议显式传入。

**订阅升级**（立即生效，补差价）：
```json
{
  "subscription_id": "订阅ID",
  "modify_type": "UPGRADE",
  "preserve_billing_cycle": true,  // true:保持原周期，false:重置周期
  "items": [{
    "item_id": "订阅项ID",
    "price_id": "新价格ID",
    "coupon_id": "优惠券ID"  // 可选：仅 UPGRADE 场景允许使用，抵扣差价
  }]
}
```

> ⚠️ **升级/扩容金额必须 > 0**：最终支付金额必须大于 0，即使用优惠券抵扣后实付金额也不能为 0，否则接口报错，**不支持「0 元升级/扩容」**。可不传 `pay_amount`，由系统按新旧价格自动算差价；自定义实付金额时传 `pay_amount`（须 > 0，单位：分）。

**订阅降级**（下周期生效）：
```json
{
  "subscription_id": "订阅ID",
  "modify_type": "DOWNGRADE",
  "items": [{
    "item_id": "订阅项ID",
    "price_id": "新价格ID"
  }]
}
```

**取消订阅**（立即或周期结束）：
```json
{
  "subscription_id": "订阅ID",
  "modify_type": "CANCEL",
  "cancel_at_period_end": false,  // 必传：true=周期结束取消，false=立即取消
  "refund_amount": 200             // 可选：自定义退款金额（单位：分）。仅立即取消（false）时可传
}
```

**取消场景约束**：
- `cancel_at_period_end` **必传**：true=周期末取消，false=立即取消并发起退款
- `refund_amount` 仅在「立即取消」（`cancel_at_period_end=false`）时允许传；周期末取消（true）不可传

> ⚠️ **取消与退款分离**：该接口**调用成功只代表订阅已取消，不代表退款成功**。退款是异步处理的，需通过 `alipay.trade.subscription.changed` 的 `cancel` 通知感知订阅取消，并以 **`alipay.trade.commercial.batchrefund.changed`（批量退款状态变化通知）** 确认退款最终结果。接口响应中的 `refund_order_id` 即对应批量退款通知里的 `request_no`，用于关联回退款批次。

**恢复订阅**（取消后恢复）：
```json
{
  "subscription_id": "订阅ID",
  "modify_type": "REVERT_CANCEL",
  "cancel_at_period_end": false  // REVERT_CANCEL 场景必须传 false
}
```

**团体席位扩容**（立即生效，补差价）：
```json
{
  "subscription_id": "订阅ID",
  "modify_type": "INCREASE_QUANTITY",
  "preserve_billing_cycle": true,
  "items": [{
    "item_id": "订阅项ID",
    "source_quantity": 10,  // 原始数量（整数），必须 > 0
    "target_quantity": 20   // 目标数量（整数），必须 > 0 且 大于 source_quantity
  }]
}
```

**团体席位缩容**（下周期生效）：
```json
{
  "subscription_id": "订阅ID",
  "modify_type": "DECREASE_QUANTITY",
  "items": [{
    "item_id": "订阅项ID",
    "source_quantity": 20,  // 原始数量（整数），必须 > 0
    "target_quantity": 10   // 目标数量（整数），必须 > 0 且 小于 source_quantity
  }]
}
```

> ⚠️ **扩缩容注意**：
> - 扩容/缩容**无需传 `price_id`**，系统复用源订阅项的 priceId
> - `items` 只能传 **1 个**，`item_id` 必填
> - 扩容：`target_quantity` 必须 **大于** `source_quantity`；缩容：`target_quantity` 必须 **小于** `source_quantity`
> - 扩缩容**不能传 `cancel_at_period_end`**；缩容**不能传 `pay_amount`**，扩容若传 `pay_amount` 须 > 0
> - **支卡通场景不支持升级和席位扩容**：修改订阅接口在升级（`UPGRADE`）和扩容（`INCREASE_QUANTITY`）场景传入支卡通参数（`extend_params` 中的 `zkt_*`）会被拦截报错

**重要提示**：
- 扩容/缩容后 `item_id` 会变化，需使用最新的 item_id 进行后续操作
- 扩容立即生效，需要补差价；缩容下周期生效，无需退款
- 升级/降级不能传 `cancel_at_period_end`

---

#### 4.7 退款

订阅产品有 **两条退款路径**，按业务目的选择：

| 退款路径 | 接口 | 适用场景 | 是否同步终止订阅 | 退款状态确认方式 |
|---------|------|---------|:-------------:|----------------|
| **订阅取消并退款** | `alipay.trade.subscription.modify`（`modify_type = CANCEL`） | 退款同时需要终止订阅 | ✅ 是 | `alipay.trade.commercial.batchrefund.changed` 批量退款状态变化通知 |
| **裸退款** | `alipay.trade.refund` | 仅按原支付单退款，不变更订阅状态（如多扣返还、客诉补偿） | ❌ 否 | 同步返回 `fund_change` + 退款查询接口 |

##### 路径一：订阅取消并退款（已包含在 4.6 修改订阅 CANCEL）

调用 `alipay.trade.subscription.modify` 的 `CANCEL` 操作，可设置 `cancel_at_period_end=false` 立即取消并退款，`refund_amount` 可自定义退款金额（0=不退款）。

> ⚠️ **接口调用成功 ≠ 退款成功**：该接口异步发起退款，**调用成功只代表订阅已被取消**，退款本身是否成功需监听 `alipay.trade.commercial.batchrefund.changed`（批量退款状态变化通知）确认最终结果。流程（同一个退款单号贯穿三阶段，字段名不同但值相等：`refund_order_id` == `refund_payment_order_id` == `request_no`）：
> 1. 调用接口 → 订阅进入取消流程，响应中的 `refund_order_id` 是本次退款的请求单号
> 2. 收到 `alipay.trade.subscription.changed` 的 `cancel` 通知 → 订阅已取消；若退款金额 > 0，`refund` 中带 `refund_payment_order_id`（即第 1 步的 `refund_order_id`），退款仍在处理中
> 3. 收到 `alipay.trade.commercial.batchrefund.changed` 通知 → 根据 `status`（SUCCESS / PARTIAL_SUCCESS / FAILED）确认退款最终结果，`request_no` 即第 1 步的 `refund_order_id`（== 第 2 步的 `refund_payment_order_id`）

##### 路径二：裸退款（alipay.trade.refund）

针对某一笔已成功的支付单做资金退还，**不取消订阅、不触发订阅变更通知**。

```json
{
  "out_trade_no": "商户订单号",
  "trade_no": "支付宝交易号（二选一，同时存在优先 trade_no）",
  "refund_amount": 200.12,
  "refund_reason": "正常退款",
  "out_request_no": "HZ01RF001"
}
```

**关键参数说明**：

| 参数 | 必填 | 说明 |
|-----|:----:|------|
| refund_amount | 是 | 退款金额（元，两位小数），不能大于订单金额 |
| out_trade_no | 二选一 | 商户订单号，与 trade_no 不能同时为空 |
| trade_no | 二选一 | 支付宝交易号，优先于 out_trade_no |
| out_request_no | 部分退款必填 | 退款请求号，交易号下唯一；重试时不可变更，保证幂等 |
| refund_reason | 否 | 退款原因，展示在退款账单详情 |
| query_options | 否 | 额外返回字段：`refund_detail_item_list` / `deposit_back_info` / `refund_voucher_detail_list` |

**核心规则**：

1. 支持单笔交易分多次退款，每次需用不同的 `out_request_no`；同一笔退款重试时 `out_request_no` 不可变更
2. 累计退款金额不能超过原始交易总金额
3. 同一笔交易的退款请求至少间隔 **3 秒**
4. **退款成功判断**：`code=10000` 仅代表请求成功，不代表退款成功；以 `fund_change=Y` 为退款成功，`fund_change=N` 或无此字段需调用退款查询接口确认（查询需间隔退款请求 **5 秒以上**）
5. 退款原订单涉及分账时，分账接收方需在商家平台开启分账回退授权；不支持接收方为个人的分账单退款
6. 裸退款不会触发订阅变更通知，订阅状态不自动变更；如需终止订阅请用「订阅取消并退款」

**场景选择**：
- 用户主动退订 → 订阅取消并退款（`CANCEL`）
- 商家补偿、多扣返还等只涉及资金、无需变更订阅 → 裸退款（`alipay.trade.refund`）

> 完整参数（含退分账明细 `refund_royalty_parameters`、退商品明细 `refund_goods_detail`）、响应字段、业务错误码与退款成功判断详见：[API 完整参考 - 退款接口](references/api-complete.md)

---

#### 4.8 关闭订阅（非托管模式）

**接口**：`alipay.trade.subscription.apply.close`

非托管模式下，商户主动关闭 INCOMPLETE 状态的订阅，关闭指定 DRAFT 状态的支付单，并将订阅状态推进为 INCOMPLETE_EXPIRED。

**关闭订阅示例**：
```json
{
  "subscription_id": "SUB202605200001",
  "order_no": "PAY202605200001"
}
```

**重要参数说明**：

| 参数 | 必填 | 说明 |
|-----|------|------|
| subscription_id | 是 | 订阅ID |
| order_no | 是 | 需要关闭的支付单号 |

**响应示例（成功）**：
```json
{
  "success": true,
  "result_code": "SUCCESS",
  "result_message": "订阅关闭成功",
  "subscription_id": "SUB202605200001"
}
```

**响应示例（失败）**：
```json
{
  "success": false,
  "result_code": "SUBSCRIPTION_NOT_EXIST",
  "result_message": "订阅不存在: SUB202605200001"
}
```

**使用场景与规则**：

| 规则 | 说明 |
|------|------|
| 前置状态 | 订阅必须处于 `INCOMPLETE` 状态 |
| 支付单要求 | 支付单必须属于该订阅，且应为 `DRAFT` 状态 |
| 幂等性 | 订阅已处于 `INCOMPLETE_EXPIRED` 状态时直接返回成功；非 DRAFT 状态支付单幂等跳过，不报错（已支付 `PAID` 状态除外：不允许关闭，会报错） |
| 操作不可逆 | 关闭后订阅不可恢复，PENDING 周期变为 CLOSED，PENDING 订阅项变为 INVALID |
| 并发安全 | 并发调用安全，以最终状态为准 |

**状态转换**：
```
INCOMPLETE (未完成) → INCOMPLETE_EXPIRED (已过期关闭)
```

**适用场景**：
- 非托管模式下商户主动关闭订阅
- 试用期结束或商户主动取消的场景
- 用户创建订阅但未支付，商户需要主动关闭释放资源

---

#### 4.9 商户自助扣款（非托管模式）

**接口**：`alipay.trade.subscription.pay`

**使用场景**：**非托管模式**下，商户收到 `alipay.trade.subscription.pay.notify` 可扣款预通知后，在其给出的 `effective_time_start` ~ `effective_time_end` 扣款窗口内通过此接口发起**同步扣款**。托管模式由支付宝自动扣款，不需要调用此接口。

**关键要点**：
- `out_trade_no` 为**幂等键**：一致则重新唤起原单支付，不一致则重新创单；**支卡通金额变化时必须换新单号**
- `pay_amount` 单位为分（String 格式），不超过支付单金额（订阅核心计算的本期应付金额）
- `expire_time` 可选，格式 `数字+m/h`，范围 5 分钟 ~ 2 小时
- 返回 `status`：PENDING_PAY / PAID / COMPLETED / CLOSED
- **校验拦截**：扣款模式必须非托管、订阅状态必须 ACTIVE、已预约周期末取消（`cancel_at_period_end=true`）的订阅不允许扣款、须在扣款窗口内、金额不超限

> 完整请求/响应参数、status 枚举与错误码见 [API 完整参考 - 商户自助扣款](references/api-complete.md)；请求示例见 [API 请求示例 - 4.5](references/api-examples.md)。

---

#### 4.10 预计退款金额查询

**接口**：`alipay.trade.subscription.estimatedrefund.query`

**使用场景**：商户在取消订阅前，预估当前可退金额，用于向用户展示「取消后将退回多少」。

**关键要点**：
- 请求：`subscription_id`（必填）、`customer_id`（可选，传了须与订阅一致）
- 仅 `ACTIVE` 状态订阅返回 `refundable=true` 及 `estimated_refund_amount`（单位：分）
- 其他状态返回 `refundable=false`，**不返回退款金额**
- 订阅必须属于调用方商户

> 完整参数与响应示例见 [API 完整参考 - 预计退款金额查询](references/api-complete.md)。

---

### 第5步：测试上线

#### 5.1 测试清单

使用测试环境完成以下测试：

| 测试场景 | 预期结果 | 状态 |
|---------|---------|------|
| 创建商品 | 返回 product_id | □ |
| 创建价格 | 返回 price_id | □ |
| 创建客户 | 返回 customer_id | □ |
| 创建订阅-个体 | 返回支付链接 | □ |
| 创建订阅-团体 | 返回支付链接 | □ |
| 创建订阅-免费试用期 | 返回支付链接，pay_amount不传 | □ |
| 创建订阅-低价试用期 | 返回支付链接，pay_amount=实际金额 | □ |
| 创建订阅-优惠券 | 返回支付链接，折扣生效 | □ |
| 用户支付 | 收到异步通知 | □ |
| 验签通过 | 无报错 | □ |
| 权益开通 | 用户状态正确 | □ |
| 订阅升级 | 补差价成功，收到 item_update 通知 | □ |
| 订阅降级 | 下周期生效，收到 item_downgrade 通知 | □ |
| 订阅取消-立即 | 收到 cancel 通知，状态变为 CANCELED | □ |
| 订阅取消-周期末 | 收到 cancel_at_period_end 通知，状态保持 ACTIVE | □ |
| 撤销取消 | 收到 item_cancel_revert 通知，状态恢复 | □ |
| 免费试用生效 | 收到 trialing 通知(无支付单) | □ |
| 付费试用生效 | 收到 trialing 通知(有支付单) | □ |
| 试用转正式 | 收到 active 通知(TRIALING→ACTIVE) | □ |
| 席位扩容 | 补差价成功，数量立即更新 | □ |
| 席位缩容 | 下周期pending_items正确 | □ |
| 关闭订阅 | INCOMPLETE状态订阅关闭成功 | □ |
| 关闭订阅幂等 | INCOMPLETE_EXPIRED状态重复关闭返回成功 | □ |
| 商户自助扣款（非托管） | 收到 pay.notify 后窗口内调用 pay，扣款成功 | □ |
| 预计退款金额查询 | ACTIVE 订阅返回 refundable=true 及金额 | □ |
| 续费成功 | 收到period_extend通知 | □ |
| 试用期结束 | 自动扣款成功 | □ |
| 测试推进-续费 | 测试客户订阅推进续费成功 | □ |
| 测试推进-取消 | 测试客户订阅推进取消成功 | □ |
| 测试推进-降级生效 | 测试客户订阅推进降级生效成功 | □ |
| 测试推进-试用结束 | 测试客户订阅推进试用期结束成功 | □ |

#### 5.2 常见问题排查

| 错误 | 原因 | 解决方案 |
|-----|------|---------|
| INVALID_PARAMETER | 参数格式错误 | 检查 items 是否为数组格式 |
| 验签失败 | 公钥选择错误 | 使用「支付宝公钥」验签 |
| 收不到通知 | 应用网关地址未配置 / 消息未订阅 | 检查商家后台**应用网关地址**是否正确（异步通知推送至此，≠授权回调地址）；确认已在开放平台订阅 `alipay.trade.subscription.changed` 消息 |
| 通知重复处理 | 未做幂等 | 基于 notify_id 实现幂等 |
| item_id 无效 | 扩容/缩容后未更新 | 使用最新的 item_id |

#### 5.3 商家测试推进后台（加速周期场景验证）

接入过程中的续费、取消、降级生效、试用期结束等周期场景，原本依赖定时任务自然触发，测试周期长。支付宝提供**商家测试推进后台**，允许商户针对**测试客户**的订阅自主立即触发周期任务，无需等待到期。

- **后台地址**：<https://b.alipay.com/page/checkout-management/subscription-test/list>
- **适用对象**：仅测试客户（客户系统 `isTest=true`）的订阅，非测试客户会被拒绝
- **是否需开发**：无需开发，后台可视化操作；不影响正式接口接入与线上定时任务
- **使用前必做**：商家通常已通过 `alipay.trade.customer.create` 创建过客户、手里已有 `customer_id`，此时在后台“测试客户管理”选 **“添加已有客户”** 并填入 `customer_id` 完成打标即可，无需重新创建客户（详见指南 1.3 节）

**支持的操作类型**：

| 操作 | 推荐用于验证 |
|------|------------|
| 续费 | `period_extend` / 试用转正式 `active` 通知 |
| 取消订阅 | `cancel_at_period_end` / `cancel` 通知与状态流转 |
| 降级生效 | `item_downgrade` 下周期生效后状态 |
| 试用期结束 | 试用期扣款与 `active`（TRIALING→ACTIVE）通知 |

**使用要点**：
- 提交前先用 `alipay.trade.subscription.query` 确认订阅状态，对照各操作的前置校验（如 续费 要求 `status IN (ACTIVE, TRIALING)` 且 `cancel_at_period_end != true`）
- 任务不存在直接失败、不自动创建；同一订阅并发推进会返回 `CONCURRENT_EXECUTION`
- 推进后以收到的异步通知为准更新本地订阅状态

> 完整操作类型、前置校验、执行流程、错误码与推荐验证路径详见：[商家测试推进后台指南](references/test-advance.md)

> 🔔 **迭代联调小贴士（订阅通知测试地址）**：存量商户迭代开发时线上网关通知地址只能配一个，无法把订阅通知接到测试地址。可在**测试客户**上单独配置一个测试通知地址，系统会自动把该测试客户的通知路由到测试地址、不影响线上。同样以 `isTest=true` 触发，支持 `alipay.trade.subscription.changed` 与 `alipay.trade.subscription.pay.notify`；未配置测试地址则仍走默认线上地址，不丢通知。详见指南第八节。

#### 5.4 上线前检查

- [ ] 应用已上线（小程序需审核通过）
- [ ] 使用生产环境配置（网关地址、密钥）
- [ ] 异步通知地址使用 HTTPS
- [ ] 服务器的 IP 已加入白名单（如配置了）

### ✅ 接入完成！

恭喜你完成支付宝订阅产品接入！🎉

---

## 📚 API 速查表

### 商品管理
- `alipay.trade.product.create` - 创建商品
- `alipay.trade.product.modify` - 修改商品
- `alipay.trade.product.query` - 查询商品

### 价格管理
- `alipay.trade.price.create` - 创建价格
- `alipay.trade.price.query` - 查询价格

### 客户管理
- `alipay.trade.customer.create` - 创建客户

### 订阅管理
- `alipay.trade.subscription.create` - 创建订阅
- `alipay.trade.subscription.query` - 查询订阅
- `alipay.trade.subscription.modify` - 修改订阅（统一接口）
  - modify_type: UPGRADE / DOWNGRADE / CANCEL / REVERT_CANCEL / INCREASE_QUANTITY / DECREASE_QUANTITY
- `alipay.trade.subscription.pay` - 商户自助扣款（**非托管模式专用**，在扣款窗口内同步扣款）
- `alipay.trade.subscription.apply.close` - 关闭订阅（非托管模式，关闭 INCOMPLETE 状态订阅）
- `alipay.trade.subscription.estimatedrefund.query` - 查询预计退款金额（取消前预估可退金额）

### 退款
- `alipay.trade.subscription.modify`（`CANCEL`） - 订阅取消并退款（退款同时终止订阅）
- `alipay.trade.refund` - 裸退款，按原支付单原路退款，不变更订阅状态（支持部分退款、多次退款）

### 消息通知
- `alipay.trade.subscription.changed` - 订阅变更通知（active/trialing/period_extend/item_update/item_downgrade/cancel_at_period_end/cancel/item_cancel_revert）
- `alipay.trade.subscription.pay.notify` - 可扣款预通知（非托管模式）
- `alipay.trade.commercial.batchrefund.changed` - 批量退款状态变化通知（订阅取消并退款的退款最终结果）

### 营销工具
- `alipay.trade.promotion.coupon.create` - 创建优惠券
- `alipay.trade.promotion.coupon.query` - 查询优惠券

### 低代码接入
- `alipay.trade.commercial.order.create` - 获取收银台链接

### 自动续购（AI 行业代扣，独立产品，详见 [auto-renewal.md](references/auto-renewal.md)）
- `alipay.user.agreement.page.sign` - 发起自动续购协议签约
- `alipay.user.agreement.query` - 代扣协议查询
- `alipay.user.agreement.permission.create` - 扣款预通知（创建扣款许可 `deduct_permission`）
- `alipay.trade.pay` - 发起代扣扣款（凭 `agreement_no` + `deduct_permission`）
- `alipay.user.agreement.unsign` - 解约自动续购协议
- 通知类型：签约 `dut_user_sign` / 解约 `dut_user_unsign` / 交易 `trade_status_sync`

### 单笔支付（ONE_TIME 商业订单收银，详见 [single-payment.md](references/single-payment.md)）
- `alipay.trade.commercial.order.create` - 创建商业订单（HOSTED/QR_CODE/PAGE 三种收款形态）
- `alipay.trade.commercial.order.query` - 查询商业订单
- `alipay.trade.commercial.order.close` - 关闭未支付订单（仅 `PENDING_PAY`）
- `alipay.trade.commercial.batchrefund.query` - 查询批量退款结果

### 测试推进（接入验证）
- 商家测试推进后台 - <https://b.alipay.com/page/checkout-management/subscription-test/list>（仅测试客户，支持 续费 / 取消 / 降级 / 试用结束 推进）

---

## 🔗 官方文档链接

### 核心文档
- [个体订阅](https://opendocs.alipay.com/ai-solution/0jg564.md)
- [团体席位订阅](https://opendocs.alipay.com/ai-solution/0jg565.md)
- [营销工具包](https://opendocs.alipay.com/ai-solution/0jg566.md)
- [低代码接入](https://opendocs.alipay.com/ai-solution/0jg567.md)

### 接口文档
- [商品创建](https://opendocs.alipay.com/solution/615bfd8c_alipay.trade.product.create.md)
- [价格创建](https://opendocs.alipay.com/solution/5a02644d_alipay.trade.price.create.md)
- [订阅创建](https://opendocs.alipay.com/solution/7a8012f1_alipay.trade.subscription.create.md)
- [订阅修改](https://opendocs.alipay.com/solution/6cd02c10_alipay.trade.subscription.modify.md)
- [订阅查询](https://opendocs.alipay.com/solution/d6b6c14f_alipay.trade.subscription.query.md)
- [订阅通知](https://opendocs.alipay.com/solution/0a3d608d_alipay.trade.subscription.changed.md)

### 内部参考文档
- [单笔支付接入指南](references/single-payment.md) - 单笔支付（ONE_TIME 商业订单收银）独立能力接入：订单创建/查询/关闭/批量退款查询，含参数、示例、枚举字典、错误码总表
- [自动续购接入指南](references/auto-renewal.md) - 自动续购（AI 行业代扣）独立产品接入：产品介绍、签约/扣款预通知/扣款/解约/变更全流程、验签、公共错误码
- [通知完整指南](references/notification-guide.md) - 消息通知通道、13个场景明细、参数结构、事务回查机制
- [商家测试推进后台指南](references/test-advance.md) - 测试客户周期任务（续费/取消/降级生效/试用期结束）自助推进、前置校验、错误码
- [API 完整参考](references/api-complete.md) - 全部订阅接口参数与示例（含 alipay.trade.refund 裸退款接口）
- [快速开始指南](references/quickstart.md) - 10 分钟完成基本对接（前置条件、最小闭环）
- [开发对接选项](references/dev-options.md) - SDK / 非 SDK / 低代码三种对接方式选型
- [测试环境配置](references/dev-environment.md) - Dev 环境与预发环境配置信息
- [Java 代码示例](references/code-example-java.md) - 完整 Java 语言接入示例
- [团体席位订阅详细指南](references/group-subscription.md) - 团体席位（多数量）订阅接入
- [营销工具包详细指南](references/marketing-tools.md) - 优惠/营销能力接入
- [低代码接入详细指南](references/low-code-integration.md) - 低代码方式接入订阅

### 其他资源
- [支付宝开放平台](https://open.alipay.com/)
- [接口加签方式](https://opendocs.alipay.com/common/02mriz)
- [应用网关配置](https://opendocs.alipay.com/common/02qibh)
- [服务器IP白名单](https://opendocs.alipay.com/common/02kg65)
- [服务端 SDK 下载](https://opendocs.alipay.com/common/02n6z6)

---

## 💡 最佳实践

### 1. 订阅状态管理
订阅状态完整枚举：INCOMPLETE / INCOMPLETE_EXPIRED / TRIALING / ACTIVE / PAST_DUE / UNPAID / PAUSED / CANCELED。推荐 `subscription_status` + `cancel_at_period_end` 组合判断：
- `TRIALING`：试用期中
- `ACTIVE` 且 `cancel_at_period_end=false`：正常订阅
- `ACTIVE` 且 `cancel_at_period_end=true`：待取消（周期结束后失效）
- `PAST_DUE` / `UNPAID` / `PAUSED`：预留状态，当前版本不会流转到（周期扣款失败重试超限后订阅直接自动取消为 CANCELED）
- `CANCELED`：已取消
- `INCOMPLETE`：未完成支付，非托管模式可调用 `alipay.trade.subscription.apply.close` 关闭
- `INCOMPLETE_EXPIRED`：未完成已过期/已关闭，不可恢复

### 2. 团体订阅席位管理
- 扩容：立即生效，需补差价，`item_id` 会变化
- 缩容：下周期生效，`pending_items` 记录待生效数量
- 每次 扩容/缩容 后，保存最新的 `item_id`

### 3. 试用期优化
- 推荐试用期：3-7天
- 试用期结束后自动扣款，建议提前通知用户
- 可在试用期结束前1-2天发送提醒

### 4. 优惠券策略
- 新用户首购：`duration="once"` + 高折扣
- 长期留存：`duration="repeating"` + 中等折扣
- VIP 用户：`duration="forever"` + 专属折扣

### 5. 异步通知处理
- 必须实现幂等处理（推荐使用 subscription_id + change_type + change_date 组合做幂等键）
- 验签必须通过
- 返回 "success" 必须精确匹配（小写，无换行空格）
- 建议使用消息队列处理业务逻辑
- `trialing` 通知需区分免费试用（无 order_no）和付费试用（有 order_no）
- `active` 通知需区分首次支付生效和试用转正式
- `cancel` 通知如有 refund 字段，需同步处理退款逻辑
- `item_downgrade` 通知中 currentPeriodStart/End 已更新为下周期时间
- 非托管模式需处理 `alipay.trade.subscription.pay.notify` 可扣款预通知

### 6. INCOMPLETE 订阅清理
- 用户创建订阅后未支付，订阅处于 `INCOMPLETE` 状态
- 非托管模式下，商户可调用 `alipay.trade.subscription.apply.close` 主动关闭
- 关闭操作不可逆，关闭后订阅状态变为 `INCOMPLETE_EXPIRED`
- 接口支持幂等，重复关闭已过期订阅返回成功
- 建议定期清理超时未支付的 INCOMPLETE 订阅，避免资源占用

---

## ⚠️ 重要注意事项

### 1. 团体订阅特有逻辑
- 商品创建时 `unit_label` 必填
- 创建订阅时必须传 `quantity`
- `item_id` 在每次 扩容/缩容 后会变化
- 缩容时注意 `pending_items` 字段

### 2. 试用期扣款
- 试用期结束前一天 7–8 点在支付宝站内发送扣款预通知（站内消息，不发短信/邮件）
- 结束当天自动扣款
- 扣款失败持续重试，试用期内仍未成功则解约订阅
- 用户可随时取消试用

> 非试用期周期扣款时机（提前 48h 预通知、提前 24h 扣款等）见 4.4.0 节。

### 3. 支付链接使用
- `alipay_jump_schema`：跳转拉起支付宝客户端
- `alipay_schema`：生成二维码扫码支付
- 根据实际场景选择合适的链接类型

### 4. 签名验证
- 公共参数放在 URL 查询字符串
- 业务参数放在 POST body
- 签名字符串中的参数值需要 URL 编码
- 验签必须使用「支付宝公钥」

### 5. 消息通知要点
- 同一 `change_type` 可能对应多个业务场景（如 `active` 可能是首次支付生效或试用转正式），通过 `order_no` 是否为空区分
- `trialing` 通知分免费试用（无支付单）和付费试用（有支付单）两种
- `cancel` 类型如携带 `refund` 字段，需同步处理退款逻辑
- `item_downgrade` 和 `item_cancel_revert` 通知中 currentPeriodStart/End 已更新为下周期
- 非托管模式需关注 `alipay.trade.subscription.pay.notify` 可扣款预通知
- 幂等处理推荐使用 subscription_id + change_type + change_date 组合键

---

## 🎓 常见问题

**Q1: 如何区分个体订阅和团体订阅？**
A: 商品创建时，`unit_label` 必填的是团体订阅，创建订阅时需要传 `quantity`

**Q2: 订阅升级和降级的区别？**
A: 升级立即生效并需补差价，降级下周期生效无需付费

**Q3: 如何实现试用期？**
A: 创建订阅时传入 `trial_period_days` 参数（正整数 3-365）、`trial_desc`（最大 12 字符）。免费试用时不传 `pay_amount`；低价试用（如5元试用7天）时传 `pay_amount` 为实际金额。不允许传 `pay_amount=0`。注意 `trial_period_days` 与 `coupon_id` 互斥；试用期场景不允许选非托管模式。

**Q4: 如何使用优惠券？**
A: 创建优惠券后，在创建订阅或升级时传入 `coupon_id`

**Q5: 低代码接入适合什么场景？**
A: 适合快速验证、商品少、价格简单、研发资源有限的团队

**Q6: 扩容/缩容后 item_id 为什么会变化？**
A: 每次修改订阅项都会生成新的 item_id，需保存最新的 item_id 用于后续操作

**Q7: 如何判断订阅是否会在周期结束后取消？**
A: 检查 `cancel_at_period_end` 字段，true 表示周期结束后取消

**Q8: 试用期状态是什么？**
A: `subscription_status: TRIALING` 表示试用期中

**Q9: 团体订阅 pending_items 是什么？**
A: 缩容时记录待生效的席位数量，下周期才会生效

**Q10: 如何自定义升级费用？**
A: 订阅升级时传入 `pay_amount` 参数（自定义实付金额，须 > 0），不传则系统自动计算差价。注意：升级/扩容的最终支付金额必须大于 0，即使用券抵扣后也不能为 0，故不支持「0 元升级」

**Q11: 关闭订阅和取消订阅有什么区别？**
A: 关闭订阅（`alipay.trade.subscription.apply.close`）适用于 INCOMPLETE 状态的订阅，关闭后不可恢复，状态变为 INCOMPLETE_EXPIRED；取消订阅（`alipay.trade.subscription.modify` 的 `CANCEL` 操作）适用于已生效的订阅（ACTIVE/TRIALING），支持立即取消或周期结束取消，取消后可恢复（REVERT_CANCEL）

**Q12: 关闭订阅支持重复调用吗？**
A: 支持。接口具备幂等性，如果订阅已处于 INCOMPLETE_EXPIRED 状态，再次调用直接返回成功

**Q13: 收到 `active` 通知时如何区分首次支付和试用转正式？**
A: 通过 `order_no` 字段判断：首次支付和试用转正式都有支付单（order_no 非空）。进一步区分可通过查询订阅的 trial_start/trial_end 字段，如有值表示从试用期转正式。

**Q14: 收到 `trialing` 通知时如何区分免费试用和付费试用？**
A: 通过 `order_no` 字段判断：免费试用签约时无支付单（order_no 为空），付费试用有支付单（order_no 非空），同时 pay_amount 大于 0。

**Q15: `alipay.trade.subscription.pay.notify` 是什么？什么时候会收到？**
A: 这是**非托管模式专用**的可扣款预通知，在扣款窗口开始时通知商户可扣款的时间范围（effective_time_start/end）。商户收到后须在窗口内调用 `alipay.trade.subscription.pay` 发起扣款。托管模式由支付宝自动扣款，不会收到此通知。

**Q16: 续费扣款失败时用户会收到什么通知？**
A: 支付宝会通过短信（SMS）和邮件（Email）向用户发送通知，包含商户名、服务名、到期日期和主动支付链接，引导用户完成续费。

**Q17: 接入过程中如何快速验证续费、取消、降级生效、试用期结束等周期场景？**
A: 使用商家测试推进后台（<https://b.alipay.com/page/checkout-management/subscription-test/list>），针对测试客户的订阅自主推进 续费 / 取消 / 降级 / 试用结束 四类周期任务，无需等待定时任务到期。详见 [商家测试推进后台指南](references/test-advance.md)。

**Q19: 订阅退款用「订阅取消并退款」还是「裸退款」？**
A: 看退款目的。需要退款并终止订阅（用户主动退订），用 `alipay.trade.subscription.modify` 的 `CANCEL`；只针对某笔已成功支付单做资金退还、不取消订阅（如多扣返还、客诉补偿），用 `alipay.trade.refund` 裸退款。注意两条路径的退款确认方式不同：取消并退款是异步退款，**接口成功只代表订阅已取消**，退款结果需监听 `alipay.trade.commercial.batchrefund.changed`；裸退款以同步返回的 `fund_change=Y` 或退款查询接口为准。裸退款不会触发订阅变更通知、订阅状态不自动变 `CANCELED`；同一笔退款不要用多个退款产品重复退款。详见 [API 完整参考 - 退款接口](references/api-complete.md)。

**Q20: 如何判断 alipay.trade.refund 是否退款成功？**
A: `code=10000` 只代表请求成功，不代表退款成功。以响应 `fund_change=Y` 为退款成功；`fund_change=N` 或无此字段时需调用退款查询接口确认，且查询需间隔退款请求 5 秒以上。多次退款需用不同 `out_request_no`，同一笔退款重试时该值不可变更（保证幂等），同一笔交易累计退款金额不能超过原交易总金额。

**Q21: 订阅取消并退款后，怎么知道退款到底有没有成功？**
A: 「订阅取消并退款」接口调用成功只代表订阅已被取消，退款是异步处理、不一定成功。退款最终结果需监听 `alipay.trade.commercial.batchrefund.changed`（批量退款状态变化通知）：用通知中的 `request_no` 关联到本次退款批次，再以 `status` 判断结果 —— `SUCCESS` 全部成功、`PARTIAL_SUCCESS` 部分成功、`FAILED` 全部失败；具体每笔明细看 `details` 数组里的 `status`。订阅取消本身则通过 `alipay.trade.subscription.changed` 的 `cancel` 通知感知，若退款金额 > 0 该通知 `refund` 中还带 `refund_payment_order_id`。三个字段是同一个退款单号：`refund_order_id`（接口响应）== `refund_payment_order_id`（cancel 通知）== `request_no`（批量退款通知），用任一即可串起整条链路。

**Q22: 非托管模式如何发起续费扣款？**
A: 非托管模式（`deduct_type=MERCHANT_DEDUCT`）下，支付宝不会自动扣款。商户需在收到 `alipay.trade.subscription.pay.notify` 可扣款预通知后，于其给出的 `effective_time_start` ~ `effective_time_end` 窗口内调用 `alipay.trade.subscription.pay` 主动发起同步扣款（详见 4.9）。要求订阅为非托管模式且状态为 ACTIVE。托管模式调用该接口会被拒绝。

**Q23: 取消订阅前如何向用户展示将退多少？**
A: 调用 `alipay.trade.subscription.estimatedrefund.query`（详见 4.10）查询预计退款金额。仅 ACTIVE 状态订阅返回 `refundable=true` 及 `estimated_refund_amount`（单位：分）；其他状态返回 `refundable=false` 且不返回金额。

---

## 📦 代码示例

### Go 语言示例

详见：[Go 代码示例](references/code-example-go.md)

### Java 语言示例

使用支付宝官方 SDK，参考 [支付宝开放平台 SDK 文档](https://opendocs.alipay.com/common/02n6z6)

### 其他语言

参考 [非 SDK 接入指南](references/non-sdk-integration.md)

---

## 🔧 错误码速查

| 错误码 | 说明 | 解决方案 |
|-------|------|---------|
| INVALID_PARAMETER | 参数格式错误 | 检查参数格式，items 必须为数组，且当前只支持单个订阅项 |
| PRODUCT_NOT_FOUND | 商品不存在 | 检查 product_id 是否正确 |
| PRICE_NOT_FOUND | 价格不存在 | 检查 price_id 是否正确 |
| CUSTOMER_NOT_FOUND | 客户不存在 | 检查 customer_id 是否正确 |
| SUBSCRIPTION_NOT_EXIST | 订阅不存在 | 检查 subscription_id 是否正确 |
| INVALID_SIGN | 签名验证失败 | 检查签名算法、密钥是否正确 |
| SUBSCRIPTION_STATUS_ERROR | 订阅状态异常 | 检查订阅当前状态是否允许该操作 |
| SUBSCRIPTION_STATUS_NOT_UPDATABLE | 订阅状态不允许关闭 | 仅 INCOMPLETE 状态可关闭，INCOMPLETE_EXPIRED 状态幂等返回成功 |
| PAYMENT_ORDER_NOT_EXIST | 支付单不存在 | 检查 order_no 是否正确 |
| REQUEST_PARAM_ILLEGAL | 参数非法（如支付单不属于该订阅、托管模式调用 pay、订阅状态非ACTIVE、customerId 不匹配等） | 按提示信息核对参数与场景 |
| PERMISSION_DENIED | 无权限操作/查询该订阅 | subscription_id 必须属于调用方商户，确认商户号一致 |
| PRODUCT_NOT_SIGNED | 商户未签约产品 | 联系支付宝业务人员开通「支付SaaS 解决方案」 |
| TRADE_CLOSE_CANCEL_SUBSCRIPTION_FAILED | 订阅关闭后状态更新失败 | 系统异常，建议重试 |

完整错误码列表：[错误码文档](references/troubleshooting.md)

---

## 对外兼容性检查清单（codereview 必查，人工维护）

> 本清单是**人工维护的只读校验基线**，开发流程只读取、不修改。当 codereview 发现代码改动触及以下 API 行为时，必须逐条核对代码是否破坏对外契约；若发现代码行为与本清单/本 skill 描述不一致，在《改造影响点 + 存量兼容风险报告》中标注「待人工校准」项，**不阻断 PR**，但须单独建跟踪项由人工校准本文档。
>
> 修订本清单需人工评审，禁止通过开发流程自动改动。

| 改动 API | 必查兼容点 |
|---------|-----------|
| `alipay.trade.subscription.create` | `items` 当前只支持单个订阅项；`coupon_id` 与 `pay_amount`/`quantity`/`trial_period_days` 任意组合互斥；`trial_period_days` 正整数 3-365；`trial_desc` 最大 12 字符；`pay_amount` 不允许传 0；试用期订阅不允许选非托管（`MERCHANT_DEDUCT`）；`deduct_type` 一经选定全生命周期不可改；`extend_params` 支卡通参数仅非托管可传且 `zkt_account_id`/`zkt_amount` 同传同缺 |
| `alipay.trade.subscription.modify`（UPGRADE） | `preserve_billing_cycle` 语义（true 保周期 / false 重置）；最终支付金额必须 > 0，用券抵扣后也不能为 0（不支持 0 元升级）；`pay_amount` 可选（不传则系统算差价）；UPGRADE 与扩容不允许传支卡通参数（支卡通场景不支持升级/席位扩容） |
| `alipay.trade.subscription.modify`（DOWNGRADE） | 下周期生效，不创支付单不算金额；不传 `cancel_at_period_end`；不能传 `pay_amount` |
| `alipay.trade.subscription.modify`（CANCEL） | `cancel_at_period_end` **必传**（true 周末 / false 立即）；`refund_amount` 仅立即取消可传；接口成功只代表订阅已取消，退款结果以批量退款通知为准 |
| `alipay.trade.subscription.modify`（REVERT_CANCEL） | `cancel_at_period_end` 必须传 false |
| `alipay.trade.subscription.modify`（INCREASE/DECREASE_QUANTITY） | 无需传 `price_id`（复用源订阅项）；`items` 只能 1 个且 `item_id` 必填；扩容 target>source、缩容 target<source；不能传 `cancel_at_period_end`；缩容不能传 `pay_amount`，扩容传则须 > 0；扩缩容后 `item_id` 变化 |
| `alipay.trade.subscription.pay`（非托管） | 仅非托管 + ACTIVE 状态 + 扣款窗口内可调；已预约周期末取消的订阅不允许扣款；`out_trade_no` 为幂等键（一致重新唤起、不一致重新创单，支卡通金额变化须换新单号）；`pay_amount` 不超支付单金额（本期应付金额） |
| `alipay.trade.subscription.apply.close`（非托管） | 仅 INCOMPLETE 可关闭，幂等（已 INCOMPLETE_EXPIRED 直接成功）；不可逆 |
| `alipay.trade.subscription.estimatedrefund.query` | 仅 ACTIVE 返回 `refundable=true` 及金额；其他状态 `refundable=false` 不返回金额 |
| `alipay.trade.refund`（裸退款） | 不取消订阅、不发订阅变更通知；`fund_change=Y` 才算退款成功；多次退款用不同 `out_request_no`、同笔重试不可变；累计不超原交易；同笔请求间隔 ≥3s、查询间隔 ≥5s |
| `alipay.trade.subscription.changed`（通知） | change_type 多场景区分（`active` 首次支付/试用转正式、`trialing` 免费试用/付费试用，靠 `order_no` 是否为空区分）；幂等键 subscription_id+change_type+change_date；返回精确 "success" |
| `alipay.trade.subscription.pay.notify`（通知） | 仅非托管模式推送；商户须在窗口内调 pay；托管模式不收到 |
| `alipay.trade.commercial.batchrefund.changed`（通知） | 退款最终结果以此为准；`request_no` == 取消接口 `refund_order_id` == cancel 通知 `refund_payment_order_id`；status: SUCCESS/PARTIAL_SUCCESS/FAILED |

### 通知处理通用兼容点

- 返回必须 `HTTP 200 + "success"`（小写、无换行空格），否则重试
- 重试策略：25 小时内 8 次（2m/10m/10m/1h/2h/6h/15h）
- 必须用支付宝公钥验签
- 幂等必须实现（subscription_id + change_type + change_date 组合键）

### 周期扣款时机兼容点（托管模式，改扣款调度必查）

- 非试用期：周期结束前 48h 且 7-8 点站内预通知（不发短信/邮件）→ 提前 24h 扣款 → 失败重试至周期前 10min → 周期结束仍未成功则取消
- 试用期：结束前一天 7-8 点站内预通知 → 结束当天扣款 → 失败重试至试用期结束 → 仍未成功则解约