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

# Virtual card activity history

> Every event Fluz records on a virtual card — creation, settings, locks, PINs, wallet tokens, expense details, sharing, and approvals — and how each one appears in objectChangeHistory.

A virtual card's activity history shows who created the card, every change to its settings and status, who it was shared with, and which approvals authorized those changes. Read it with `objectChangeHistory` and `objectType: VIRTUAL_CARDS`.

<Info>
  **Prerequisites:** a user access token with the `VIEW_OBJECT_CHANGE_HISTORY` scope, and the `virtualCardId` of a card on the account. See [Activity history overview](/features/activity-history) for the full query, response fields, and access rules.
</Info>

```graphql theme={null}
query {
  objectChangeHistory(
    objectType: VIRTUAL_CARDS
    objectId: "07df5653-43a8-4532-9881-3ab5857bbe11"
  ) {
    changeType
    change
    createdAt
    subjectUserId
    approvalId
    actor { userId system applicationId applicationName }
  }
}
```

***

## Creation

The card records `OBJECT_CREATED` when it's issued.

| How the card was created | `actor` | `subjectUserId` | `change` |
| - | - | - | - |
| `createVirtualCard` | The calling user and the connected application | The cardholder, when you pass `authUserId` | `{}` |
| `createVirtualCardBulkOrder` or another scheduled creation | `system: "scheduled-task-handler"` | The cardholder | `{ "source": "SCHEDULE", "scheduled_task_id", "scheduled_event_id" }` |
| A CSV import | The user who ran the import | The cardholder, when it's someone else | `{ "source": "CSV_IMPORT", "import_job_id" }` |
| An approved [virtual card request](/features/request-virtual-card-approval) | The requester | The cardholder, when it's someone else | `{}`, with `approvalId` set |
| The Fluz web or mobile app | The signed-in user | The cardholder, when it's someone else | `{}` |

When a card is created through an approval, it also gets the request's `APPROVAL_REQUESTED` and `APPROVAL_APPROVED` events, dated when they happened. See [Approvals](#approvals).

New cards also record `OWNER_ASSIGNED` for their first owner, and an `ACCESS_GRANTED` event with `"reason": "owner-floor"` for the owner's `SPENDER` access. See [Ownership and access](/features/activity-history#ownership-and-access).

***

## Settings changes

A settings change records one `FIELD_CHANGED` event per field that changed, with `change: { "field", "old", "new" }`.

| `field` | `old` / `new` | Recorded when |
| - | - | - |
| `nickname` | The nickname, or `null` | `editVirtualCard` with `cardNickname`, or the Fluz app. |
| `spend_limit` | The limit in dollars as a number, for example `500`, or `null` when cleared | `editVirtualCard` with both `spendLimit` and `spendLimitDuration`, an approved [limit change](/features/request-virtual-card-limit-change), raising a lifetime limit in the Fluz app, or editing the card balance in the Fluz app. A balance edit records the card's resulting limit, which includes Fluz's buffer, not the balance you entered. |
| `spend_limit_duration` | `DAILY`, `WEEKLY`, `MONTHLY`, `ANNUAL`, `LIFETIME`, or `null` | `editVirtualCard` with both `spendLimit` and `spendLimitDuration`, an approved limit change, or the Fluz app. |
| `lock_date` | An ISO 8601 UTC timestamp, usually the end of the chosen day, for example `"2026-12-31T23:59:59.999Z"`, or `null` when cleared | `editVirtualCard` with `lockDate`, an approved lock date change, the Fluz app, or an unlock that moves or clears the lock date. |
| `lock_next_use` | `true` or `false` | `editVirtualCard` with `lockCardNextUse`, or the Fluz app. |
| `funding_source` | The `bankAccountId` funding the card, or `null` when the card isn't funded by a bank account | `editVirtualCard` with `bankAccountId` or `primaryFundingSource`, or the Fluz app. |
| `spend_account` | The `userCashBalanceId` funding the card, or `null` when the card isn't funded by a spend account | `editVirtualCard` with `userCashBalanceId`, closing the spend account that funded the card with `closeUserCashBalance`, or the Fluz app. |
| `card_type` | `SINGLE_USE` → `MULTI_USE` | A single-use card is converted to a multi-use card in the Fluz app. The conversion also records any status, lock date, or limit fields that changed with it. |

A limit change records both `spend_limit` and `spend_limit_duration` when both change, and only the one that changed otherwise.

A funding switch can record both `funding_source` and `spend_account`: one gets the new ID and the other changes to `null`. Switching to a bank card records the previous funding field changing to `null`. The bank card's own ID isn't recorded.

***

## Status changes

Locking, unlocking, and closing a card record `FIELD_CHANGED` with `field: "status"`.

| `status` value | Meaning |
| - | - |
| `UNLOCKED` | The card is open and can spend. |
| `LOCKED` | The card is open but locked. Authorizations are declined. |
| `USED` | A single-use card was spent. |
| `CANCELLED` | The card was cancelled. |
| `EXPIRED` | The card expired. |

The history records lock state as a status. `UNLOCKED` and `LOCKED` both describe an open card, which the card queries report as `status: ACTIVE` with the lock in `authorizationSetting.lockedByUser` and `lockedBySystem`. See [Card status and limits](/virtual-cards/card-status-and-limits).

| Event | `old` → `new` | `actor` | Extra keys |
| - | - | - | - |
| Locked by a user | `UNLOCKED` → `LOCKED` | The user, through `lockVirtualCard`, `closeUserCashBalance` with `lockAllVirtualCards`, or the Fluz app | — |
| Unlocked | `LOCKED` → `UNLOCKED` | The user, through `unlockVirtualCard` or the Fluz app. The requester, for an approved unlock request. | — |
| Locked by Fluz | `UNLOCKED` → `LOCKED` | See [Lock reasons](#lock-reasons) | `reason` |
| Locked by Fluz support | `UNLOCKED` → `LOCKED` | `system: "cms"` | — |
| Single-use card spent | → `USED` | `system: "virtual-card-service"` | — |
| Cancelled | → `CANCELLED` | The user whose request cancelled the card. `system: "purchase-service"` when no user is tied to the request. | `reason` |
| Expired | `UNLOCKED` or `LOCKED` → `EXPIRED` | `system: "virtual-card-expirer"` | — |

An unlock can also change the lock date, recorded as a separate `lock_date` event. Unlocking a single-use card sets a lock date one day out. Unlocking a multi-use card whose lock date has passed clears it to `null`.

A cancelled card's `reason` is one of:

| `reason` | Meaning |
| - | - |
| `USER_REQUESTED_CANCEL` | A user cancelled the card. |
| `PURCHASE_VIRTUAL_CARD_ERROR` | The purchase that created the card failed, so Fluz cancelled it. |
| `FLUZPAY_WITHDRAW_OR_USAGE` | Fluz cancelled a reserved card to release the balance it held for another purchase. |

### Lock reasons

When a card is locked without a person asking for it, the lock event carries `change.reason`:

| `reason` | Why the card was locked | `actor` |
| - | - | - |
| `LOCK_DATE_REACHED` | The card's lock date passed. | `system: "virtual-card-service"` |
| `LOCK_NEXT_USE` | The card had `lockCardNextUse` set and was used. | `system: "virtual-card-service"` |
| `SINGLE_LOAD_LIMIT` | The card reached its single-load limit. | `system: "virtual-card-service"` |
| `FRAUD_DECISION` | A fraud review decided to lock the card. | `system: "virtual-card-service"` |
| `TOKENIZATION_RISK` | Adding the card to a digital wallet failed a risk check. | `system: "virtual-card-service"` |
| `LOCKED_BY_SYSTEM` | Fluz locked the card for another reason, for example because its last digital wallet token was removed. | `system: "virtual-card-service"` |
| `PURCHASE_CLEANUP` | Fluz locked the card while cleaning up a purchase that didn't complete. | The user whose request led to the lock |
| `FUNDING_SOURCE_REMOVED` | The funding source behind the card was removed in the Fluz mobile app. | The user who removed it |

A single-load card that drops back under its limit is unlocked again, attributed to `system: "virtual-card-service"`.

***

## Security changes

Fluz records that these changes happened, and who made them, but never the sensitive value.

| `field` | `old` → `new` | Recorded when |
| - | - | - |
| `pin` | `null` → `"updated"` | A PIN is set with [`setVirtualCardPIN`](/set-virtual-card-pin), when a card is created with a PIN, or in the Fluz app. Only successful changes are recorded. |
| `wallet_token` | → `"added"` | The card is added to a digital wallet. The actor is the user. Some wallet provisioning paths record only the `"activated"` event. |
| `wallet_token` | `"added"` → `"activated"` | The card network activates the wallet token. The actor is `system: "virtual-card-service"`. |
| `wallet_token` | → `"removed"` | The wallet token is removed. The actor is `system: "virtual-card-service"`. |
| `billing_address` | `null` → `"UPDATED"`, with `"via": "BUSINESS_ADDRESS_UPDATE"` | Fluz support updates a business's address on all its cards. One event per card whose address changed. The actor is `system: "cms"`. |

***

## Expense details

Memos, receipts, and categories belong to a transaction, not to the card. When one changes, Fluz records a `FIELD_CHANGED` event on the card the transaction was made with.

| `field` | `old` / `new` | Set with |
| - | - | - |
| `memo` | `old` is `null`. `new` is `ADDED`, `CHANGED`, or `REMOVED`. The memo text is never recorded. | `memo` |
| `receipt` | `old` is `null`. `new` is `ADDED`, `CHANGED`, or `REMOVED`. The file is never recorded. | `attachmentId` |
| `expense_category` | The previous and new category names, or `null` | `transactionCategory` |
| `erp_category` | The previous and new QuickBooks category names, or `null` | `erpTransactionMetadata.categoryReferenceItemId` or `categoryName` |

Each event also identifies the transaction:

| Key | Description |
| - | - |
| `transaction_log_id` | The Fluz transaction the change belongs to. |
| `transaction_record_id` | The transaction's `recordId`, when it's known. |
| `old_id`, `new_id` | The previous and new category IDs, on category events. Omitted on the side that has no category. |

These events are recorded for:

* [`updateTransactionMetadata`](/features/add-expense-details).
* The `UPDATE_TRANSACTION_METADATA` [bulk operation](/submit-a-bulk-operation), for `memo` and `transactionCategory`.
* `bulkUpdateErpTransactionMetadata`, for `erp_category`.
* Edits in the Fluz web app. In the Fluz mobile app, receipt uploads and removals, and QuickBooks category changes.

They're attributed to the user who made the change and the connected application, if any. A category counts as changed only when its ID changes.

Not recorded:

* A memo or category set when the transaction is made.
* A card's default memo or category copied onto each new transaction.
* QuickBooks vendor, customer, class, billable, and memo fields, including memo edits in the Fluz mobile app.
* A QuickBooks category or memo that Fluz copies into the Fluz fields.

***

## Sharing

A card's ownership, access, and invite events follow the shared rules in [Ownership and access](/features/activity-history#ownership-and-access).

When a recipient claims a card that was shared with them, the card records `ACCESS_GRANTED` or `ACCESS_LEVEL_CHANGED` with `"reason": "shared-card-claim"`. The claimer is both the actor and the subject.

***

## Approvals

These requests record approval events on the card. The trail is described in [Approvals](/features/activity-history#approvals).

| Request | `approval_type` | `approval_code` | Resulting event |
| - | - | - | - |
| [Create a virtual card](/features/request-virtual-card-approval) | `VIRTUAL_CARD_CREATION` | `600003` | `OBJECT_CREATED` on the new card |
| [Change the spend limit](/features/request-virtual-card-limit-change) | `VIRTUAL_CARD` | `600002` | `spend_limit` / `spend_limit_duration` |
| Unlock the card | `VIRTUAL_CARD` | `600005` | `status` → `UNLOCKED` |
| Unlock a card declined because it was locked | `VIRTUAL_CARD` | `600102` | `status` → `UNLOCKED` |
| Raise a limit after a purchase was declined | `VIRTUAL_CARD` | `600103` | `spend_limit`, attributed to `system: "virtual-card-service"` |
| Change the lock date | `VIRTUAL_CARD` | `600006` | `lock_date` |
| Replace a card funded by a restricted bank account | `VIRTUAL_CARD_CREATION` | `600004` | Approval events, including a decline or expiry, on the original card. Once approved, the replacement card records its own `OBJECT_CREATED`, attributed to the original cardholder, and the approval trail |
| Access to the card | `ACCOUNT_ACCESS` | `100004`, `100005` | `ACCESS_GRANTED`, or `ACCESS_LEVEL_CHANGED` if the requester already had lower access |

A request about an existing card that nobody decides in time records `APPROVAL_EXPIRED` on the card. A declined or expired request to create a card (`600003`) leaves no history, because no card was created.

***

## Systems you can see

| `actor.system` | What it does |
| - | - |
| `virtual-card-service` | Locks, unlocks, and marks cards used, applies approved limit increases, and records wallet token updates from the card network. |
| `virtual-card-expirer` | Expires cards. |
| `scheduled-task-handler` | Creates scheduled cards and the cards of bulk orders. |
| `purchase-service` | Cancels a card whose purchase failed when no user is tied to the request. |
| `approvals-service` | Records expired requests and decisions made through an approval link that names no approver. |
| `erp-service` | Applies a QuickBooks category automatically. |
| `transactional-graph-service` | Records an expense details change made through the API when the caller can't be resolved to a user. |
| `cms` | Fluz support. |

***

## What isn't recorded

* Revealing card details.
* Transactions, authorizations, refunds, and spend amounts. A transaction only shows up through what it caused, such as a `USED`, `LOCK_NEXT_USE`, or `SINGLE_LOAD_LIMIT` event.
* The bank card's ID when the card switches to bank card funding. You see `funding_source` or `spend_account` change to `null` instead.
* Turning Fluz balance funding on or off.
* Card balance loads and closures at the card issuer that don't change the card's status.
* Share links. Generating, claiming, or deactivating a share link isn't part of the card's history. The claim's access grant is.

## Next steps

<CardGroup cols={2}>
  <Card title="Activity history overview" icon="history" href="/features/activity-history">
    The query, response fields, actors, approvals, and access levels.
  </Card>

  <Card title="Edit a virtual card" icon="pen" href="/features/edit-virtual-card">
    Change the settings that appear in the card's history.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.