Posting Structure
Overview
A posting is a single line within a transaction that specifies a transfer of value to or from an account. Every transaction consists of two or more postings.
Syntax
posting = INDENT [flag] account [WHITESPACE amount [cost] [price]]
flag = "*" | "!"
cost = "{" cost_spec "}" | "\{\{" cost_spec "\}\}"
price = "@" amount | "@@" amountComponents
Indentation
Postings MUST be indented (at least one space or tab):
2024-01-15 * "Transaction"
Assets:Checking 100 USD ; Correct: indented
Income:Salary ; Correct: indented
2024-01-15 * "Invalid"
Assets:Checking 100 USD ; ERROR: not indentedFlag (Optional)
A posting may have its own flag independent of the transaction:
| Flag | Meaning |
|---|---|
* | Complete/verified |
! | Incomplete/needs attention |
2024-01-15 * "Mixed status"
Assets:Checking -100 USD ; Inherits transaction flag (*)
* Expenses:Food 50 USD ; Explicitly complete
! Expenses:Other 50 USD ; Explicitly incompleteAccount
The account receiving or giving value. Must be a valid account name:
2024-01-15 * "Transfer"
Assets:Checking -500 USD
Assets:Savings 500 USDAmount (Optional)
A number followed by a currency:
2024-01-15 * "Purchase"
Assets:Checking -85.50 USD
Expenses:Food 85.50 USDWhen omitted, the amount is computed to balance the transaction:
2024-01-15 * "Purchase"
Assets:Checking -85.50 USD
Expenses:Food ; Computed as 85.50 USDCost Specification (Optional)
Records the acquisition cost of commodities:
2024-01-15 * "Buy stock"
Assets:Brokerage 10 AAPL {150 USD} ; Per-unit cost
Assets:Brokerage 10 AAPL \{\{1500 USD\}\} ; Total cost
Assets:Cash -1500 USDSee costs.md for full cost specification documentation.
Price Annotation (Optional)
Records the exchange rate for currency conversion:
2024-01-15 * "Exchange"
Assets:EUR 100 EUR @ 1.10 USD ; Per-unit price
Assets:EUR 100 EUR @@ 110 USD ; Total price
Assets:USD -110 USDSee prices.md for full price annotation documentation.
Amount Elision
Rules
UNDEFINED: The exact elision rule is pending clarification. Tracked in: python-beancount.md conformance issues
Option A (One per currency): At most one posting per currency MAY omit its amount. Multiple currencies may each have one elided posting.
Option B (One total): At most one posting total MAY omit its amount. That posting expands to cover all currencies.
Regardless of which rule applies:
- The omitted amount(s) are computed to make the transaction balance
- The sum of all posting weights for each currency MUST equal zero
Examples
; Single currency - unambiguous
2024-01-15 * "Simple"
Assets:Checking 100 USD
Income:Salary ; Computed as -100 USDInvalid Examples
; ERROR: Two elided postings for same currency
2024-01-15 * "Ambiguous"
Assets:Checking 100 USD
Expenses:Food
Expenses:Coffee ; Which gets how much?
; ERROR: Cannot compute without other amounts
2024-01-15 * "Empty"
Assets:Checking
Income:Salary ; No amounts to compute fromWeight Calculation
The posting weight determines how it contributes to transaction balancing:
| Posting Type | Weight Formula |
|---|---|
| Simple amount | amount |
With cost {cost} | units × cost |
With total cost \{\{cost\}\} | cost |
With price @ price | units × price |
With total price @@ price | price |
| Cost + Price | units × cost (price is informational) |
Examples
; Simple: weight = 100 USD
Assets:Checking 100 USD
; Cost: weight = 10 × 150 = 1500 USD
Assets:Stock 10 AAPL {150 USD}
; Total cost: weight = 1500 USD
Assets:Stock 10 AAPL \{\{1500 USD\}\}
; Price: weight = 100 × 1.10 = 110 USD
Assets:EUR 100 EUR @ 1.10 USD
; Total price: weight = 110 USD
Assets:EUR 100 EUR @@ 110 USD
; Cost + Price: weight = 10 × 150 = 1500 USD (price ignored for balance)
Assets:Stock 10 AAPL {150 USD} @ 180 USDPosting Metadata
Metadata can be attached to individual postings with double indentation:
2024-01-15 * "Purchase"
transaction-meta: "value" ; Transaction metadata (single indent)
Assets:Checking -85.50 USD
bank-ref: "TXN123" ; Posting metadata (double indent)
category: "groceries"
Expenses:Food 85.50 USD
receipt: "scan.pdf"Arithmetic Expressions
Amounts support arithmetic expressions:
2024-01-15 * "Split dinner"
Assets:Checking -75.00 USD
Expenses:Food:Mine (75.00 / 3) USD
Expenses:Food:Alice (75.00 / 3) USD
Expenses:Food:Bob (75.00 / 3) USDSupported operators:
- Addition:
+ - Subtraction:
- - Multiplication:
* - Division:
/ - Parentheses:
()
Balance Verification
After parsing all postings:
- Compute weight of each posting
- Sum weights by currency
- Each currency's sum must equal zero (within tolerance)
2024-01-15 * "Balanced"
Assets:Checking -100.00 USD ; -100 USD
Expenses:Food 50.00 USD ; +50 USD
Expenses:Coffee 50.00 USD ; +50 USD
; Sum: -100 + 50 + 50 = 0 ✓Posting Order
Posting order within a transaction:
- Is preserved for display purposes
- Does NOT affect validation
- Does NOT affect booking (unless explicitly configured)
Examples
Basic Transfer
2024-01-15 * "ATM Withdrawal"
Assets:Cash 200.00 USD
Assets:Checking -200.00 USDPurchase with Elision
2024-01-15 * "Grocery shopping"
Expenses:Food 85.50 USD
Assets:Checking ; -85.50 USD computedStock Purchase with Cost
2024-01-15 * "Buy Apple stock"
Assets:Brokerage 10 AAPL {185.50 USD}
Expenses:Commission 9.99 USD
Assets:Cash ; -1864.99 USD computedCurrency Exchange with Price
2024-01-15 * "EUR to USD"
Assets:EUR -100 EUR @ 1.10 USD ; Gives 100 EUR
Assets:USD 110 USD ; Gets 110 USDComplex Transaction
2024-01-15 * "Stock sale with commission"
Assets:Brokerage -10 AAPL {150 USD} @ 185 USD
lot-id: "2023-buy"
Assets:Cash 1840.01 USD
bank-ref: "DEP123"
Expenses:Commission 9.99 USD
Income:CapitalGains ; -350 USD gain computedValidation Errors
Posting validation produces errors in these conditions:
| Condition | Error Type |
|---|---|
| Transaction does not balance | ValidationError |
| Multiple postings missing amounts for same currency | ValidationError |
| Account not opened | ValidationError |
| Account closed before posting date | ValidationError |
| Currency not allowed in account | ValidationError |