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

# 模拟卡片交易

> 在预备环境的虚拟卡上放置测试消费——如何请求预授权、清算、拒付或退款，以及如何通过 API 验证结果。

预备环境的虚拟卡是具有真实 BIN 的真实卡片记录，但不在实时支付网络上——没有商户可以刷它们。为验证你的消费、余额和对账逻辑，Fluz 会通过发卡方处理器的测试环境向你的卡注入一次授权。从那一点开始的所有下游路径都是生产代码路径：相同的授权服务、相同的消费控制、相同的总账分录、相同的 webhooks。

<Note>
  **仅限预备环境**

  模拟交易仅存在于预备环境（`https://transactional-graph.staging.fluzapp.com/api/v1/graphql`）。不会发生资金流动，不会产生交换费，也不会向 Mastercard 提交任何内容。在生产环境中，交易只会来自真实的商户活动。
</Note>

<Warning>
  **由 Fluz 触发模拟**

  没有公共的 mutation 可以将交易注入到卡片上。授权模拟发生在发卡方处理器的控制台中，该控制台位于 Fluz 的 PCI 环境内，不对合作伙伴公开。请通过你的集成渠道（共享 Slack 频道或 [partnerships@fluz.app](mailto:partnerships@fluz.app)）告知我们所需的交易，我们会将其运行在你的卡上，通常在同一工作日完成。本页其余内容——发卡、读取结果——均可自助完成。
</Warning>

## 在你请求模拟之前

一次授权会经过完整的控制堆栈，因此未正确设置的卡片会因与你的测试无关的原因而被拒。

<Steps>
  <Step title="账户已通过 KYC">
    只有已验证的账户才能发卡——也才能通过授权。参见 [测试 KYC 流程](/test-kyc-flows) 获取会通过的身份信息。
  </Step>

  <Step title="你拥有一张 ACTIVE 卡">
    使用 `createVirtualCard` 并选择来自[Test Virtual Card Offers](/test-virtual-card-offers)的一个 offer 来发卡。保存好 `virtual_card_id`——我们通过它来定位卡片。
  </Step>

  <Step title="卡已注资且未锁定">
    该卡从你的 Fluz 余额中支取。确认消费限额覆盖你的测试金额，并且卡片未被锁定、未过期、未透支。`getVirtualCardBalance` 可以一眼看到 `remainingBalance`。
  </Step>
</Steps>

## 你可以模拟什么

根据所需选择生命周期中的任意环节。每种情况都会在你这边映射到不同的记录和 webhook。

<AccordionGroup>
  <Accordion title="授权（通过）" icon="circle-check">
    基本情形：在你指定的商户，以你指定的金额进行一次消费。卡片的可用余额会立即减少，交易进入待处理状态。使用它来验证消费控制、余额递减，以及你的 `TRANSACTION_CREATE` 处理器的行为。
  </Accordion>

  <Accordion title="清算（捕获）" icon="receipt">
    跟随授权之后的结算环节，在真实世界中可能会延后几天。我们既可以与授权同步一步完成捕获，也可以让授权保持打开，以便你观察待处理状态，然后再单独请求捕获。第二种方式更贴近生产的演练。
  </Accordion>

  <Accordion title="拒付" icon="circle-x">
    被授权服务拒绝的交易。告诉我们你想看到哪种拒付——由控制导致的拒付（超出消费限额、品牌锁定卡在错误商户、被锁定的卡）或认证拒付（CVV 不匹配）。拒付会包含 `declineReason` 和 `declineCategory`；完整列表见[拒付代码](/features/decline-codes)。
  </Accordion>

  <Accordion title="撤销" icon="rotate-ccw">
    在清算前被释放的授权——例如商户放弃了交易，或终端超时。被占用的金额会返还到卡上。如果你的对账基于授权而非清算，值得测试该情况。
  </Accordion>

  <Accordion title="退款" icon="arrow-left">
    购买清算后全额或部分退回到卡片的金额。它会以 `REFUND` 交易类型出现，而不是减少原交易金额，因此你的总账需要将其作为独立记录处理。
  </Accordion>

  <Accordion title="零金额和 AVS 校验" icon="shield-check">
    一些商户会在扣款前用 $0.00 或 $0.01 的授权探测卡片。它们会作为独立记录出现，并在稍后被撤销。如果你的对账会汇总授权，请测试此情形——它是造成重复计数的常见来源。
  </Accordion>
</AccordionGroup>

## 需要你提供什么

提供得越全，往返就越少。

| 字段                | 必填 | 说明                                |
| ----------------- | -- | --------------------------------- |
| `virtual_card_id` | 是  | 由 `createVirtualCard` 返回。卡号后四位也可。 |
| 金额                | 是  | 单位 USD。                           |
| 结果                | 是  | 通过或拒付——如果是拒付，请注明要演练的原因。           |
| 商户名称              | 否  | 默认为通用测试商户。如果你基于描述符匹配，请设置它。        |
| MCC               | 否  | 如果你在测试基于类别的逻辑，请设置它。               |
| 单步清算              | 否  | 开启则立即捕获；关闭则保留授权为待处理。              |

## 验证结果

一旦我们确认模拟已运行，所有内容都可以通过 API 读取。读取模拟交易与读取真实交易没有任何区别。

<CodeGroup>
  ```graphql Transactions on the card theme={null}
  query {
    getVirtualCardTransactions(input: {
      virtualCardIds: ["<virtual_card_id>"]
      filters: { transactionTypes: [PURCHASE, REFUND, DECLINE] }
    }) {
      virtualCardId
      transactions {
        transactionId
        transactionDate
        transactionType
        transactionStatus
        transactionAmount
        transactionApproval
        transactionResponseCode
        merchantName
        merchantDescriptor
        mcc
      }
    }
  }
  ```

  ```graphql Balance after the spend theme={null}
  query {
    getVirtualCardBalance(input: {
      virtualCardIds: ["<virtual_card_id>"]
    }) {
      virtualCardId
      spentAmount
      remainingBalance
      spendLimit
      spendLimitDuration
    }
  }
  ```
</CodeGroup>

一笔模拟购买应显示为一条 `PURCHASE` 记录，并伴随 `remainingBalance` 的相应减少。拒付会以 `DECLINE` 类型出现，并且不影响余额——拒付也可以通过[获取拒付交易](/features/get-decline-transactions)单独查询。

<Tip>
  卡级别查询只覆盖卡片活动。若要在账户统一总账中与存款和转账一同查看相同事件，请使用 `getTransactions`——参见[交易概览](/features/transactions-details-overview)。
</Tip>

### Webhooks

模拟交易会触发与真实交易相同的事件，这使其成为端到端测试你端点的最简洁方式：

| 事件                    | 触发时机                                           |
| --------------------- | ---------------------------------------------- |
| `TRANSACTION_CREATE`  | 授权被通过。`status` 为 `PENDING`。                    |
| `TRANSACTION_UPDATE`  | 交易被清算。`status` 变为 `SETTLED`。                   |
| `TRANSACTION_DECLINE` | 授权被拒付，并包含 `declineReason` 和 `declineCategory`。 |

如果你请求了不带单步清算的授权，你应当先单独看到 `TRANSACTION_CREATE`，而 `TRANSACTION_UPDATE` 只会在捕获运行后出现。有关负载和签名校验，见 [Webhooks](/fluz-dashboard/webhooks)。

## 故障排查

| 你看到的情况           | 可能原因                                    |
| ---------------- | --------------------------------------- |
| 期望通过却被拒          | 消费限额低于金额、卡被锁定、Fluz 余额不足，或品牌锁定卡在了错误商户使用。 |
| 卡片上没有任何记录        | 模拟运行在了另一张卡上。请确认你提供的 `virtual_card_id`。  |
| 交易一直处于待处理        | 正常——授权尚未被捕获。请请求清算环节。                    |
| 未收到 webhook      | 检查订阅与所需的权限范围；交易本身仍可通过 API 查看。           |
| 对于 \$0.01 扣款余额未变 | 正常，属于 AVS 探测。它会自行撤销。                    |

## 后续步骤

<CardGroup cols={2}>
  <Card title="你的第一笔虚拟卡消费" icon="credit-card" href="/quickstart/create-and-spend-with-a-virtual-card">
    完整的成功路径——选择一个项目、发卡、揭示卡片信息，并跟踪其消费。
  </Card>

  <Card title="获取虚拟卡交易" icon="list" href="/features/get-virtual-card-transactions">
    按类型与日期范围筛选卡片活动，并读取交易上的每个字段。
  </Card>

  <Card title="拒付代码" icon="circle-x" href="/features/decline-codes">
    每一种拒付原因与类别，以及你的应用应如何处理。
  </Card>

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

**想了解更多？** 请通过 [partnerships@fluz.app](mailto:partnerships@fluz.app) 联系我们。与我们的专家交流以获取更多信息或请求演示。
