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

# 订阅支付

> 从周期价格到首次订阅、续费、取消和升降级的完整流程。

这一页讲周期性收费。订单、Session 和 Webhook 那套基础和一次性支付完全一样，先看过 [Hosted Checkout 接入](/cn/build-integration) 会顺很多。

## 先选路径

三种场景，走的接口不一样：

| 场景                                       | 走哪条                     | 说明                         |
| ---------------------------------------- | ----------------------- | -------------------------- |
| 新客户，或客户还没有可复用的支付工具                       | 周期价格 + Checkout Session | **推荐**。客户在收银台里自己选支付方式并授权   |
| 已有 Clink Customer 和可用 Payment Instrument | `POST /subscription`    | 服务端直接建订阅并发起首笔付款            |
| 已有活跃订阅，客户要换卡、取消、升降级、看账单                  | `POST /billing/session` | 优先交给客户门户；服务端自动化再用查询和更新 API |

<Note>
  `POST /checkout/session` 和 `POST /subscription` 不是同一个接口的两种写法。前者给客户一个可交互的收银台，后者是服务端在已有客户和支付工具时直接下单。
</Note>

## 一、准备周期性商品和价格

订阅**必须**用预先注册的 Product 和周期价格。`priceDataList` 那种临时商品建不了订阅。

```json theme={null}
{
  "productId": "prd_xxxxx",
  "currency": "USD",
  "unitAmount": 29.99,
  "priceType": "recurring",
  "recurringDetails": {
    "interval": "month",
    "intervalCount": 1,
    "trialPeriodDays": 7,
    "pricingModel": "flat_rate"
  },
  "isDefaultPrice": true
}
```

`interval` 支持 `day`、`week`、`month`、`year`、`quarter`、`half_year`、`custom`。

<Note>
  `quarter` 和 `half_year` 是平台自己算周期边界的，你不用把它换算成 3 个月或 6 个月再传。只有 `interval` 为 `custom` 时，`intervalCount` 才表示天数。
</Note>

这一页的示例只用月付的 `flat_rate` 固定价。其他计费模式见 [创建价格](/cn/api-reference/endpoint/create-price) 的字段说明。

## 二、推荐路径：用 Checkout 创建首次订阅

结构和一次性支付一模一样——后端建 Session、前端打开收银台、Webhook 更新本地状态。只是把临时商品换成了周期价格。

```json theme={null}
{
  "customerEmail": "buyer@example.com",
  "merchantReferenceId": "membership_10001",
  "productId": "prd_xxxxx",
  "priceId": "price_xxxxx",
  "originalAmount": 29.99,
  "originalCurrency": "USD",
  "uiMode": "hostedPage",
  "successUrl": "https://merchant.example.com/subscription/success",
  "cancelUrl": "https://merchant.example.com/subscription/cancel"
}
```

金额和币种仍然要传，后端会校验它们和 Product/Price 一致。

<Warning>
  创建 Session 的那一刻，**订阅还不存在，钱也还没收到**。

  客户提交支付后，收银台按周期价格走订阅流程，产生 Subscription、Invoice 和 Order 三个对象。浏览器跳回 `successUrl` 只表示交互结束——最终状态要查接口，并结合验签后的 Webhook 更新。
</Warning>

## 三、服务端路径：直接创建订阅

客户已经有 Clink Customer 和可用支付工具时用这条。

```json theme={null}
{
  "customerId": "cus_xxxxx",
  "merchantReferenceId": "membership_10002",
  "productId": "prd_xxxxx",
  "priceId": "price_xxxxx",
  "paymentInstrumentId": "pi_xxxxx",
  "paymentMethodType": "CARD",
  "paymentCurrency": "USD",
  "returnUrl": "https://merchant.example.com/subscription/return"
}
```

`customerId`、`customerEmail`、`referenceCustomerId` 至少给一个。周期价格必须属于当前商户，并且支持你传的 `paymentCurrency`。

<Note>
  某种支付方式能不能用于订阅，还受商户渠道配置和币种限制影响。上线前按你自己账户实际启用的方式逐一验证，别照抄一张通用清单。
</Note>

返回里的 `status` 是数字，表示**这一次付款**的结果：

| `status` | 含义        | 你该做什么                                |
| -------- | --------- | ------------------------------------ |
| `1`      | 本次支付成功    | 等对应的 Webhook 并幂等处理。**不能只凭这个返回就开通权益** |
| `2`      | 处理中       | 显示处理中并继续查询。不要当成失败去重新扣款               |
| `3`      | 失败        | 记下失败结果，引导客户换支付方式或重试                  |
| `5`      | 需要客户再操作一步 | 按返回的 `action` 打开跳转、二维码或其他验证          |

响应还会带回 `subscriptionId`、`sessionId`、`paymentInstrumentId`、`orderId` 和 `invoiceId`。**这五个都存进你自己的订阅记录**——后面查询和对账时，只靠其中一个字段会不够用。

## 四、订阅状态怎么映射到权益

这是接订阅时最容易做错的地方。付款状态和权益状态是两件事。

| 订阅状态                 | 含义            | 本地权益怎么处理                          |
| -------------------- | ------------- | --------------------------------- |
| `incomplete`         | 订阅建了，首次付款还没完成 | **不要开通付费权益**                      |
| `free_trial`         | 在免费试用期内       | 按你的试用规则开通，记下 `trialEnd`           |
| `active`             | 订阅有效，当前没有未结账单 | 保持权益开启                            |
| `past_due`           | 续费失败，系统还可能重试  | 按你的宽限期策略处理。**不是已支付，也不要立刻再发起一笔扣款** |
| `incomplete_expired` | 首次订阅没完成，超时关闭了 | 关掉这条没生效的订阅流程                      |
| `cancelled`          | 订阅已终止         | 到实际终止时间再回收权益                      |

<Warning>
  **不要拿 `subscription.created` 当作开通付费权益的信号。** 它只说明订阅记录建出来了。

  免费试用由 `subscription.trialing` 驱动；首笔付款和续费要结合 `subscription.activated`、`invoice.paid` 和查询结果做幂等流转。

  权益变化要落到你自己的订阅和账单记录上，不能只更新一个订单状态——订阅是持续关系，一个订单号装不下。
</Warning>

## 五、要订阅哪些事件

一次性支付那套 `order.*` 仍然有效，订阅再加下面这些。

**生命周期**

`subscription.created`、`subscription.trialing`、`subscription.activated`、`subscription.past_due`、`subscription.incomplete_expired`、`subscription.cancelled`

**套餐变更**

`subscription.updated.plan_changed`、`subscription.updated.plan_change_canceled`、`subscription.updated.renewed`、`subscription.updated.cancel_at_period_end_set`、`subscription.updated.cancel_at_period_end_revoked`

**账单**

`invoice.open`、`invoice.paid`、`invoice.void`

<Warning>
  订阅时必须写完整的事件名。`subscription.*` 和 `invoice.*` 这类通配符**不是能提交给 API 的值**。
</Warning>

事件会重试，也不保证顺序。处理器至少要做到：

* 按 `event.id` 原子去重
* 乱序到达时按订阅状态优先级处理，别让旧事件覆盖新状态
* 同一个 `invoiceId` 的履约动作只执行一次

验签、去重和订单匹配的写法见 [Hosted Checkout 接入](/cn/build-integration)。

## 六、取消

```json theme={null}
{
  "reason": "客户主动取消",
  "cancelReasonCode": "no_longer_needed",
  "cancelImmediately": false
}
```

`reason` 必填，1 到 255 个字符。`cancelReasonCode` 可选，取值为 `too_expensive`、`need_more_features`、`found_alternative`、`no_longer_needed`、`poor_customer_service`、`poor_usability`、`poor_quality`、`other_reasons`。

`cancelImmediately` 省略或传 `false` 时，订阅在**当前周期结束时**取消；传 `true` 立即取消。

<Warning>
  **取消不等于退款。** 立即取消不会自动退还本期已收的钱。要退款得单独调 [退款接口](/cn/api-reference/endpoint/create-refund)。
</Warning>

## 七、升降级

必须先预览再确认，两步都要传 `quantity`。

**第一步：预览**

```json theme={null}
{
  "priceId": "price_yyyyy",
  "quantity": 1,
  "promotionCode": "WELCOME20"
}
```

**第二步：用预览返回的 `priceSnapshotId` 确认**

```json theme={null}
{
  "priceSnapshotId": "snap_xxxxx",
  "quantity": 1,
  "promotionCode": "WELCOME20"
}
```

用了优惠码的话，预览和确认要传**同一个码**，否则金额对不上。

`immediate: true` 的变更可能产生补差价付款并返回 `action`；`false` 表示预约到下一个账期边界生效。待生效的变更可以调 `POST /subscription/{id}/update/cancel` 撤销。

<Note>
  当前 API Reference 里 preview 和 confirm 的请求体示例漏了 `quantity`，但服务端把它列为必填。以这一页为准，两个请求都要传。
</Note>

## 八、计划阶段

`scheduledPhases` 可以让订阅在未来的续费边界自动切套餐，最多 10 个阶段，`sequence` 和 `effectiveCycle` 都从 `1` 开始且严格递增。

这是进阶能力，首次接入用不上。字段说明见 [结账会话](/cn/guides/payments/checkout_session)。

## 接下来

<CardGroup cols={2}>
  <Card title="优惠与促销码" icon="ticket-percent" href="/cn/promotions">
    给订阅加折扣，以及折扣持续几个账期。
  </Card>

  <Card title="上线检查" icon="rocket" href="/cn/go-live">
    订阅相关的验收项。
  </Card>
</CardGroup>
