# Getting started with beancount_ex
```elixir
Mix.install([
{:beancount_ex, "~> 0.6"},
{:kino, "~> 0.13"}
])
```
## Build a ledger
Constructors live on `Beancount`. You build a list of typed directive structs.
```elixir
ledger = [
Beancount.open(~D[2026-01-01], "Assets:Bank", ["USD"]),
Beancount.open(~D[2026-01-01], "Income:Salary", ["USD"]),
Beancount.open(~D[2026-01-01], "Equity:Opening", ["USD"]),
Beancount.transaction(~D[2026-01-31], "*", "Employer", "Salary", [
Beancount.posting("Assets:Bank", Decimal.new("5000"), "USD"),
Beancount.posting("Income:Salary", Decimal.new("-5000"), "USD")
])
]
```
## Render to Beancount text
```elixir
IO.puts(Beancount.render(ledger))
```
## Check the ledger
With the default CLI engine you need `pip install beancount beanquery` (the
latter provides `bean-query` for reports). The native engine works without
Python tooling:
```elixir
# Optional: use native validation (booking, balance assertions, pad)
Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
case Beancount.check(ledger) do
{:ok, result} -> result.status
{:error, result} -> result.normalized.errors
end
```
## Parse existing text
```elixir
bean = Beancount.render(ledger)
{:ok, parsed} = Beancount.parse_text(bean)
Beancount.render(parsed) == bean
```
## Reports preview
```elixir
Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
{:ok, result} = Beancount.balances(ledger)
Beancount.Query.Result.to_maps(result)
```
## Next notebooks
- [Accounting cookbook](accounting.livemd) - cash, salary, trading patterns
- [Parsing and validation](parsing.livemd) - import, round-trip, errors
- [Reporting with Explorer](reporting.livemd) - DataFrames and dashboards