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

# 基本支付流程

> 接入前先分清 Checkout Session、Order 和商户订单。

## 一次支付实际发生了什么

<Steps>
  <Step title="客户点「立即购买」">
    商户前端把商品和数量发给商户后端，不直接调用 Clink。
  </Step>

  <Step title="商户后端先建一条商户订单">
    记下买了什么、多少钱、卖给谁。这条记录是商户系统里的真相，后面所有状态都挂在它上面。
  </Step>

  <Step title="商户后端创建 Checkout Session">
    Clink 返回 `sessionId` 和 `url`。`url` 就是收银台地址。
  </Step>

  <Step title="客户在收银台付款">
    选支付方式、输入卡号、过 3DS 验证，全部在 Clink 的页面上完成，商户不接触卡号。
  </Step>

  <Step title="Clink 把结果推给 Webhook">
    付款成功推 `order.succeeded`，失败推 `order.failed`。
  </Step>

  <Step title="商户后端确认收款，然后发货">
    收到事件、验完签、匹配上订单之后，才发货、充值或开通权益。
  </Step>
</Steps>

第 2 步经常被跳过。直接拿 Clink 的 Session 当订单用，对账时就会发现查不到「谁买了什么」——Clink 只知道有人付了 19.99 美元，不知道这笔钱对应商户系统里哪个用户的哪次购买。

## 三个"订单"，别搞混

上面那六步里，有三样东西都能被叫做"订单"：Clink 建的 **Checkout Session**、客户付款产生的 **Order**、以及商户后端自己那条记录。名字像，作用完全不同。

| 对象               | 是什么              | 谁创建               | 用来干什么        |
| ---------------- | ---------------- | ----------------- | ------------ |
| Checkout Session | 一次收银台会话，带时效的支付入口 | Clink（商户调 API 触发） | 把客户送到收银台     |
| Order            | 一笔实际付款的结果        | Clink（客户付款时自动产生）  | 判断钱到底收到没有    |
| 商户订单             | 商户系统里的业务记录       | 商户后端              | 决定要不要发货，以及对账 |

一个 Session 可以产生多笔 Order。客户第一次刷卡失败、换张卡再刷成功，就是两笔 Order 挂在同一个 Session 下。所以判断付款结果要看 Order，不要看 Session。

## 状态怎么读

### Checkout Session

`status` 描述这个支付入口还能不能用：

| Session `status` | 含义               | 对应处理                     |
| ---------------- | ---------------- | ------------------------ |
| `open`           | 入口有效，还能付款        | 等客户付款，或引导客户重新打开收银台       |
| `completed`      | 已经付成功，不再接受新的支付尝试 | 用 `orderId` 查 Order 确认结果 |
| `expired`        | 入口过期，不能再付        | 要继续收款就重建一个 Session       |

`paymentStatus` 另有 `unpaid`、`processing`、`paid` 三个值，适合展示给客户看进度。对账仍然看 Order。

<Warning>
  `expired` 不等于付款失败。客户可能在过期前一刻发起了付款，这笔 Order 稍后才成功。别拿 Session 过期直接把商户订单判死。
</Warning>

### Order

`status` 是付款结果，也是要映射到商户业务状态的那个字段：

| Order `status`     | 含义                  | 对应处理                                               |
| ------------------ | ------------------- | -------------------------------------------------- |
| `success`          | 付款成功                | 幂等地触发发货                                            |
| `pending`          | 处理中，还没有结果           | 等 Webhook，或过一会查 `GET /order/{id}`。**不要重新扣款**       |
| `failed`           | 付款失败                | 记下 `failureCode` 和 `failureMessage`，确认没有在途付款后才允许重试 |
| `requires_action`  | 需要客户再操作一步，比如 3DS 验证 | 按返回的 `action` 引导客户完成验证                             |
| `partial_refunded` | 部分退款                | 更新累计退款金额                                           |
| `refunded`         | 全额退款                | 回收权益或走售后                                           |

`pending` 是最容易出事的状态。它的意思是"还不知道"，不是"失败了"。这时候重新发起扣款，客户很可能被扣两次。

## 什么才能作为发货依据

只有一件事算数：商户后端收到了通过验签的 `order.succeeded` 事件，或主动查 `GET /order/{id}` 拿到了 `success`，并且这笔 Order 能匹配上商户订单。

<Warning>
  下面这几个信号看着像收到钱了，单独出现时都不算：

  * 客户被跳回了 `successUrl`——这个地址谁都能手动敲
  * Session 的 `status` 变成 `completed`——它只说明入口关了
  * Webhook 返回了 HTTP 200——那只是告诉 Clink"收到了"
  * 前端 SDK 触发了 `complete` 或 `session-success`——浏览器里的事件可以被伪造
</Warning>

## 两个环境

Clink 分沙盒和生产两套环境。沙盒就是通常说的测试环境，不动真钱。

|        | 沙盒                                    | 生产                                |
| ------ | ------------------------------------- | --------------------------------- |
| 商户后台   | `https://uat-dashboard.clinkbill.com` | `https://dashboard.clinkbill.com` |
| API 地址 | `https://uat-api.clinkbill.com`       | `https://api.clinkbill.com`       |
| 密钥前缀   | `sk_uat_` / `pk_uat_`                 | `sk_prod_` / `pk_prod_`           |
| 钱      | 不动真钱，可以随便刷                            | 真实扣款                              |

两套环境是两个独立的后台地址，账号和密码共用一套，但数据和密钥完全隔离。沙盒里建的产品、客户、订单，生产环境查不到。

<Warning>
  开发阶段要登录的是沙盒后台 `uat-dashboard.clinkbill.com`。在生产后台初始化出来的密钥以 `sk_prod_` 开头，拿它调沙盒 API 会一路认证失败，而且报错看不出是环境搞错了。
</Warning>

测试卡号 `4242 4242 4242 4242`，CVC 任意 3 位，有效期填任何未来日期。这张卡只在沙盒有效。

## 接下来

<CardGroup cols={2}>
  <Card title="跑通第一笔测试支付" icon="trending-up" href="/cn/quickstart">
    照着做，十几分钟能看到一笔成功订单。
  </Card>

  <Card title="选择接入方式" icon="git-branch" href="/cn/choose-integration">
    收银台是跳走还是嵌在自己页面里。
  </Card>
</CardGroup>
