Skip to content

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 | "@@" amount

Components

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 indented

Flag (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 incomplete

Account

The account receiving or giving value. Must be a valid account name:

2024-01-15 * "Transfer"
  Assets:Checking        -500 USD
  Assets:Savings          500 USD

Amount (Optional)

A number followed by a currency:

2024-01-15 * "Purchase"
  Assets:Checking   -85.50 USD
  Expenses:Food      85.50 USD

When omitted, the amount is computed to balance the transaction:

2024-01-15 * "Purchase"
  Assets:Checking   -85.50 USD
  Expenses:Food                   ; Computed as 85.50 USD

Cost 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 USD

See 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 USD

See prices.md for full price annotation documentation.

Amount Elision

Rules

UNDEFINED: The exact elision rule is pending clarification. See: Pending Issue - Amount Elision Rule

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 USD

Invalid 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 from

Weight 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 USD

Posting 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) USD

Supported operators: - Addition: + - Subtraction: - - Multiplication: * - Division: / - Parentheses: ( )

Balance Verification

After parsing all postings:

  1. Compute weight of each posting
  2. Sum weights by currency
  3. 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 USD

Purchase with Elision

2024-01-15 * "Grocery shopping"
  Expenses:Food        85.50 USD
  Assets:Checking                    ; -85.50 USD computed

Stock 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 computed

Currency 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 USD

Complex 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 computed

Validation 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