A Beancount importer for Zenmoney CSV exports, built on beangulp.
pip install beancount-zenmoneyOr with uv:
uv add beancount-zenmoney- Python 3.10+
- Beancount 3.x
- beangulp
Create an import.py file for beangulp (see examples/import.py for a complete example):
from beancount_zenmoney import ZenMoneyImporter
account_map = {
"PKO - PLN": "Assets:Bank:PKO:PLN",
"Revolut - EUR": "Assets:Bank:Revolut:EUR",
}
category_map = {
"Salary": "Income:Salary",
"Food / Groceries": "Expenses:Food:Groceries",
}
importers = [
ZenMoneyImporter(
account_map=account_map,
category_map=category_map,
),
]Run with beangulp:
beangulp extract -e ledger.beancount import.py zenmoney_export.csvZenMoneyImporter(
# Required: Map Zenmoney account names to Beancount accounts
account_map={
"Bank - PLN": "Assets:Bank:PLN",
},
# Optional: Map Zenmoney categories to Beancount accounts
category_map={
"Food": "Expenses:Food",
},
# Optional: Base account for the importer (default: "Assets:ZenMoney")
base_account="Assets:Import:ZenMoney",
# Optional: Default expense account for unknown categories
default_expense="Expenses:Unknown",
# Optional: Default income account for unknown categories
default_income="Income:Unknown",
# Optional: Default asset account for unknown Zenmoney accounts
default_account="Assets:Unknown",
# Optional: Transaction flag - "*" for cleared (default), "!" for pending
flag="!",
)| Zenmoney Transaction | Beancount Result |
|---|---|
| Expense (outcome only) | Debit from asset, credit to expense |
| Income (income only) | Credit to asset, debit from income |
| Transfer (same currency) | Debit from source, credit to destination |
| Currency exchange | Debit in one currency, credit in another with price |
| Refund | Credit to asset, debit from expense |
Currency exchanges automatically include price annotations for proper cost tracking:
2025-12-12 * "" "FX EXCHANGE EUR/PLN 4.25"
Assets:Bank:PKO:PLN -4250.00 PLN
Assets:Bank:PKO:EUR 1000.00 EUR @ 4.25 PLN
Each transaction includes metadata from ZenMoney:
2025-12-14 * "SuperMarket" ""
zenmoney_created: "2025-12-14 10:30:00"
zenmoney_changed: "2025-12-14 11:00:00"
zenmoney_category: "Food / Groceries"
Assets:Bank:PKO:PLN -125.50 PLN
Expenses:Food:Groceries 125.50 PLN
The importer implements date() and filename() methods for beangulp archiving:
# Archive files with automatic date-based naming
beangulp archive -e ledger.beancount import.py zenmoney_export.csv
# Creates: documents/Assets/Import/ZenMoney/2025-11-29-to-2025-12-15.zenmoney.csvSkipped rows are logged as warnings for troubleshooting:
import logging
logging.basicConfig(level=logging.WARNING)- Open the Zenmoney app or web interface
- Go to Menu → Export
- Select CSV format
- Choose the date range for export
- Download the CSV file
The CSV file should have semicolon-separated columns including:
date,categoryName,payee,commentoutcomeAccountName,outcome,outcomeCurrencyShortTitleincomeAccountName,income,incomeCurrencyShortTitlecreatedDate,changedDate
Expense transaction:
2025-12-14 * "SuperMarket" ""
Assets:Bank:PKO:PLN -125.50 PLN
Expenses:Food:Groceries 125.50 PLN
Internal transfer:
2025-12-11 * "" ""
Assets:Bank:PKO:PLN -2000.00 PLN
Assets:Cash:PLN 2000.00 PLN
Income transaction:
2025-12-15 * "ACME CORP" "DECEMBER SALARY"
Assets:Bank:PKO:PLN 15000.00 PLN
Income:Salary -15000.00 PLN
git clone https://github.com/MrLokans/beancount-zenmoney.git
cd beancount-zenmoney
make installThe package is automatically published to PyPI when a version tag is pushed:
make release VERSION=0.2.0This script will:
- Run all checks (lint, format, typecheck, tests)
- Validate the version format and ensure the tag doesn't exist
- Update version in
pyproject.tomland__init__.py - Commit, tag, and push to remote
make install # Install dependencies
make test # Run tests
make lint # Run linter
make format # Format code (ruff check --fix + ruff format)
make typecheck # Run type checker
make check # Run all checks (lint, format-check, typecheck, test)
make build # Build package
make clean # Clean build artifacts
make release VERSION=X.Y.Z # Create and push a releasemake testTests use pytest with fixtures for sample CSV data. Test coverage is reported automatically.
MIT License - see LICENSE for details.