Skip to main content
在一张由 Fluz 签发的卡上完成的一次消费,并不是单一事件。它是商户、卡网络与 Fluz 之间的一次对话,可能持续几秒、几小时,甚至数周——并且在结束前会在你这边生成多条记录。 本页说明每个阶段发生的事、每个阶段会产生哪些 Fluz 记录与 webhook,以及容易让一个天真的集成在算术上出错的地方。
本页涵盖的是开放式卡交易——在卡网络上由 Fluz 签发的虚拟卡的消费。礼品卡购买、充值、提现与钱包转账不经过此生命周期;它们在各自的轨道上结算。参见 Transactions Overview 获取承载上述所有类型的统一总账。

三个阶段

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

一次消费,多条记录

一笔消费可能产生一次授权、一次或多次清算,且可能出现撤销或退款。Fluz 通过三种查询对外暴露它们,分别回答不同的问题: 三笔消费,以及它们各自留下的记录:
退款是一条新记录,而不是对旧记录的编辑。退款以独立的 REFUND 交易到达。原始 PURCHASE 记录不会发生任何变化——其金额保持不变。如果你的系统在退款入账后减少原始购买金额,你会把这笔入账的贷记重复计算。请在记录层面做核对;绝不要修改原始记录。

单报文与双报文流程

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

单报文

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

双报文

网络先发送授权,商户稍后提交清算——通常是当晚的批量,也可能在酒店、租车与旅行等场景中延迟数日。两者之间的间隔即“待处理窗口”,大多数对账错误都发生在这里。
清算金额可能与授权金额不同。 小费、加油、货币转换与分批发货都会导致清算金额高于或低于最初的预留。以清算金额为准,绝不要将授权金额当作最终值。

资金所在

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

Fluz 在每个阶段记录了什么

两个数据源,两套状态词汇。
  • getVirtualCardTransactions 返回如 PROCESSINGCLEAREDtransactionStatus 值。
  • getTransactions 返回 status 值为 PENDINGSETTLED
它们从两个角度描述相同的生命周期。不要编写假设两处词汇一致的代码。→ How the GraphQL API works
拒绝并不是一笔交易。 被拒绝的授权不会进入账户总账,因此在 getTransactions 中任何状态下都不会出现。通过 getDeclinedTransactions 查询它们,并在 Decline Codes 中读取原因。

授权

当网络请求 Fluz 批准一笔扣款时,Fluz 会基于卡片、账户与卡背后的资金来评估该请求。所有这一切都在远低于一秒内完成,因为网络会超时。
  • 卡片为 ACTIVE —— 未被锁定、未过期、未到达 lockDate,且未被一次性规则消耗
  • 金额符合卡片 spendLimit 及其 spendLimitDuration
  • 若卡片发行于品牌锁定的计划,商户需匹配该品牌锁
  • 账户持有人已通过身份验证
  • 卡背后的资金来源可覆盖该金额
  • 银行计划自身的限额未被超出
卡本身不持有余额。它会在授权时从开卡时配置的资金栈中扣取:
  1. userCashBalanceId 指定的消费账户,或账户默认值
  2. 预付(礼品卡)余额,除非 usePrepaymentBalance: false
  3. 奖励余额,除非 useRewardsBalance: false
  4. 外部银行账户,当 primaryFundingSourceBANK_ACCOUNT
超过上述来源可覆盖范围的授权会被拒绝,即便卡片的 spendLimit 更高。→ Manage Virtual Card Funding Sources
网络会请求一个金额;Fluz 会记录其批准的金额。在部分批准时两者会不同,被预留的是批准金额。请从 Fluz 记录读取金额,而不是假设它与商户请求一致。
被拒的授权会向商户返回响应码,并在 Fluz 侧生成 declineReasondeclineCategory。最常见原因包括超出消费限额、卡被锁定、卡背后资金不足、品牌锁卡在错误商户处使用,以及 CVV 或 AVS 不匹配。→ Decline Codes

非购买类授权

资金预留

已批准的授权会减少该卡可继续消费的额度,但不会把钱从账户中划出。在清算之前:
  • 卡的 remainingBalance 体现该预留
  • 总账记录处于 PENDING
  • expectedClearedDate 告诉你何时再查看
若清算从未到达,预留并不会永远保留——网络的到期规则会释放它,资金回到卡的可用余额。大多数授权在约一周内到期;差旅与住宿类预留更久。具体窗口由网络与商户决定,而非 Fluz。

撤销

撤销是在清算之前取消一笔授权。预留被释放,资金回到卡上。撤销可以是全部或部分。 常见原因:
  • 商户放弃了交易,或终端超时
  • 商品缺货,或持卡人在发货前取消
  • 发送了重复授权
  • 授权在未清算的情况下到期
清算之后的“撤销”实际上是退款。一旦交易被清算,就不再有可释放的预留。此后返回的资金将以贷记形式到达——一条独立的 REFUND 记录——并应按此处理。是否存在匹配的清算记录,是区分两种情形的分界线。

清算与结算

清算是商户提交最终金额,通常作为隔夜批处理的一部分。Fluz 使用网络的参考标识符将其与未结清的授权匹配,并将记录最终化。 需要为之做好准备的现实情况:
  • 金额会变化。 小费、加油、外汇与分批发货都会改变数额。
  • 可能有多次清算。 分批发货会针对同一授权分段清算,且分段可能乱序到达。
  • 可能出现无授权的清算。 在某些情况下,网络允许商户强制入账——离线终端、机上购买、交通费用汇总。Fluz 会监控这些,但你的总账必须接受一笔一开始就已清算、且没有待处理阶段的购买。
  • 匹配并非保证成功。 罕见情况下,清算上的标识符与其对应授权对不上,清算会作为独立记录出现。
不要仅依赖网络参考标识符进行对账。 它们不保证在交易全生命周期内保持一致,且在不同网络之间不稳定。请在你创建订单时,将 Fluz 的 record_idreference_id 存储到你自己的订单上。→ Reconciling against your own system

退款

商户退回金额会通过网络发送一笔贷记。Fluz 会在卡级数据源上记作 REFUND,并在总账上记作一笔贷记。它可能先以授权到达、稍后清算,也可能直接以清算到达。 两个会打破天真匹配的情形:
  • 未关联退款。 网络可能在没有原始购买引用,或使用了不同标识符的情况下发送贷记。它会以独立贷记到达,无法与任何记录关联。
  • 批量退款。 多笔属于不同原始购买的退款可能共享网络标识符并被分组到达。
因此,不要假设退款与购买是一一对应。将退款作为独立贷记与卡片对账,并让余额成为唯一真实来源。

外币

以其他货币进行的消费会以 USD 清算,同时在记录上保留原始金额: 这三个字段会一起返回——要么全部有值,要么全部为空。转换发生在清算时,因此即便商户收取相同金额,外币授权与其清算在 USD 计价上通常也会不同。

常见报文序列

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

基于生命周期进行构建

1

将待处理与已清算视为不同事物

切勿将待处理授权显示为已完成购买,且不要将授权与清算相加。如果你只需要一个数字,请汇总已清算记录,并将预留单独展示。
2

订阅三类交易事件

TRANSACTION_CREATETRANSACTION_UPDATETRANSACTION_DECLINE。只监听 create 的集成会让每笔交易永远停留在授权金额。→ Webhooks
3

基于 updatedGte 同步,而非 createdGte

一条以 PENDING 创建、后来清算的记录会更改其更新时间戳,而不是创建时间戳。基于创建时间的同步会悄然漏掉每一次结算。
4

基于余额快照对账

每条总账记录都携带各余额的事后状态。读取这些字段,而不是自行累加金额——它们已经计入了费用、返现与未结预留。
5

使处理器具备幂等性

Webhook 会重试,清算也可能乱序到达。以 Fluz 记录标识符作为键,使重放成为空操作。

测试生命周期

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

后续步骤

Transactions Overview

统一总账——记录包含的内容与如何对账。

Get Virtual Card Transactions

卡级活动、筛选、外汇字段与分页。

Get Declined Transactions

从未成为交易的授权。

Decline Codes

所有拒绝原因与类别,以及各自的处理建议。

Simulate Virtual Card Transactions

在预发卡上放一笔测试消费,观察生命周期的运转。

Webhooks

订阅交易事件、验证签名、处理重试。