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:
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
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
counterparty: who’s on the other side
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 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 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
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, orprogram_id. Sending more than one returns422. You can combine the scope filter with astage_timerange, exceptcontrol_account_id, which can’t be combined withstage_timefilters.GET /transactions/by-client-referencereturns every transaction carrying the exactclient_referenceyou 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. Passstageandversionto read an earlier snapshot;0(the default for both) selects the latest.GET /transactions/{transaction_id}/eventsreturns the lifecycle events applied to the transaction.GET /transactions/{transaction_id}/historyreturns the full transaction snapshot at each stage, ordered bystage.
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 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).
See Linking an Account to register, list, get, and delete a linked account, and 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).
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.