Improves the Beancount import process to send SATS amounts with fiat metadata to the API, enabling automatic conversion to EUR-based postings. Updates the API to store entries in Fava instead of the Castle DB, simplifying the JournalEntry creation process. Adds error handling to the upload entry function. Includes a note about imported transactions being stored in EUR with SATS in metadata. |
||
|---|---|---|
| .. | ||
| btc_eur_rates.csv | ||
| import_beancount.py | ||
| README.md | ||
Castle Beancount Import Helper
Import Beancount ledger transactions into Castle accounting extension.
📁 Files
import_beancount.py- Main import scriptbtc_eur_rates.csv- Daily BTC/EUR rates (create your own)README.md- This file
🚀 Setup
1. Create BTC/EUR Rates CSV
Create btc_eur_rates.csv in this directory with your actual rates:
date,btc_eur_rate
2025-07-01,86500
2025-07-02,87200
2025-07-03,87450
2. Update User Mappings
Edit import_beancount.py and update the USER_MAPPINGS dictionary:
USER_MAPPINGS = {
"Pat": "actual_wallet_id_for_pat",
"Alice": "actual_wallet_id_for_alice",
"Bob": "actual_wallet_id_for_bob",
}
How to get wallet IDs:
- Check your LNbits admin panel
- Or query:
curl -X GET http://localhost:5000/api/v1/wallet -H "X-Api-Key: user_invoice_key"
3. Set API Key
export CASTLE_ADMIN_KEY="your_lnbits_admin_invoice_key"
export LNBITS_URL="http://localhost:5000" # Optional
📖 Usage
cd /path/to/castle/helper
# Test with dry run
python import_beancount.py ledger.beancount --dry-run
# Actually import
python import_beancount.py ledger.beancount
📄 Beancount File Format
Your Beancount transactions must have an Equity:<name> account:
2025-07-06 * "Foix market"
Expenses:Groceries 69.40 EUR
Equity:Pat
2025-07-07 * "Gas station"
Expenses:Transport 45.00 EUR
Equity:Alice
Requirements:
- Every transaction must have an
Equity:<name>account - Account names must match exactly what's in Castle
- The name after
Equity:must be inUSER_MAPPINGS
🔄 How It Works
- Loads rates from
btc_eur_rates.csv - Loads accounts from Castle API automatically
- Maps users - Extracts user name from
Equity:Nameaccounts - Parses Beancount transactions
- Converts EUR → sats using daily rate
- Uploads to Castle with metadata
📊 Example Output
$ python import_beancount.py ledger.beancount
======================================================================
🏰 Beancount to Castle Import Script
======================================================================
📊 Loaded 15 daily rates from btc_eur_rates.csv
Date range: 2025-07-01 to 2025-07-15
🏦 Loaded 28 accounts from Castle
👥 User ID mappings:
- Pat → wallet_abc123
- Alice → wallet_def456
- Bob → wallet_ghi789
📄 Found 25 potential transactions in ledger.beancount
✅ Transaction 1: 2025-07-06 - Foix market (User: Pat) (Rate: 87,891 EUR/BTC)
✅ Transaction 2: 2025-07-07 - Gas station (User: Alice) (Rate: 88,100 EUR/BTC)
✅ Transaction 3: 2025-07-08 - Restaurant (User: Bob) (Rate: 88,350 EUR/BTC)
======================================================================
📊 Summary: 25 succeeded, 0 failed, 0 skipped
======================================================================
✅ Successfully imported 25 transactions to Castle!
❓ Troubleshooting
"No account found in Castle"
Error: No account found in Castle with name 'Expenses:XYZ'
Solution: Create the account in Castle first with that exact name.
"No user ID mapping found"
Error: No user ID mapping found for 'Pat'
Solution: Add Pat to the USER_MAPPINGS dictionary in the script.
"No BTC/EUR rate found"
Error: No BTC/EUR rate found for 2025-07-15
Solution: Add that date to btc_eur_rates.csv.
"Could not determine user ID"
Error: Could not determine user ID for transaction
Solution: Every transaction needs an Equity:<name> account (e.g., Equity:Pat).
📝 Transaction Metadata
Each imported transaction includes:
{
"meta": {
"source": "beancount_import",
"imported_at": "2025-11-08T12:00:00",
"btc_eur_rate": 87891.0,
"user_id": "wallet_abc123"
}
}
And each line includes:
{
"metadata": {
"fiat_currency": "EUR",
"fiat_amount": "69.400",
"fiat_rate": 1137.88,
"btc_rate": 87891.0
}
}
This preserves the original EUR amount and exchange rate for auditing.