← Back to self-hosters
Beancount how-to

Sync your bank into Beancount.

A step-by-step guide for plaintext accounting: pull your EU & UK bank transactions straight into your Beancount ledger. €3/month, no eIDAS certificate, no rate-limit wall, and encrypted so only you can read it.

€3/month — 1 account included · No credit card required

The 5-minute setup

From bank to ledger in five steps.

  1. Install the importer

    Grab the beangulp importer from PyPI. It ships the client SDK it needs, so this is the only dependency to add.

    bash

    pip install beancount-openbanking-io
  2. Export your credentials

    From the open-banking.io dashboard, export credentials.json — it pairs an API key with the decryption key that only you hold, so the importer can read your data locally.

    bash

    # Dashboard → Settings → API keys → "Export credentials"
    # downloads credentials.json. Keep it next to your ledger.
    mv ~/Downloads/credentials.json ./credentials.json

    list_accounts.py

    from beancount_openbanking_io import Client
    
    client = Client("credentials.json")
    for account in client.accounts():
        print(account.id, account.currency, account.name)

    The second snippet prints every account id you can map. Copy the ids you want to sync — you'll paste them into the config in the next step.

  3. Map accounts in a config file

    Create a *openbanking.yaml file next to your ledger. Point it at your credentials and map each bank account id to a Beancount account. currency, counterpart and assert_balance are optional per account.

    myfinances.openbanking.yaml

    # Any file ending in *openbanking.yaml is picked up by the importer.
    credentials: credentials.json
    
    accounts:
      - id: "a1b2c3d4-0000-1111-2222-333344445555"
        account: Assets:Bank:Checking
        currency: EUR                       # optional — inferred from the bank if omitted
        counterpart: Expenses:Uncategorized # optional — default second posting
        assert_balance: true                # optional — append a balance assertion
    
      - id: "f6e5d4c3-9999-8888-7777-666655554444"
        account: Assets:Bank:Savings

    Any filename ending in openbanking.yaml is auto-detected by the importer's identify() step — keep one file per ledger, or several if you split books.

  4. Run the import

    Wire the importer into a one-file beangulp script, then extract transactions and append them to your ledger. Run it by hand, from a Makefile, or on a cron schedule.

    import.py

    #!/usr/bin/env python3
    import beangulp
    from beancount_openbanking_io import OpenBankingImporter
    
    importers = [
        OpenBankingImporter(),
    ]
    
    if __name__ == "__main__":
        beangulp.Ingest(importers).main()

    bash

    python import.py extract myfinances.openbanking.yaml >> ledger.beancount

    beangulp's extract prints Beancount entries to stdout — redirect them into your ledger, or into a staging file you review before merging.

  5. Read the result

    You get real Beancount transactions with signed amounts, an obio-id on every posting for de-duplication, and an optional balance assertion at the end of each run.

    ledger.beancount

    2026-06-28 * "Netto" "Card purchase"
      obio-id: "txn_9f2c7a1e5b"
      Assets:Bank:Checking  -42.18 EUR
    
    2026-06-29 * "ACME A/S" "Salary June"
      obio-id: "txn_1b8e4d9077"
      Assets:Bank:Checking  +2450.00 EUR
    
    2026-06-30 balance Assets:Bank:Checking  8137.55 EUR

    Re-running is safe: beangulp de-duplicates on the obio-id metadata, so importing the same window twice never doubles your postings. Pipe the output through smart_importer to auto-categorise the second leg.

Why it fits plaintext accounting

Built the way your ledger already works.

Encrypted — we can't read it

Transactions are encrypted on your device with a key only you hold. We store ciphertext, so your statement never sits in readable form on our servers.

No eIDAS certificate

No PSD2 (eIDAS) certificate to buy or register, and no bank application to file first. Connect your bank and start importing.

No 4-requests-a-day wall

No four-requests-per-account-per-day cap to schedule around. Extract as often as your books actually need.

Plays well with your tooling

Plain beangulp output — pipe it through smart_importer for auto-categorisation, or fava, bean-check and your own scripts. No lock-in.

Replacing GoCardless or Nordigen?

Their free personal tier stopped onboarding new self-hosters, and the four-requests-per-account-per-day limit breaks routine Beancount imports. open-banking.io is the €3/month replacement — no certificate, no daily wall, and encrypted so only you can read it. (Bank connectivity is powered by our licensed supplier, Enable Banking.)

Get your bank into Beancount.

Connect an EU or UK bank in minutes and keep your ledger in sync — for €3 a month.

Get early access

No credit card required