> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.thepennyinc.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.thepennyinc.com/_mcp/server.

# Transactions

Every movement of money is a **Transaction**: a card purchase, a transfer between your own accounts, or funds arriving from a linked bank account. There's no separate object for "funding" or "transfer": each one is a transaction, distinguished by `type`, `channel`, and `counterparty`.

## Shape of a transaction

A settled card purchase:

```json
{
  "transaction_id": "transaction_01937a7d-ad6b-77ca-8046-ad6b7ca046ce",
  "account_id": "account_019372e3-b8dc-7de2-80b6-b8dcde20b6c9",
  "business_id": "business_01937b95-484e-75af-8c68-484e5afc68d3",
  "business_entity_id": "business_entity_01937c9d-3a1e-72b0-8881-3a1e2b088159",
  "program_id": "program_019377de-7f88-7f02-894f-7f88f0294fcb",
  "version": 1,
  "version_time": "2026-08-21T19:42:10Z",
  "stage": 2,
  "stage_time": "2026-08-21T19:42:10Z",
  "status": "settled",
  "type": "payment",
  "direction": "outbound",
  "base_amount": "108.50",
  "base_amount_currency": "USD",
  "channel": {
    "type": "card",
    "card_id": "card_019375de-a2a0-7f31-884a-a2a0f3184abd",
    "cardholder_id": "cardholder_01937e19-4ebb-75bd-8250-4ebb5bd25085",
    "processing_details": {
      "pan_entry_mode": "contactless",
      "type": "point_of_service",
      "card_product_id": "card_product_01937f5d-a015-7a55-818b-a015a5518b97",
      "card_class": "consumer"
    },
    "scheme_details": {
      "network": "visa",
      "funding_type": "prepaid",
      "product_type": "consumer"
    }
  },
  "counterparty": {
    "type": "card",
    "merchant": {
      "merchant_id": "WFM-0481726",
      "code": "5411",
      "category": "Grocery Stores, Supermarkets",
      "name": "Whole Foods Market",
      "city": "San Francisco",
      "country": "US",
      "subdivision": "US-CA",
      "zip_code": "94105"
    },
    "acquirer": {
      "id": "FNMS-4021958",
      "name": "First National Merchant Services"
    }
  }
}
```

Keys whose value is `null` are omitted. This transaction has no `message`, `client_reference`, or `original_amount`, so those keys are absent.

### `type`: what kind of movement

| Type       | Meaning                                                        |
| ---------- | -------------------------------------------------------------- |
| `payment`  | A card purchase, or funds received from a linked bank account. |
| `transfer` | A movement of funds between two of your Capital Accounts.      |

### `direction`: which way it moved

`inbound` (money arriving) or `outbound` (money leaving) the account named in `account_id`. A transfer between two of your own accounts produces one transaction on each side: `outbound` on the source, `inbound` on the destination.

### `channel`: how it happened

| `channel.type` | Meaning                                                                         | Extra fields                                                       |
| -------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `card`         | A transaction made with a Penny-issued card.                                    | `card_id`, `cardholder_id`, `processing_details`, `scheme_details` |
| `internal`     | A transfer between two of your Capital Accounts.                                | None                                                               |
| `bank`         | Funds received from one of your [linked accounts](/banking/linking-an-account). | `linked_account_id`                                                |

### `counterparty`: who's on the other side

| `counterparty.type` | Meaning                                                            | Fields                                               |
| ------------------- | ------------------------------------------------------------------ | ---------------------------------------------------- |
| `card`              | The merchant and acquirer, for card transactions.                  | `merchant`, `acquirer`                               |
| `transfer`          | The account on the other side of the movement.                     | `account_id`                                         |
| `business`          | Another business, for transactions that cross business boundaries. | `business_id`, `business_entity_id`, `business_name` |

The merchant's category is two flat fields on the merchant object: `code` (the 4-digit MCC, e.g. `"5411"`) and `category` (its label, e.g. `"Grocery Stores, Supermarkets"`). The acquirer is an external processor identifier (`id`, `name`) and doesn't follow Penny's ID format.

### `status`: where it is in its lifecycle

| Status              | Meaning                                                                                                               |
| ------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `created`           | The transaction exists but hasn't been approved, declined, or settled.                                                |
| `approved`          | The transaction is approved and its amount is pending.                                                                |
| `declined`          | The transaction was declined.                                                                                         |
| `cancelled`         | An approved transaction's pending amount was released before it settled.                                              |
| `expired`           | An approved transaction's pending amount timed out before it settled.                                                 |
| `partially_settled` | Part of the pending amount has settled.                                                                               |
| `settled`           | The full amount has settled.                                                                                          |
| `reversed`          | The transaction settled, and a later matching movement in the opposite direction brought its net effect back to zero. |
| `deprecated`        | The transaction was superseded and no longer counts; all its amounts are zero.                                        |

`status` is derived from the transaction's applied events, checked in priority order. Each check falls through to the next when it doesn't apply:

`cancelled` and `expired` both require the transaction to be approved first: they mark the pending amount being released without settling, and differ only in whether it timed out (`expired`) or was released another way (`cancelled`). See [Transaction Events](/get-started/platform-concepts/transactions-ledger#transaction-events) for the event identifiers (`transaction.created`, `transaction.approved`, `transaction.settled`, …) that drive these transitions.

`stage` increases by one each time an event advances the transaction through its lifecycle. Use it to detect out-of-order webhook delivery: a lower `stage` arriving after a higher one has already been processed can be ignored.

## Reading transactions

```http
GET /transactions/
GET /transactions/by-client-reference?client_reference={client_reference}
GET /transactions/{transaction_id}
GET /transactions/{transaction_id}/events
GET /transactions/{transaction_id}/history
```

* `GET /transactions/` lists your business's latest transactions. It accepts **at most one** scope filter per request: `account_id`, `card_id`, `cardholder_id`, `control_account_id`, or `program_id`. Sending more than one returns `422`. You can combine the scope filter with a `stage_time` range, except `control_account_id`, which can't be combined with `stage_time` filters.
* `GET /transactions/by-client-reference` returns every transaction carrying the exact `client_reference` you supplied when you started the movement. References don't need to be unique, so this is a paginated list.
* `GET /transactions/{transaction_id}` returns the latest state. Pass `stage` and `version` to read an earlier snapshot; `0` (the default for both) selects the latest.
* `GET /transactions/{transaction_id}/events` returns the lifecycle events applied to the transaction.
* `GET /transactions/{transaction_id}/history` returns the full transaction snapshot at each stage, ordered by `stage`.

Transactions are also available under the account, card, or cardholder they belong to: `GET /accounts/capital/{account_id}/transactions`, `GET /accounts/control/{account_id}/transactions`, `GET /cards/{card_id}/transactions`, and `GET /cardholders/{cardholder_id}/transactions`. See [Reading Transactions & Ledger Entries](/banking/reading-transactions) for filtering examples.

## Linked accounts and funding Capital Accounts

A **linked account** is an external bank account you register with Penny as a source of incoming funds. When Penny receives funds from a registered linked account, it routes them to your Capital Account, where they appear as an `inbound` transaction with `type: "payment"` and a `bank` channel whose `linked_account_id` names the linked account. Details of where to send funds are coming soon.

Subscribe to `linked_account.created` and `linked_account.updated` to follow a linked account's status (see the [Event Catalog](/platform/webhooks-event-catalog)).

See [Linking an Account](/banking/linking-an-account) to register, list, get, and delete a linked account, and [Accounts](/banking/accounts) for how Capital Accounts hold balances and how money moves between them.

## Received payment details

Funds received from a linked account show up as an ordinary `inbound` transaction on the Capital Account; there's no separate payment object to reconcile against. The transaction doesn't repeat the sender's routing or account number. Instead, read `channel.linked_account_id` and fetch that linked account (with `?reveal_sensitive=true` if you need the unmasked account number or IBAN; see [Linking an Account](/banking/linking-an-account)).

## Ledger entries

Where a transaction is the record of an activity, a **ledger entry** (`GET /ledger/`) is the resulting posting against an account's balance. Most of the time you'll work with transactions; use the ledger when you need the append-only record of exactly what moved and when.