> ## 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.

# 结账会话

> 托管的结账页面体验

## 概述

结账会话链接通过 POST Session API 动态生成。该 API 返回一个有时效性的链接，指向预填充了客户信息的 Clink 托管结账页面。我们建议为每次客户支付意向创建一个新的会话。

每个结账会话可以进行多次支付尝试，直到完成一笔成功的交易。成功的交易可以是一次性购买或订阅。

## 会话数据

### 状态

* 开放：结账会话已创建但尚未收到成功支付
* 完成：结账会话已通过成功支付完成
* 过期：结账会话已过期，不允许进行更多支付尝试

### 产品和价格

如果你已在控制台配置了产品和价格，你可以直接使用它们的 ID 进行引用。对于基于订阅的循环付款，必须预先创建产品。

对于一次性购买的产品，你可以在 priceDataList 中定义产品详情（名称、单价、数量等）。结账会话将相应显示这些产品详情。

### 订阅排程阶段

对于订阅型结账会话，如果希望客户完成 checkout 后创建的订阅在未来续费边界自动切换套餐，可以在请求顶层传入 `scheduledPhases`。

初始订阅仍由 `productId` 和 `priceId` 决定。每个预约阶段使用订阅价格的 `priceSnapshotId`、目标 `quantity`，并通过 `effectiveCycle` 指定第几次续费边界生效。`sequence` 和 `effectiveCycle` 都从 `1` 开始且必须严格递增，最多 10 个阶段。

请使用 Product API 或 Price API 返回的 `priceSnapshotId`。阶段快照必须是订阅价格、包含有效 recurring 信息，并支持 checkout 的支付币种。`metadata` 可选，最多 10 个键，键名最长 40 个字符，值最长 500 个字符。

### 客户

结账会话包含预填充的客户信息。创建时至少需要提供 `customerId`、`customerEmail`、`referenceCustomerId` 其中一个。如果三个都为空，请求会返回 `CUSTOMER_NOT_FOUND`。

`referenceCustomerId` 是商户侧客户 ID，可用于定位、校验、创建或绑定 Clink 客户。

当传入 `customerId` 时，它是主标识。Clink 会先按 `customerId` 查找客户。如果同时传入 `customerEmail`，邮箱必须与该客户一致。如果同时传入 `referenceCustomerId`，也必须与该客户一致；如果该客户原本没有 `referenceCustomerId`，且该引用 ID 未被其他客户占用，Clink 会自动绑定到该客户。

未传 `customerId` 时，Clink 会使用 `customerEmail` 和/或 `referenceCustomerId` 解析客户：

* 只传 `customerEmail`：按邮箱查找已有客户，找不到则创建新客户。
* 只传 `referenceCustomerId`：按商户侧客户 ID 查找已有客户，找不到则创建新客户。
* 两个都传：两个标识必须指向同一个客户。如果邮箱找到客户 A，引用 ID 找到客户 B，且 A != B，请求会返回 `CUSTOMER_IDENTIFIER_NOT_MATCHED`。如果只有其中一个标识匹配到已有客户，也会返回 `CUSTOMER_IDENTIFIER_NOT_MATCHED`。如果两个都找不到，则创建新客户并带上这两个标识。

最终结账会话只保存解析后的 `customerId`。`customerEmail` 和 `referenceCustomerId` 主要用于定位、校验、必要时创建或绑定客户。

### URLs

使用 `uiMode` 控制结账会话的展示方式：

* `hostedPage`：托管收银台页面
* `elements`：嵌入式收银台

对于托管收银台，我们强烈建议提供 `successUrl` 和 `cancelUrl` 用于结账后的导航。

当 `uiMode` 为 `elements` 时，`returnUrl` 必填。

### 直接拉起二维码支付

`directPaymentQrCodePaymentMethodType` 用于控制在打开收银台时，是否直接拉起二维码支付流程。

目前该字段支持 `CASHAPP` 和 `QRIS`。

该参数仅在以下条件同时满足时生效：

* `paymentMethodType` 与 `directPaymentQrCodePaymentMethodType` 设置为相同值
* 当前收银台支持所选支付方式

行为：

* 生效时，收银台会直接进入二维码支付流程
* 在免密场景下，支付不会被自动完成

以下情况会被忽略：

* 收银台不支持所选支付方式
* `paymentMethodType` 与 `directPaymentQrCodePaymentMethodType` 不一致

允许的值：

* `CASHAPP`
* `QRIS`

### 促销码展示

将 `allowPromotionCodes` 设置为 `true` 可以启用收银台促销码能力。默认情况下，收银台会展示促销码输入框。

如果需要应用促销码但不展示输入框，可以设置 `showPromotionCode` 为 `false`，并传入 `promotionCode`。在这种模式下，`promotionCode` 必填，Clink 会在创建会话时校验该促销码。

### Merchant Reference

Merchant Reference 作为商户内部标识符用于跟踪目的。此参考号将记录在通过结账会话创建的订单中。

<Warning>
  **幂等性**：Clink 不基于 Merchant Reference ID 维护幂等性。<br />
  这些 ID 仅用于将会话与你的内部系统进行对账。使用相同 Merchant Reference ID 创建的多个结账会话将被视为不同的会话。
</Warning>

## 返回与跳转 URL

对于使用 `uiMode: hostedPage` 创建的托管结账会话，Clink 会在支付成功后跳转到 `successUrl`，用户离开流程时跳转到 `cancelUrl`。

在成功跳转过程中，Clink 会将 Session ID 作为 URL 参数附加，便于你通过 Session#Get API 查询会话数据。

`successUrl` 示例：

<Tip>
  * https\://your\_success\_url.com?sessionId=sess\_randoms <br />
  * https\://your\_success\_url.com?custom=xxxxxxxx\&sessionId=sess\_randoms
</Tip>

对于使用 `uiMode: elements` 创建的嵌入式结账会话，`returnUrl` 为必填项。你可以在 URL 中包含 `{ELEMENTS_SESSION_ID}`，Clink 会在返回你的站点前将其替换为创建出的 session ID。

`returnUrl` 示例：

<Tip>
  https\://YOUR\_DOMAIN/complete.html?session\_id={ELEMENTS_SESSION_ID}
</Tip>

## 客户体验

Clink 希望提供一个自适应、高效且标准化的结账体验解决方案。虽然定制选项有限，但界面保持简洁专业的设计。

商户信息和取消 URL 可从左上角访问。产品和价格信息基于 dashboard 配置或 API 输入显示。

可用的支付方式和货币会根据以下因素自动调整：

* 购买类型（一次性或订阅）
* 客户的地理位置

## 快速入门示例

参考以下代码片段快速开始：

<AccordionGroup>
  <Accordion icon="file-json" defaultOpen="true" title="示例代码">
    <Danger>在部署到生产环境之前，请务必充分测试你的代码！</Danger>

    <CodeGroup>
      ```json 无预创建产品的一次性购买 theme={null}
      curl --location --request POST 'https://api.clinkbill.com/api/checkout/session' \
      --header 'X-Timestamp: ${currentMillisecondsTimestamp}' \
      --header 'X-API-Key: ${sk_key}' \
      --header 'Content-Type: application/json' \
      --data-raw '{
          "customerEmail": "customer@example.com",
          "originalAmount": ${amount},
          "originalCurrency": "USD",
          "uiMode": "hostedPage",
          "priceDataList":[
              {
                  "name":"一次性购买",
                  "quantity": 1,
                  "unitAmount":${unitAmount},
                  "currency":"USD"
              }
          ]
      }'
      ```

      ```json 使用预创建产品的购买 theme={null}
      curl --location --request POST 'https://api.clinkbill.com/api/checkout/session' \
      --header 'X-Timestamp: ${currentMillisecondsTimestamp}' \
      --header 'X-API-Key: ${sk_key}' \
      --header 'Content-Type: application/json' \
      --data-raw '{
          "customerEmail": "customer@example.com",
          "originalAmount": ${amount},
          "originalCurrency": "USD",
          "uiMode": "hostedPage",
          "priceId": "${price_id}",
          "productId": "${prd_id}"
      }'
      ```

      ```json 隐藏促销码 theme={null}
      curl --location --request POST 'https://api.clinkbill.com/api/checkout/session' \
      --header 'X-Timestamp: ${currentMillisecondsTimestamp}' \
      --header 'X-API-Key: ${sk_key}' \
      --header 'Content-Type: application/json' \
      --data-raw '{
          "customerId": "cus_xxxxx",
          "originalAmount": 19.99,
          "originalCurrency": "USD",
          "uiMode": "hostedPage",
          "priceId": "price_xxxxx",
          "productId": "prd_xxxxx",
          "allowPromotionCodes": true,
          "showPromotionCode": false,
          "promotionCode": "SAVE10"
      }'
      ```

      ```json 带订阅排程阶段的购买 theme={null}
      curl --location --request POST 'https://api.clinkbill.com/api/checkout/session' \
      --header 'X-Timestamp: ${currentMillisecondsTimestamp}' \
      --header 'X-API-Key: ${sk_key}' \
      --header 'Content-Type: application/json' \
      --data-raw '{
          "customerId": "cus_xxxxx",
          "originalAmount": ${amount},
          "originalCurrency": "USD",
          "uiMode": "hostedPage",
          "priceId": "${initial_price_id}",
          "productId": "${prd_id}",
          "successUrl": "https://YOUR_DOMAIN/success",
          "cancelUrl": "https://YOUR_DOMAIN/cancel",
          "scheduledPhases": [
              {
                  "sequence": 1,
                  "effectiveCycle": 2,
                  "priceSnapshotId": "${growth_price_snapshot_id}",
                  "quantity": 1,
                  "metadata": {
                      "source": "checkout_schedule"
                  }
              },
              {
                  "sequence": 2,
                  "effectiveCycle": 4,
                  "priceSnapshotId": "${scale_price_snapshot_id}",
                  "quantity": 2
              }
          ]
      }'
      ```

      ```json 嵌入式结账（Elements） theme={null}
      curl --location --request POST 'https://api.clinkbill.com/api/checkout/session' \
      --header 'X-Timestamp: ${currentMillisecondsTimestamp}' \
      --header 'X-API-Key: ${sk_key}' \
      --header 'Content-Type: application/json' \
      --data-raw '{
          "customerEmail": "customer@example.com",
          "originalAmount": ${amount},
          "originalCurrency": "USD",
          "uiMode": "elements",
          "returnUrl": "https://YOUR_DOMAIN/complete.html?session_id={ELEMENTS_SESSION_ID}",
          "priceDataList":[
              {
                  "name":"嵌入式结账购买",
                  "quantity": 1,
                  "unitAmount":${unitAmount},
                  "currency":"USD"
              }
          ]
      }'
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>
