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

# Transactions Overview

> One ledger for every money movement on the account — which query to reach for, what a transaction record contains, and how to reconcile against your own system.

Every movement of money on a Fluz account produces a transaction record: gift card purchases, virtual card authorizations, deposits, withdrawals, internal transfers, wallet-to-wallet sends, bill payments, and cashback. One feed, one shape, one query.

Records are **account-level**. There is no user-level filtering — a query returns everything on the account your token is scoped to.

***

## Which query do I want?

| You want                                   | Use                          | Page                                                                     |
| :----------------------------------------- | :--------------------------- | :----------------------------------------------------------------------- |
| Everything, filtered any way               | `getTransactions`            | [Get All Transactions](/features/get-all-transactions)                   |
| Only authorizations that were declined     | `getDeclinedTransactions`    | [Get Declined Transactions](/features/get-declined-transactions)         |
| Activity on specific virtual cards         | `getVirtualCardTransactions` | [Get Virtual Card Transactions](/features/get-virtual-card-transactions) |
| Gift card orders as purchases              | `getUserPurchases`           | [Get Gift Card Purchases](/features/get-gift-card-purchases)             |
| Gift cards as assets, with remaining value | `getGiftCards`               | [View Gift Cards](/view-gift-card)                                       |

<Note>
  **Declines are not a transaction status.** `status` is only ever `PENDING` or `SETTLED` — a declined authorization never becomes a settled transaction, so it won't appear in `getTransactions` at all. If you're debugging "the charge didn't go through," that's `getDeclinedTransactions` and [Decline Codes](/features/decline-codes), not this feed.
</Note>

***

<Warning>
  **Field naming is mixed, and you have to match it exactly.**

  Most fields on the `Transaction` type are snake\_case — `record_id`, `transaction_type`, `created_at`, `cash_balance_available_balance`. But newer additions are camelCase — `memo`, `transactionCategory`, `attachmentUrl`, `connectedAppId`, `connectedAppName`, `expectedClearedDate`.

  Everything *around* the record is camelCase: the filter input (`createdGte`, `amountGte`, `virtualCardProgram`) and the connection fields (`totalCount`, `hasNextPage`).

  Introspect the schema before writing queries rather than assuming a convention. → [How the GraphQL API works](/concepts/graphql)
</Warning>

***

## What's in a record

Around fifty fields, in six groups. Request only what you need — the response is large if you ask for everything.

<AccordionGroup>
  <Accordion title="Identity and routing">
    `record_id`, `account_id`, `user_id`, `user`, `transaction_type`, `channel` (`WEB`, `MOBILE`, `API`), `connectedAppId` and `connectedAppName` — which of your applications initiated it.
  </Accordion>

  <Accordion title="The money">
    `amount`, `fee`, `cashback`, `cashback_rate`, `bonus_cashback_rate`, plus two directional fields worth understanding:

    * `external_funding_source_activity` — the change to external funding sources (bank cards and accounts)
    * `fluz_balance_activity` — the change to internal Fluz balances

    Together these tell you whether money entered Fluz, left Fluz, or just moved around inside it.
  </Accordion>

  <Accordion title="Balance snapshots">
    See [below](#balance-snapshots) — every record carries the after-state of every balance.
  </Accordion>

  <Accordion title="Context">
    `source` and `destination` as display strings ("Visa \*\*\*\*1234", "Amazon"), `description`, `merchant_id`, `logo_url`, `card_last_four`, `card_display_name`, `virtual_card_program`, `source_type`.

    Foreign transactions add `original_currency_amount`, `original_currency_code`, and `conversion_rate`.
  </Accordion>

  <Accordion title="Your annotations">
    `memo`, `transactionCategory`, `attachmentUrl` — see [Annotating](#annotating-transactions).
  </Accordion>

  <Accordion title="Linkage">
    `reference_id`, `transfer_id`, `liability_id`, `used_user_cash_balance_id`, `descriptor_id` — the fields you reconcile against. See [Reconciliation](#reconciling-against-your-own-system).
  </Accordion>
</AccordionGroup>

### Balance snapshots

Every transaction carries the balance of **every** balance type as it stood *after* that transaction was applied. That makes the feed a replayable ledger — you can reconstruct the state of the account at any point in its history without a separate balance-history API.

| Field prefix                     | Balance    | Product name       |
| :------------------------------- | :--------- | :----------------- |
| `cash_balance_*`                 | Cash       | Cash balance       |
| `seat_balance_*`                 | Rewards    | Rewards balance    |
| `gift_card_prepayment_balance_*` | Prepayment | Prepayment balance |
| `reserve_balance_*`              | Reserve    | Reserve balance    |
| `other_cash_balance_*`           | Other cash | —                  |

<Note>
  `seat_balance_*` is the **rewards** balance. The naming is historical — don't go looking for a separate seat concept.
</Note>

Each comes in `_available_balance` and `_total_balance`. Paired `is_*_affected` booleans (`is_cash_balance_affected`, `is_seat_balance_affected`, `is_gift_card_balance_affected`, `is_reserve_balance_affected`) tell you which balances this transaction actually touched — cheaper to branch on than diffing snapshots.

→ [Wallet Overview](/features/move-funds-with-external-accounts) for what each balance is.

***

## Filtering

`getTransactions` takes a rich `TransactionFilterInput`. The families:

| Family              | Fields                                                                   |
| :------------------ | :----------------------------------------------------------------------- |
| **Record & status** | `recordId`, `status`                                                     |
| **Amount**          | `amount`, `amountGte`, `amountLte`, and the same three for `finalAmount` |
| **Cashback**        | `cashbackAmount`, `cashbackPercentage`, each with `Gte`/`Lte`            |
| **Fees**            | `feeAmount`, `feeAmountGte`, `feeAmountLte`                              |
| **Dates**           | `createdGte`, `createdLte`, `updatedGte`, `updatedLte` — ISO 8601, UTC   |
| **Merchant**        | `merchantId`, `merchant`                                                 |
| **Properties**      | `transactionType`, `channel`, `category`                                 |
| **Virtual cards**   | `virtualCard`, `virtualCardProgram`                                      |
| **Other**           | `fundingSource`, `userCashBalanceId`, `referenceId`, `liabilityId`       |

`amount` is the base amount; `finalAmount` is amount plus fees — the total actually charged. Filter on `finalAmount` when reconciling against what a funding source was debited.

<Warning>
  **Confirm the accepted values for `transactionType` before relying on it.** The reference page lists human-readable strings (`Add Money`, `Gift Card Purchase`, `Transfer - Out`) in one place and enum-style constants (`GIFT_CARD_PURCHASE`, `DEPOSIT`) in its examples and sample responses. These are not interchangeable. Query a small unfiltered page first and read the actual `transaction_type` values your account returns.
</Warning>

### Pagination and throughput

`limit` **maxes out at 20**, and `offset` walks forward. Check `hasNextPage` rather than inferring from a short page; `totalCount` gives the full size of the filtered set.

Rate limits are 100 queries per minute per user and 300 per minute per IP, with `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers on responses.

<Note>
  **Do the arithmetic before building a sync job.** 20 records per query × 100 queries per minute is a ceiling of roughly **2,000 transactions per minute**. An account with 500,000 lifetime transactions takes over four hours to walk end to end.

  Design for incremental sync: bound every job with `createdGte`/`updatedGte` against your last successful watermark, and never re-walk history you already hold.
</Note>

***

## Annotating transactions

Attach a free-text `memo` (max 255 characters), a `transactionCategory`, and a file to any transaction — either at transaction time on deposits, purchases, and transfers, or afterwards with `updateTransactionMetadata`. Categories are created on first use and reused when the same name comes back.

<Warning>
  **`attachmentUrl` is a signed URL that expires. Never store it.** Re-fetch the transaction when you need the file.

  This also breaks naive caching. Settled transactions look immutable, but `memo`, `transactionCategory`, and `attachmentUrl` are all mutable after settlement — so a cached `SETTLED` record will serve stale annotations and a dead attachment link. Cache the financial fields if you like; re-fetch the annotations.
</Warning>

→ [Add Expense Details](/features/add-expense-details)

***

## Reconciling against your own system

Five fields do the joining:

| Field                       | Joins to                                                                                                                                                                        |
| :-------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `reference_id`              | The purchase display ID — the short human-readable Fluz transaction ID (e.g. `1047283`) that also appears on gift card records and in exports, and that Fluz support references |
| `transfer_id`               | The transfer that produced this record, for wallet-to-wallet movements                                                                                                          |
| `used_user_cash_balance_id` | Which spend account the money came from — essential for per-budget reporting                                                                                                    |
| `liability_id`              | The bill payment this settles                                                                                                                                                   |
| `connectedAppId`            | Which of your applications initiated it, when several share an account                                                                                                          |

A workable pattern:

1. **Store `record_id` and `reference_id`** against your own order at the time you create it. Don't try to match on amount and timestamp later.
2. **Sync incrementally on `updatedGte`,** not `createdGte` — a `PENDING` transaction that later settles changes `updated_at`, and a created-date sync will miss the transition.
3. **Expect settlement lag.** ACH withdrawals sit `PENDING` for 1–3 business days; card authorizations settle on their own timeline. `expectedClearedDate` tells you when to look again.
4. **Reconcile balances against snapshots,** not by summing amounts. The `*_available_balance` fields are authoritative and already account for fees, cashback, and pending holds.

<Note>
  `externalReferenceId` does **not** appear on transaction records. If you need your own user ID on a movement, join through the account or carry it in `memo` at transaction time. → [Managing External Reference IDs](/managing-external-reference-ids)
</Note>

***

## Scopes

`getTransactions` requires **both** `LIST_PAYMENT` **and** `LIST_PURCHASES`. Missing either returns a `FORBIDDEN` error naming the required scopes.

Enable both on your app's Permissions tab before you build — a requested scope that isn't enabled is silently dropped rather than rejected. → [Configure OAuth App](/configure-o-auth-app)

***

## Next steps

<CardGroup cols={2}>
  <Card title="Get all transactions" icon="list" href="/features/get-all-transactions">
    Full filter, field, and pagination reference.
  </Card>

  <Card title="Declined transactions" icon="circle-x" href="/features/get-declined-transactions">
    Authorizations that never became transactions.
  </Card>

  <Card title="Decline codes" icon="triangle-alert" href="/features/decline-codes">
    What each decline reason means.
  </Card>

  <Card title="Virtual card transactions" icon="credit-card" href="/features/get-virtual-card-transactions">
    Scoped to one or more cards.
  </Card>

  <Card title="Gift card purchases" icon="gift" href="/features/get-gift-card-purchases">
    Orders rather than ledger entries.
  </Card>

  <Card title="Add expense details" icon="paperclip" href="/features/add-expense-details">
    Memos, categories, and attachments.
  </Card>
</CardGroup>
