The Formance Ledger represents financial activity using two primitives: postings and transactions. Postings are the basic unit of movement; transactions are timestamped containers that group one or more postings together.
Postings#
A posting records the movement of an amount of an asset from a source account to a destination account.
{
"source": "alice",
"destination": "bob",
"asset": "COIN",
"amount": 100
}Each posting has exactly one source and one destination. The Formance Ledger records the full history of postings; account balances are derived from that history rather than stored directly.
The asset field is an unconstrained string. By convention it follows the ISO 4217 three-letter currency code (e.g. USD, EUR, GBP), optionally suffixed with a precision indicator (USD/2 means amounts are expressed in cents). Custom asset names like COIN or REWARD_POINT are equally valid.
Transactions#
A transaction is a timestamped, permanently recorded grouping of one or more postings. For example, Alice trading coins for gems at a teller involves two postings in one transaction:
{
"postings": [
{
"source": "alice",
"destination": "teller",
"amount": 100,
"asset": "COIN"
},
{
"source": "teller",
"destination": "alice",
"amount": 5,
"asset": "GEM"
}
]
}Atomicity#
Transactions are atomic: all of their postings are applied together, or none are. There is no intermediate state in which some postings have been committed and others have not.
In the example above, the posting to platform:fees fails. Even though the posting to merchant:account succeeded in isolation, atomicity means neither posting is applied; the customer is not charged and the merchant receives nothing. There is no intermediate state where the merchant was paid but the platform was not.
Single source and destination postings#
Every posting in the Formance Ledger has exactly one source and one destination. When a split or fan-out is needed, use a transient intermediary account: funds move into it in one posting and out to each destination in separate postings, all within the same atomic transaction:
{
"postings": [
{
"source": "customer:wallet",
"destination": "order:hold",
"asset": "USD/2",
"amount": 2000
},
{
"source": "order:hold",
"destination": "merchant:account",
"asset": "USD/2",
"amount": 1800
},
{
"source": "order:hold",
"destination": "rider:earnings",
"asset": "USD/2",
"amount": 100
},
{
"source": "order:hold",
"destination": "platform:fees",
"asset": "USD/2",
"amount": 100
}
]
}order:hold is the transient intermediary. It receives the full amount in the first posting and distributes it in the three that follow. All four postings commit atomically: either the full split happens, or nothing does.
The split logic ("10% to fees, the rest to the merchant") belongs in Numscript, which compiles your intent into unambiguous single-destination postings automatically.
Each posting has one source, one destination, and one unambiguous amount. Every balance question resolves to a single number: alice moved exactly 2000 USD/2 to order:hold, and platform:fees received exactly 100 USD/2.