The transaction directive records a balanced movement between accounts.
See the Beancount Transactions section.
Beancount syntax
2026-01-31 * "Employer" "Salary" #paycheck ^jan-2026
order-id: "INV-42"
Assets:Bank 5000 USD
Income:Salary -5000 USDGeneral form: YYYY-MM-DD FLAG ["Payee"] "Narration" [#tag] [^link]
Elixir struct
%Beancount.Directives.Transaction{
date: ~D[2026-01-31],
flag: "*",
payee: "Employer",
narration: "Salary",
postings: [
%Beancount.Directives.Posting{
account: "Assets:Bank",
amount: Decimal.new("5000"),
currency: "USD",
cost: nil,
price: nil,
flag: nil,
metadata: %{}
},
%Beancount.Directives.Posting{
account: "Income:Salary",
amount: Decimal.new("-5000"),
currency: "USD",
cost: nil,
price: nil,
flag: nil,
metadata: %{}
}
],
tags: ["paycheck"],
links: ["jan-2026"],
metadata: %{"order-id" => "INV-42"}
}Or use Beancount.transaction/6:
Beancount.transaction(~D[2026-01-31], "*", "Employer", "Salary", [
Beancount.posting("Assets:Bank", Decimal.new("5000"), "USD"),
Beancount.posting("Income:Salary", Decimal.new("-5000"), "USD")
],
tags: ["paycheck"],
links: ["jan-2026"],
metadata: %{"order-id" => "INV-42"}
)Fields
date-Date.t()of the transaction.flag- status flag, typically"*"(complete) or"!"(needs review).payee- optional counterparty string.nilrenders narration only.narration- required description string (may be empty"").postings- list ofBeancount.Directives.Postinglegs. Must balance to zero in all currencies when validated.tags- list of tag names (without#), applied to the transaction header.links- list of link names (without^), for grouping related entries.metadata- optional map rendered on the transaction before postings.