> ## Documentation Index
> Fetch the complete documentation index at: https://doc.haipay.net/llms.txt
> Use this file to discover all available pages before exploring further.

# 订阅（历史导航 V20260623）

> 历史订阅支付指南：对比 PayUrl 跳转模式与 JS 嵌入模式，含可用 mode 参数切换普通支付与订阅支付的自定义组合模式、上线要求、争议费用与测试卡号。

HaiPay 订阅支付适用于会员、周期性服务和自动续费场景。这个页面不再堆叠完整参数大表，而是先帮助你理解接入模式、业务约束和实施顺序，再跳转到对应的 API Reference 查看详细字段与调试能力。

> **[快速开始](#quick-start)**
>
> 先看接入步骤、必备能力和推荐阅读路径。

> **[集成模式](#integration-modes)**
>
> 对比 Apple Pay / Google Pay、信用卡组件和组合模式。

> **[核心 API](#core-apis)**
>
> 直接进入订阅申请、查询、取消和退款接口。

> [!WARNING]
>
> * 提供明确的订阅入口、扣款周期说明和退订入口。
> * 在订阅成功以及每次扣款前后，通过邮件或其他站外方式通知用户。
> * 提供可确认的订阅协议，并在用户明确授权后再发起订阅。
> * 保持客服可用，至少覆盖主要运营地区的服务时间。

> [!TIP]
>
> * 信用卡交易在扣款后 180 天内，消费者可能发起争议。
> * 每笔争议会产生 20 美元争议处理费。
> * 如果选择抗辩，将额外产生 20 美元抗辩费。
> * 抗辩成功时，HaiPay 会退还抗辩费；原始争议处理费默认不退。

> [!CAUTION]
>
> PCI DSS 严格禁止在 `WebView` 或 `iframe` 中嵌入信用卡输入页。请始终在受信任的浏览器环境中完成卡信息采集与支付授权，避免合规风险和敏感数据泄露。

## 快速开始

**1. 确认业务模式与前置条件**

先阅读 [接口说明](https://doc.haipay.net/zh/history/V20260623/get-started/api-conventions.md) 和 [订阅流程](https://doc.haipay.net/zh/history/V20260623/api/version2/subscription-process.md)，确认你的场景是自动续费而不是一次性支付。

**2. 选择接入模式**

订阅支付提供两种接入模式：**PayUrl 跳转模式**（服务端获取授权链接，跳转到 HaiPay 托管页面完成支付）和 **JS CDN 嵌入模式**（使用客户端令牌在你自己的页面中嵌入支付组件）。根据你的收银台设计和前端开发能力选择合适的方式。

**3. 接入 API、通知与取消能力**

完成订阅申请后，需要能查询订阅状态、处理扣款回调，并在用户侧提供取消订阅入口。详细字段与调试入口放在本页下方的 API Reference 卡片中。

## 集成模式

订阅支付提供两种接入模式，它们的核心区别在于支付页面由谁承载：

| 对比项 | PayUrl 跳转模式 | JS 嵌入模式 |
| :- | :- | :- |
| 支付页面 | 跳转到 HaiPay 托管的支付页面 | 在商户自己的页面中嵌入支付组件 |
| 前端工作量 | 几乎为零，只需处理跳转 | 需要引入 JS 脚本并监听事件 |
| UI 控制力 | 低，页面样式由 HaiPay 控制 | 高，可自定义主题、布局和交互 |
| 关键返回字段 | 使用响应中的 `payUrl` | 使用响应中的 `clientToken` |
| 适用场景 | 快速接入、对支付页面无定制需求 | 自建收银台、需要沉浸式支付体验 |

**PayUrl 跳转模式**

最简单的接入方式。商户服务端调用订阅申请接口后，使用返回的 `payUrl` 将用户跳转到 HaiPay 托管的支付页面，用户在该页面完成授权和首笔支付。

**接入流程**

**1. 服务端调用订阅申请接口**

商户服务端向 HaiPay 发起 [订阅申请](https://doc.haipay.net/zh/history/V20260623/api-reference/subscription/api/subscriptionApply.md)，在请求中传入订阅金额、周期、回调地址等必要参数。

**2. 获取 payUrl 并跳转**

接口返回中包含 `payUrl` 字段，商户将用户浏览器重定向到该地址。

**3. 用户完成支付**

用户在 HaiPay 托管页面完成信用卡信息填写和支付授权。支付完成后，HaiPay 会将用户重定向回商户的 `callBackUrl`，同时向 `notifyUrl` 发送异步通知。

**示例代码（服务端获取 payUrl 后的前端跳转）**

```javascript theme={null}
// 假设你的服务端已调用订阅申请接口，并将 payUrl 返回给前端
const payUrl = response.data.payUrl;

// 在当前窗口跳转
window.location.href = payUrl;

// 或者在新窗口打开
// window.open(payUrl, '_blank');
```

**适用建议**

* 希望最快速度完成订阅接入，前端改动最少。
* 对支付页面的 UI 没有强定制需求。
* 移动端 H5 场景下，跳转体验通常也能满足需求。

**JS 嵌入模式**

通过引入 HaiPay JS 脚本，将支付组件直接嵌入商户页面。商户服务端调用订阅申请接口获取 `clientToken`，前端使用该令牌初始化组件，用户无需跳转即可在当前页面完成订阅支付。

JS 提供以下组件形态，请根据收银台设计需求选择：

**自定义组合模式**

与组合模式类似，但额外支持通过 `mode` 参数切换普通支付与订阅支付，适合需要统一管理多种支付场景的商户。

**引入脚本**

`https://cashier.haipay.top/js/composite-component_1.0.0.min.js`

**配置参数**

| 参数 | 必填 | 说明 |
| :- | :- | :- |
| `sandbox` | 是 | `true` 为测试环境，`false` 为生产环境 |
| `clientToken` | 是 | 订阅申请接口返回的客户端令牌 |
| `mode` | 是 | 支付场景：`payment`（普通支付）或 `subscription`（订阅支付） |
| `showPayButton` | 否 | 是否显示信用卡提交按钮，默认 `false`（不显示） |
| `themeMode` | 否 | 主题模式，可选 `light` / `dark`，默认 `light` |
| `paymentMethodConfig` | 否 | 支付方式组合，默认 `["GOOGLE_PAY","APPLE_PAY","CREDIT_CARD"]` |
| `applePayButtonType` | 否 | Apple Pay 按钮文案，可选 `buy`、`subscribe` 等 |
| `googlePayButtonType` | 否 | Google Pay 按钮文案，可选 `buy`、`subscribe` 等 |
| `cardPosition` | 否 | 信用卡放置位置，默认 `bottom`，可选：`bottom`、`top` |

**事件回调**

* `ready` — 组件渲染完成，可进行交互
* `error` — 初始化失败或支付过程出错
* `confirm` — 表单提交结果（成功/失败）
* `paymentStatus` — 支付结果通知，失败会返回错误信息（若未监听，组件将自动处理支付结果展示）
* `paymentMethodType` — 当前选中的支付方式

**适用建议**

* 需要在同一套代码中同时支持普通支付和订阅支付时，推荐此模式。
* 如仅开放部分支付方式，只需传入所需的组合即可。

```javascript theme={null}
<script src="https://cashier.haipay.top/js/composite-component_1.0.0.min.js"></script>

<div>
  <div id="paymentId"></div>
</div>

const elements = haiPay.create({
  mode: 'payment',
  sandbox: true,
  clientToken: 'your-client-token',
  themeMode: 'light',
  paymentMethodConfig: ['GOOGLE_PAY', 'APPLE_PAY', 'CREDIT_CARD']
});

elements.mount('#paymentId');

elements.on('ready', (event) => {
  console.log('rendered successfully:', event);
});

elements.on('error', (event) => {
  console.error('Payment error:', event);
});

elements.on('paymentMethodType', (event) => {
  console.log('payment method type', event);
});

elements.submitCardPayment();

elements.on('confirm', (event) => {
  console.log('confirm:', event);
});

elements.on('confirm', (event) => {
  console.log('confirm:', event);
});

elements.on('paymentStatus', (event, message) => {
  console.log('payment status:', event, message);
});

```

**Apple Pay / Google Pay（即将废弃）**

> [!WARNING]
>
> 该组件即将废弃，推荐使用「自定义组合模式」替代。

适合已具备钱包支付入口、希望快速拉起 Apple Pay / Google Pay 授权的场景。

**引入脚本**

`https://cashier.haipay.top/js/applePayGooglePaySubscribe_1.0.0.min.js`

**配置参数**

| 参数 | 必填 | 说明 |
| :- | :- | :- |
| `sandbox` | 是 | `true` 为测试环境，`false` 为生产环境 |
| `clientToken` | 是 | 订阅申请接口返回的客户端令牌 |
| `buttonType` | 否 | 按钮文案类型，可选 `buy`、`subscribe` 等 |
| `buttonTheme` | 否 | 按钮主题色，可选 `black`、`white` |
| `buttonHeight` | 否 | 按钮高度（px），默认 `50` |

**事件回调**

* `ready` — 按钮渲染完成，可进行交互
* `error` — 初始化失败或支付过程出错
* `paymentStatus` — 支付结果通知（若未监听，组件将自动处理支付结果展示）
* `paymentMethodType` — 当前选中的支付方式

```javascript theme={null}
<script src="https://cashier.haipay.top/js/applePayGooglePaySubscribe_1.0.0.min.js"></script>

<div>
  <div id="applePayGooglePayId"></div>
</div>

const elements = applePayGooglePaySubscribe.create('applePayGooglePaySubscribe', {
  sandbox: true,
  clientToken: 'your-client-token',
  buttonType: 'subscribe',
  buttonTheme: 'black',
  buttonHeight: 50
});

elements.mount('#applePayGooglePayId');

elements.on('ready', (data) => {
  console.log('Button rendered successfully:', data);
});

elements.on('error', (data) => {
  console.error('Payment error:', data);
});

elements.on('paymentMethodType', (event) => {
  console.log('payment method type', event);
});

elements.on('paymentStatus', (data) => {
  console.log('payment status:', data);
});
```

**Credit Card（即将废弃）**

> [!WARNING]
>
> 该组件即将废弃，推荐使用「自定义组合模式」替代。

适合需要直接展示信用卡订阅表单、并由商户自行控制提交时机的场景。

**引入脚本**

`https://cashier.haipay.top/js/creditCardSubscription_1.0.0.min.js`

**配置参数**

| 参数 | 必填 | 说明 |
| :- | :- | :- |
| `sandbox` | 是 | `true` 为测试环境，`false` 为生产环境 |
| `clientToken` | 是 | 订阅申请接口返回的客户端令牌 |
| `cardTheme` | 否 | 表单主题色，默认 `white` |

**事件回调**

* `ready` — 信用卡表单渲染完成，可进行交互
* `confirm` — 表单提交结果（成功/失败）
* `paymentStatus` — 支付结果通知（若未监听，组件将自动处理支付结果展示）

```javascript theme={null}
<script src="https://cashier.haipay.top/js/creditCardSubscription_1.0.0.min.js"></script>

<div>
  <div id="creditCardId"></div>
</div>

const elements = creditCardSubscription.create('card', {
  sandbox: true,
  clientToken: 'your-client-token',
  cardTheme: 'white'
});

elements.mount('#creditCardId');

elements.on('ready', (data) => {
  console.log('Card rendered successfully:', data);
});

elements.on('error', (data) => {
  console.error('Payment error:', data);
});

elements.submit();

elements.on('confirm', (data) => {
  console.log('confirm:', data);
});

elements.on('paymentStatus', (data) => {
  console.log('payment status:', data);
});
```

## 核心 API

详细请求字段、响应结构和在线调试，请直接进入 API Reference：

> **[订阅申请](https://doc.haipay.net/zh/history/V20260623/api-reference/subscription/api/subscriptionApply.md)**
>
> 创建订阅订单，拉起用户授权并完成首笔订阅支付。

> **[查询订阅](https://doc.haipay.net/zh/history/V20260623/api-reference/subscription/subscription-query.md)**
>
> 查询订阅状态、平台订阅号和扣款记录。

> **[取消订阅](https://doc.haipay.net/zh/history/V20260623/api-reference/subscription/subscription-cancel.md)**
>
> 由商户主动发起取消，停止后续周期扣款。

## 异步通知

当订阅状态变更或周期扣款完成时，HaiPay 会向商户在订阅申请时提供的 `notifyUrl` 推送异步通知。

> [!TIP]
>
> 为保障接口的扩展性和兼容性，请遵循以下回调参数接收方式：
>
> 1. **禁止**声明具体 POJO 对象接收回调参数。
> 2. **必须**使用通用数据结构（如 JSONObject、Map 等）进行参数解析。
> 3. 此设计可确保后续扩展回调字段时，不会影响验签逻辑。

收到通知后，请在响应体中返回 **SUCCESS**（大写）。

**订阅状态通知**

当订阅状态发生变更时触发（如订阅成功、订阅取消、订阅失败等）。

| 参数名 | 类型 | 说明 |
| :- | :- | :- |
| `type` | String | 通知类型，固定为 `SUBSCRIPTION` |
| `appId` | Long | 业务 ID |
| `currency` | String | 币种 |
| `subscriptionOrderId` | String | 商户订阅号 |
| `subscriptionNo` | String | 平台订阅号 |
| `amount` | String | 订阅金额 |
| `status` | Integer | 订阅状态（1: 处理中, 2: 订阅成功, 3: 订阅失败, 4: 订阅取消, 5: 订阅完成） |
| `recurringInterval` | String | 循环周期类型（D/W/M/Y） |
| `recurringIntervalCount` | Integer | 循环周期间隔 |
| `subject` | String | 订阅标题 |
| `sign` | String | 签名（需要使用币种对应的业务密钥信息进行验签） |

**订阅扣款通知**

当每期周期扣款成功或失败时触发。

| 参数名 | 类型 | 说明 |
| :- | :- | :- |
| `type` | String | 通知类型，固定为 `SUBSCRIPTIONS_DEDUCT` |
| `appId` | Long | 业务 ID |
| `currency` | String | 币种 |
| `subscriptionOrderId` | String | 商户订阅号 |
| `subscriptionNo` | String | 平台订阅号 |
| `deductNo` | String | 扣款编号 |
| `orderNo` | String | 平台订单号 |
| `amount` | String | 本次扣款金额 |
| `status` | Integer | 扣款状态（2: 成功, 3: 失败） |
| `startTime` | String | 本期扣款周期开始时间，格式: yyyy-MM-dd HH:mm:ss |
| `endTime` | String | 本期扣款周期结束时间，格式: yyyy-MM-dd HH:mm:ss |
| `sign` | String | 签名（需要使用币种对应的业务密钥信息进行验签） |

## 关键业务规则

| 项目 | 说明 |
| :- | :- |
| 交易限额 | 订阅金额范围为 `0.99 - 1000 USD` |
| 周期上限 | 无论周期单位是什么，最长订阅时长不能超过 3 年 |
| 周期单位 | Apple Pay 不支持 `W`，周订阅请改用 `D` + `7` 天 |
| 支付类型 | 订阅场景固定使用 `SUBSCRIPTION` |
| 用户通知 | 订阅成功、扣款前、扣款后都建议向用户发送站外通知 |
| 退订能力 | 生产环境必须在用户侧提供清晰、可访问的取消订阅入口 |
| 支付方式参数 | 订阅申请接口中 `inBankCode` 和 `paymentMethods` 二选一：`inBankCode` 传入单个支付方式编码，`paymentMethods` 传入英文逗号分隔的支付方式列表。`paymentMethods` 暂时仅支持前置组件组合模式使用 |

## 测试卡号

> [!WARNING]
>
> 仅限测试环境使用

**模拟支付成功**

使用以下测试卡号，CVC 填写任意 3 位数字，有效期填写任意未来日期：

* `4242424242424242`

**模拟支付失败**

使用以下测试卡号并填写无效信息：

* 卡号：`4000000000009995`
* 无效月份：`13`
* 无效 CVV：`99`

## 常见理解问题

> **什么时候看这个页面，什么时候看 API Reference？**
>
> 这个页面用于理解产品能力、选择接入模式和把握业务规则。进入开发联调阶段后，请直接查看 [订阅 API Reference](https://doc.haipay.net/zh/history/V20260623/api-reference/subscription/api/subscriptionApply.md) 获取完整字段、示例报文和调试入口。

> **为什么订阅业务必须强调退订入口和站外通知？**
>
> 订阅类交易更容易产生用户争议。清晰的授权、通知和退订能力可以显著降低拒付、投诉和风控问题，这也是订阅业务能否稳定上线的关键前置条件。

> **生产环境出现 Unsupported region: CN 怎么处理？**
>
> 这通常表示当前生产环境不支持该地区，或当前测试方式与目标地区配置不匹配。请先确认商户配置、目标市场和支付方式组合，再联系 HaiPay 支持团队确认生产可用范围。

> **PayUrl 跳转和 JS CDN 嵌入应该怎么选？**
>
> 如果你希望最快上线、前端改动最少，选 PayUrl 跳转模式即可。如果你需要自定义收银台 UI、希望用户不离开你的页面完成支付，选 JS CDN 嵌入模式。两种模式都通过同一个订阅申请接口发起，区别只在于你使用返回的 `payUrl` 还是 `clientToken`。

> **inBankCode 和 paymentMethods 应该传哪个？**
>
> 两个参数二选一，不可同时传入，也不可同时为空。如果只使用一种支付方式，传 `inBankCode`；如果需要同时支持多种支付方式（如组合模式），传 `paymentMethods`。注意 `paymentMethods` 暂时仅支持前置组件组合模式使用，其他模式请继续使用 `inBankCode`。

> **如果只想尽快做一个现代化订阅页面，推荐哪种模式？**
>
> 如果选择 JS CDN 嵌入模式，优先使用"组合模式"。它能在一个容器内统一呈现多种支付方式，页面更完整，用户理解成本更低，前端开发量也更可控。

## 相关主题

* [公共接口](https://doc.haipay.net/zh/history/V20260623/api/version2/CommonApi.md)
* [HaiPay 接口说明与公共规则](https://doc.haipay.net/zh/history/V20260623/get-started/api-conventions.md)
* [订阅支付流程图](https://doc.haipay.net/zh/history/V20260623/api/version2/subscription-process.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.