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

# Simulate Virtual Card Transactions

> Put a test spend on a staging virtual card — how to request an authorization, clearing, decline, or refund, and how to verify the result over the API.

Staging virtual cards are real card records with real BINs, but they aren't on a live payment network — no merchant can swipe them. To exercise your spend, balance, and reconciliation logic, Fluz injects an authorization against your card through the issuer processor's test environment. Everything downstream of that point is the production code path: the same authorization service, the same spend controls, the same ledger entries, the same webhooks.

<Note>
  **Staging only**

  Simulated transactions exist only in the staging environment (`https://transactional-graph.staging.fluzapp.com/api/v1/graphql`). No funds move, no interchange is generated, and nothing is submitted to Mastercard. In production, transactions arrive only from real merchant activity.
</Note>

<Warning>
  **Simulations are triggered by Fluz**

  There is no public mutation that injects a transaction onto a card. Authorization simulation happens in the issuer processor's dashboard, which sits inside Fluz's PCI environment and isn't exposed to partners. Request the transactions you need through your integration channel (shared Slack channel or [partnerships@fluz.app](mailto:partnerships@fluz.app)) and we'll run them against your card, usually the same business day. Everything else on this page — issuing the card, reading the result — is fully self-serve.
</Warning>

## Before you request a simulation

An authorization runs through the full control stack, so a card that isn't set up correctly will decline for reasons that have nothing to do with your test.

<Steps>
  <Step title="The account has passed KYC">
    Cards can only be issued — and only authorize — on a verified account. See [Testing KYC Flows](/test-kyc-flows) for identities that return a pass.
  </Step>

  <Step title="You have an ACTIVE card">
    Issue one with `createVirtualCard` using an offer from [Test Virtual Card Offers](/test-virtual-card-offers). Hold on to the `virtual_card_id` — it's how we locate the card.
  </Step>

  <Step title="The card is funded and unlocked">
    The card draws on your Fluz balance. Confirm the spend limit covers your test amount and that the card hasn't been locked, expired, or spent down. `getVirtualCardBalance` shows you `remainingBalance` at a glance.
  </Step>
</Steps>

## What you can simulate

Ask for whichever leg of the lifecycle you need. Each maps to a distinct set of records and webhooks on your side.

<AccordionGroup>
  <Accordion title="Authorization (approval)" icon="circle-check">
    The base case: a purchase at a merchant you name, for an amount you name. The card's available balance is reduced immediately and the transaction lands in a pending state. Use this to verify that spend controls, balance decrementing, and your `TRANSACTION_CREATE` handler all behave.
  </Accordion>

  <Accordion title="Clearing (capture)" icon="receipt">
    The settlement leg that follows an authorization, sometimes days later in the real world. We can either capture in a single step alongside the authorization, or leave the authorization open so you can observe the pending state and then request the capture separately. The second option is the more faithful rehearsal of production.
  </Accordion>

  <Accordion title="Decline" icon="circle-x">
    A transaction the authorization service rejects. Tell us which decline you want to see — a control-driven decline (over the spend limit, wrong merchant on a brand-locked card, locked card) or an authentication decline (CVV mismatch). Declines surface a `declineReason` and `declineCategory`; see [Decline Codes](/features/decline-codes) for the full set.
  </Accordion>

  <Accordion title="Reversal" icon="rotate-ccw">
    An authorization released before it clears — the merchant abandoned the sale, or the terminal timed out. The held amount returns to the card. Worth testing if you reconcile on authorizations rather than clearings.
  </Accordion>

  <Accordion title="Refund" icon="arrow-left">
    Value returned to the card after a purchase has cleared, in full or in part. Appears as a `REFUND` transaction type rather than a reduction of the original purchase, so your ledger needs to handle it as a separate record.
  </Accordion>

  <Accordion title="Zero-dollar and AVS checks" icon="shield-check">
    Some merchants probe a card with a $0.00 or $0.01 authorization before charging it. These appear as their own records and are reversed shortly after. If your reconciliation sums authorizations, test this case — it's a common source of double-counting.
  </Accordion>
</AccordionGroup>

## What to send us

The more of this you provide, the fewer round trips.

| Field                | Required | Notes                                                                    |
| -------------------- | -------- | ------------------------------------------------------------------------ |
| `virtual_card_id`    | Yes      | Returned by `createVirtualCard`. Card last four also works.              |
| Amount               | Yes      | In USD.                                                                  |
| Outcome              | Yes      | Approve or decline — and if decline, which reason you want to exercise.  |
| Merchant name        | No       | Defaults to a generic test merchant. Set it if you match on descriptors. |
| MCC                  | No       | Set it if you're testing category-based logic.                           |
| Single-step clearing | No       | On to capture immediately; off to leave the authorization pending.       |

## Verifying the result

Once we confirm the simulation has run, everything is readable over the API. Nothing about reading a simulated transaction differs from reading a real one.

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

A simulated purchase should show up as a `PURCHASE` row with a matching drop in `remainingBalance`. A decline shows up under the `DECLINE` type and leaves the balance untouched — declines are also queryable in isolation through [Get Declined Transactions](/features/get-decline-transactions).

<Tip>
  Card-level queries only cover card activity. To see the same event in the account's unified ledger alongside deposits and transfers, use `getTransactions` — see [Transactions Overview](/features/transactions-details-overview).
</Tip>

### Webhooks

Simulated transactions fire the same events as real ones, which makes this the cleanest way to test your endpoint end to end:

| Event                 | Fires when                                                                 |
| --------------------- | -------------------------------------------------------------------------- |
| `TRANSACTION_CREATE`  | The authorization is approved. `status` is `PENDING`.                      |
| `TRANSACTION_UPDATE`  | The transaction clears. `status` moves to `SETTLED`.                       |
| `TRANSACTION_DECLINE` | The authorization is rejected, with `declineReason` and `declineCategory`. |

If you asked for an authorization without single-step clearing, you should see `TRANSACTION_CREATE` on its own and `TRANSACTION_UPDATE` only after the capture is run. See [Webhooks](/fluz-dashboard/webhooks) for payloads and signature verification.

## Troubleshooting

| What you see                            | Likely cause                                                                                                        |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| Declined when you expected an approval  | Spend limit below the amount, card locked, insufficient Fluz balance, or a brand-locked card at the wrong merchant. |
| Nothing appears on the card             | The simulation ran against a different card. Confirm the `virtual_card_id` you sent.                                |
| Transaction stays pending               | Expected — the authorization hasn't been captured. Request the clearing leg.                                        |
| No webhook received                     | Check the subscription and required scopes; the transaction itself is still visible over the API.                   |
| Balance doesn't move on a \$0.01 charge | Expected for an AVS probe. It reverses on its own.                                                                  |

## Next steps

<CardGroup cols={2}>
  <Card title="Your First Virtual Card Purchase" icon="credit-card" href="/quickstart/create-and-spend-with-a-virtual-card">
    The full happy path — pick a program, issue a card, reveal it, and track its spend.
  </Card>

  <Card title="Get Virtual Card Transactions" icon="list" href="/features/get-virtual-card-transactions">
    Filter card activity by type and date range, and read every field on a transaction.
  </Card>

  <Card title="Decline Codes" icon="circle-x" href="/features/decline-codes">
    Every decline reason and category, and what your app should do with each.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/fluz-dashboard/webhooks">
    Subscribe to transaction events, verify signatures, and handle retries.
  </Card>
</CardGroup>

**Want to learn more?** Contact us at [partnerships@fluz.app](mailto:partnerships@fluz.app). Speak with our experts for more info or to request a demo.
