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

# 交易生命周期

> 一笔刷卡消费如何从商户终端流转到你的总账——授权、清算、结算、撤销与退款——以及 Fluz 在每个阶段记录了什么。

在一张由 Fluz 签发的卡上完成的一次消费，并不是单一事件。它是商户、卡网络与 Fluz 之间的一次对话，可能持续几秒、几小时，甚至数周——并且在结束前会在你这边生成多条记录。

本页说明每个阶段发生的事、每个阶段会产生哪些 Fluz 记录与 webhook，以及容易让一个天真的集成在算术上出错的地方。

<Note>
  本页涵盖的是**开放式卡交易**——在卡网络上由 Fluz 签发的虚拟卡的消费。礼品卡购买、充值、提现与钱包转账不经过此生命周期；它们在各自的轨道上结算。参见 [Transactions Overview](/features/transactions-details-overview) 获取承载上述所有类型的统一总账。
</Note>

***

## 三个阶段

| Stage             | 发生了什么                                     | 谁的钱在动               |
| :---------------- | :---------------------------------------- | :------------------ |
| **Authorization** | 网络向 Fluz 询问该卡是否可被扣款。Fluz 检查卡片控制与资金，并作出回应。 | 仍未发生。资金被**预留**，未动账。 |
| **Clearing**      | 商户提交最终金额。Fluz 用预留资金完成入账。                  | 预留变为真实借记。           |
| **Settlement**    | 网络在收单行与发卡行之间划拨资金。                         | 银行对银行。对你的集成不可见。     |

结算是一个在清算之后按网络自身节奏运行的银行流程。Fluz 将清算与结算表示为一个事件——当 Fluz 上一笔交易被清算时，就将其视为最终。

***

## 一次消费，多条记录

一笔消费可能产生一次授权、一次或多次清算，且可能出现撤销或退款。Fluz 通过三种查询对外暴露它们，分别回答不同的问题：

| Feed                        | Query                        | 展示内容                         |
| :-------------------------- | :--------------------------- | :--------------------------- |
| **Card activity**           | `getVirtualCardTransactions` | 一张或多张卡的消费，包含商户、MCC、外汇与网络响应字段 |
| **Account ledger**          | `getTransactions`            | 账户上的每一笔资金变动，并在每条记录后给出余额快照    |
| **Declined authorizations** | `getDeclinedTransactions`    | 被拒绝且从未成为交易的授权                |

三笔消费，以及它们各自留下的记录：

```text theme={null}
Acme Hardware — $50.00
├── Authorization        $50.00 debit      held against the card
└── Clearing             $50.00 debit      hold converted, record final

Riverside Hotel — $240.00
├── Authorization       $200.00 debit      pre-auth at check-in
├── Incremental auth     $75.00 debit      incidentals added mid-stay
└── Clearing            $240.00 debit      final folio, less than authorized

Acme Hardware — $50.00, later refunded
├── Authorization        $50.00 debit
├── Clearing             $50.00 debit
└── Refund               $50.00 credit     separate record, not a reversal
```

<Warning>
  **退款是一条新记录，而不是对旧记录的编辑。**

  退款以独立的 `REFUND` 交易到达。原始 `PURCHASE` 记录不会发生任何变化——其金额保持不变。如果你的系统在退款入账后减少原始购买金额，你会把这笔入账的贷记重复计算。请在记录层面做核对；绝不要修改原始记录。
</Warning>

***

## 单报文与双报文流程

网络发送的报文数量取决于商户与交易类型。两种流程都很常见，你的集成必须同时处理。

### 单报文

网络发送一条同时完成授权与清算的报文。常见于 PIN 借记、ATM 取现与交通出行。不存在待处理窗口——交易几乎立即成为最终状态。

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant M as Merchant
    participant N as Card network
    participant F as Fluz
    participant Y as Your integration

    M->>N: Purchase, $25.00
    N->>F: Authorize and clear
    F->>F: Spend controls + funding check
    F-->>N: Approved
    N-->>M: Approved
    F->>Y: TRANSACTION_CREATE
    F->>Y: TRANSACTION_UPDATE (cleared)
```

### 双报文

网络先发送授权，商户稍后提交清算——通常是当晚的批量，也可能在酒店、租车与旅行等场景中延迟数日。两者之间的间隔即“待处理窗口”，大多数对账错误都发生在这里。

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant M as Merchant
    participant N as Card network
    participant F as Fluz
    participant Y as Your integration

    M->>N: Authorization request, $50.00
    N->>F: Authorize
    F->>F: Spend controls + funding check
    F-->>N: Approved, funds held
    N-->>M: Approved
    F->>Y: TRANSACTION_CREATE (pending)

    Note over M,F: Hours to days pass

    M->>N: Batch submitted, $54.00 with tip
    N->>F: Clear
    F->>F: Match to authorization, finalize
    F->>Y: TRANSACTION_UPDATE (cleared, $54.00)
```

<Note>
  **清算金额可能与授权金额不同。** 小费、加油、货币转换与分批发货都会导致清算金额高于或低于最初的预留。以清算金额为准，绝不要将授权金额当作最终值。
</Note>

### 资金所在

从账户视角而非网络视角看同一生命周期：

```mermaid theme={null}
stateDiagram-v2
    [*] --> Available: Funds in the spend account
    Available --> Held: Authorization approved
    Held --> Available: Reversal or expiration
    Held --> Cleared: Clearing received
    Available --> Cleared: Single-message transaction
    Cleared --> Credited: Refund received
    Credited --> [*]
    Cleared --> [*]
```

***

## Fluz 在每个阶段记录了什么

| Network message     | 含义                      | Card feed `transactionType` | Ledger `status` | Webhook                                     |
| :------------------ | :---------------------- | :-------------------------- | :-------------- | :------------------------------------------ |
| Verification        | $0.00 或 $0.01 探测以确认卡片有效 | `PURCHASE`，很快被撤销            | `PENDING`，已释放   | `TRANSACTION_CREATE`                        |
| Authorization       | 在等待最终金额期间预留资金           | `PURCHASE`                  | `PENDING`       | `TRANSACTION_CREATE`                        |
| Authorize and clear | 在一条报文中同时批准与完成           | `PURCHASE`                  | `SETTLED`       | `TRANSACTION_CREATE` + `TRANSACTION_UPDATE` |
| Clearing            | 将先前授权的交易最终入账            | `PURCHASE`                  | `SETTLED`       | `TRANSACTION_UPDATE`                        |
| Decline             | 授权被拒绝                   | `DECLINE`                   | *无总账记录*         | `TRANSACTION_DECLINE`                       |
| Reversal            | 在清算前释放的一笔授权             | *预留被释放*                     | 记录已释放           | `TRANSACTION_UPDATE`                        |
| Refund              | 交易清算后返还的金额              | `REFUND`                    | `SETTLED` 贷记    | `TRANSACTION_CREATE`                        |

<Warning>
  **两个数据源，两套状态词汇。**

  * `getVirtualCardTransactions` 返回如 `PROCESSING`、`CLEARED` 等 `transactionStatus` 值。
  * `getTransactions` 返回 `status` 值为 `PENDING` 与 `SETTLED`。

  它们从两个角度描述相同的生命周期。不要编写假设两处词汇一致的代码。→ [How the GraphQL API works](/concepts/graphql)
</Warning>

<Note>
  **拒绝并不是一笔交易。** 被拒绝的授权不会进入账户总账，因此在 `getTransactions` 中任何状态下都不会出现。通过 `getDeclinedTransactions` 查询它们，并在 [Decline Codes](/features/decline-codes) 中读取原因。
</Note>

***

## 授权

当网络请求 Fluz 批准一笔扣款时，Fluz 会基于卡片、账户与卡背后的资金来评估该请求。所有这一切都在远低于一秒内完成，因为网络会超时。

<AccordionGroup>
  <Accordion title="会检查哪些内容" icon="list-checks">
    * 卡片为 `ACTIVE` —— 未被锁定、未过期、未到达 `lockDate`，且未被一次性规则消耗
    * 金额符合卡片 `spendLimit` 及其 `spendLimitDuration`
    * 若卡片发行于品牌锁定的计划，商户需匹配该品牌锁
    * 账户持有人已通过身份验证
    * 卡背后的资金来源可覆盖该金额
    * 银行计划自身的限额未被超出
  </Accordion>

  <Accordion title="资金来自哪里" icon="wallet">
    卡本身不持有余额。它会在授权时从开卡时配置的资金栈中扣取：

    1. `userCashBalanceId` 指定的消费账户，或账户默认值
    2. 预付（礼品卡）余额，除非 `usePrepaymentBalance: false`
    3. 奖励余额，除非 `useRewardsBalance: false`
    4. 外部银行账户，当 `primaryFundingSource` 为 `BANK_ACCOUNT`

    超过上述来源可覆盖范围的授权会被拒绝，即便卡片的 `spendLimit` 更高。→ [Manage Virtual Card Funding Sources](/Manage-Virtual-Card-Funding-Sources)
  </Accordion>

  <Accordion title="批准金额 vs 请求金额" icon="equal-not">
    网络会请求一个金额；Fluz 会记录其批准的金额。在部分批准时两者会不同，被预留的是批准金额。请从 Fluz 记录读取金额，而不是假设它与商户请求一致。
  </Accordion>

  <Accordion title="拒绝" icon="circle-x">
    被拒的授权会向商户返回响应码，并在 Fluz 侧生成 `declineReason` 与 `declineCategory`。最常见原因包括超出消费限额、卡被锁定、卡背后资金不足、品牌锁卡在错误商户处使用，以及 CVV 或 AVS 不匹配。→ [Decline Codes](/features/decline-codes)
  </Accordion>
</AccordionGroup>

### 非购买类授权

| Type              | 含义                     | 如何处理                  |
| :---------------- | :--------------------- | :-------------------- |
| $0 / $**0.01 探测** | 商户在存卡或延后扣款前确认卡片有效      | 预期会出现，不计入消费。它会自行撤销。   |
| **预授权**           | 在最终金额未知前先行预留——酒店、租车、加油 | 预期会有不同金额的清算，且常在数日后到达。 |
| **增量授权**          | 堆叠在未结清的预授权之上的额外预留      | 汇总预留，不要把第二笔当作第二次购买。   |
| **加油机**           | 按网络规则设定的固定金额，与实际加油无关   | 清算记录携带真实金额。           |

### 资金预留

已批准的授权会减少该卡可继续消费的额度，但不会把钱从账户中划出。在清算之前：

* 卡的 `remainingBalance` 体现该预留
* 总账记录处于 `PENDING`
* `expectedClearedDate` 告诉你何时再查看

若清算从未到达，预留并不会永远保留——网络的到期规则会释放它，资金回到卡的可用余额。大多数授权在约一周内到期；差旅与住宿类预留更久。具体窗口由网络与商户决定，而非 Fluz。

***

## 撤销

撤销是在清算之前取消一笔授权。预留被释放，资金回到卡上。撤销可以是全部或部分。

常见原因：

* 商户放弃了交易，或终端超时
* 商品缺货，或持卡人在发货前取消
* 发送了重复授权
* 授权在未清算的情况下到期

<Warning>
  **清算之后的“撤销”实际上是退款。**

  一旦交易被清算，就不再有可释放的预留。此后返回的资金将以贷记形式到达——一条独立的 `REFUND` 记录——并应按此处理。是否存在匹配的清算记录，是区分两种情形的分界线。
</Warning>

***

## 清算与结算

清算是商户提交最终金额，通常作为隔夜批处理的一部分。Fluz 使用网络的参考标识符将其与未结清的授权匹配，并将记录最终化。

需要为之做好准备的现实情况：

* **金额会变化。** 小费、加油、外汇与分批发货都会改变数额。
* **可能有多次清算。** 分批发货会针对同一授权分段清算，且分段可能乱序到达。
* **可能出现无授权的清算。** 在某些情况下，网络允许商户强制入账——离线终端、机上购买、交通费用汇总。Fluz 会监控这些，但你的总账必须接受一笔一开始就已清算、且没有待处理阶段的购买。
* **匹配并非保证成功。** 罕见情况下，清算上的标识符与其对应授权对不上，清算会作为独立记录出现。

<Warning>
  **不要仅依赖网络参考标识符进行对账。** 它们不保证在交易全生命周期内保持一致，且在不同网络之间不稳定。请在你创建订单时，将 Fluz 的 `record_id` 与 `reference_id` 存储到你自己的订单上。→ [Reconciling against your own system](/features/transactions-details-overview#reconciling-against-your-own-system)
</Warning>

***

## 退款

商户退回金额会通过网络发送一笔贷记。Fluz 会在卡级数据源上记作 `REFUND`，并在总账上记作一笔贷记。它可能先以授权到达、稍后清算，也可能直接以清算到达。

两个会打破天真匹配的情形：

* **未关联退款。** 网络可能在没有原始购买引用，或使用了不同标识符的情况下发送贷记。它会以独立贷记到达，无法与任何记录关联。
* **批量退款。** 多笔属于不同原始购买的退款可能共享网络标识符并被分组到达。

因此，不要假设退款与购买是一一对应。将退款作为独立贷记与卡片对账，并让余额成为唯一真实来源。

***

## 外币

以其他货币进行的消费会以 USD 清算，同时在记录上保留原始金额：

| Field                    | 含义                                    |
| :----------------------- | :------------------------------------ |
| `originalCurrencyCode`   | 商户收取的货币的 ISO 4217 代码                  |
| `originalCurrencyAmount` | 原始金额（以最小单位）—— `6300` HKD 表示 HK\$63.00 |
| `currencyConversionRate` | 折算至 USD 的汇率。国内交易为 `1.0`               |

这三个字段会一起返回——要么全部有值，要么全部为空。转换发生在清算时，因此即便商户收取相同金额，外币授权与其清算在 USD 计价上通常也会不同。

***

## 常见报文序列

除两条“幸福路径”外，以下序列也值得纳入测试覆盖。

| Sequence                              | 含义                      |
| :------------------------------------ | :---------------------- |
| `AUTHORIZE_AND_CLEAR`                 | PIN 借记、ATM、交通出行——无待处理窗口 |
| `AUTHORIZE` → `CLEAR`                 | 标准购买流程                  |
| `AUTHORIZE` → `CLEAR`（更高）             | 餐厅在刷卡后添加小费              |
| `AUTHORIZE` → `CLEAR`（更低）             | 分批发货，或酒店账单低于预授权         |
| `AUTHORIZE` → `AUTHORIZE` → `CLEAR`   | 预授权加增量授权，最终一次清算         |
| `AUTHORIZE` → `CLEAR` → `CLEAR`       | 分批发货，分段清算               |
| `AUTHORIZE` → `REVERSAL`              | 清算前放弃交易                 |
| `AUTHORIZE` → `REVERSAL`（部分）→ `CLEAR` | 释放部分预留，其余清算             |
| `AUTHORIZE` → *(expiry)*              | 从未收到清算；到期后释放预留          |
| `CLEAR` with no `AUTHORIZE`           | 强制入账——离线终端、机上、交通费用汇总    |
| `AUTHORIZE` → `CLEAR` → `REFUND`      | 购买后续被退款（全额或部分）          |
| `VERIFICATION` (\$0.00)               | 存卡验证，稍后即被撤销             |

***

## 基于生命周期进行构建

<Steps>
  <Step title="将待处理与已清算视为不同事物">
    切勿将待处理授权显示为已完成购买，且不要将授权与清算相加。如果你只需要一个数字，请汇总已清算记录，并将预留单独展示。
  </Step>

  <Step title="订阅三类交易事件">
    `TRANSACTION_CREATE`、`TRANSACTION_UPDATE` 与 `TRANSACTION_DECLINE`。只监听 create 的集成会让每笔交易永远停留在授权金额。→ [Webhooks](/fluz-dashboard/webhooks)
  </Step>

  <Step title="基于 updatedGte 同步，而非 createdGte">
    一条以 `PENDING` 创建、后来清算的记录会更改其更新时间戳，而不是创建时间戳。基于创建时间的同步会悄然漏掉每一次结算。
  </Step>

  <Step title="基于余额快照对账">
    每条总账记录都携带各余额的事后状态。读取这些字段，而不是自行累加金额——它们已经计入了费用、返现与未结预留。
  </Step>

  <Step title="使处理器具备幂等性">
    Webhook 会重试，清算也可能乱序到达。以 Fluz 记录标识符作为键，使重放成为空操作。
  </Step>
</Steps>

***

## 测试生命周期

预发卡是实际的卡记录，但不在实时网络上，因此交易是对其注入的，而非刷卡产生。你可以演练授权、单独清算、拒绝、撤销、退款与零金额探测——各自产生与生产环境相同的记录与 webhook。

→ [Simulate Virtual Card Transactions](/Simulate-Virtual-Card-Transactions)

***

## 后续步骤

<CardGroup cols={2}>
  <Card title="Transactions Overview" icon="list" href="/features/transactions-details-overview">
    统一总账——记录包含的内容与如何对账。
  </Card>

  <Card title="Get Virtual Card Transactions" icon="credit-card" href="/features/get-virtual-card-transactions">
    卡级活动、筛选、外汇字段与分页。
  </Card>

  <Card title="Get Declined Transactions" icon="circle-x" href="/features/get-decline-transactions">
    从未成为交易的授权。
  </Card>

  <Card title="Decline Codes" icon="triangle-alert" href="/features/decline-codes">
    所有拒绝原因与类别，以及各自的处理建议。
  </Card>

  <Card title="Simulate Virtual Card Transactions" icon="flask-conical" href="/Simulate-Virtual-Card-Transactions">
    在预发卡上放一笔测试消费，观察生命周期的运转。
  </Card>

  <Card title="Webhooks" icon="webhook" href="/fluz-dashboard/webhooks">
    订阅交易事件、验证签名、处理重试。
  </Card>
</CardGroup>
