Getting started
Install Python 3.12 or newer and the package:
pip install ff-iii-luciferin
Create a personal access token in Firefly III. Pass the instance root as
FIREFLY_URL, without /api/v1, and the token as FIREFLY_TOKEN. The library
does not load these environment variables automatically.
import asyncio
import os
from ff_iii_luciferin.api import FireflyClient
async def main() -> None:
client = FireflyClient(os.environ["FIREFLY_URL"], os.environ["FIREFLY_TOKEN"])
try:
about = await client.get_about()
print("Firefly III version:", about.version)
transactions = await client.fetch_transactions(max_pages=1)
for tx in transactions:
print(tx.id, tx.date, tx.amount, tx.description, tx.external_id)
categories = await client.fetch_categories()
print("Categories:", len(categories))
finally:
await client.close()
asyncio.run(main())
fetch_transactions() defaults to withdrawals. Supply tx_type="transfer"
or tx_type="deposit" when those are needed. max_pages=1 limits the example
to one API page; omit it to follow pagination until the last page. You can also
pass start_date and end_date as Python date values.
Update an existing transaction
The following code changes the transaction with ID 123 in Firefly III:
from ff_iii_luciferin.api import TransactionUpdate
updated = await client.update_transaction(
123,
TransactionUpdate(
description="Corrected description",
notes="Checked against the receipt",
tags=["reviewed", "receipt"],
category_id=7,
),
)
TransactionUpdate accepts any non-empty combination of those four fields.
Passing tags replaces the transaction's tag list; it does not append one tag.
To preserve existing tags, read the transaction and build the new list first:
from ff_iii_luciferin.services.transactions import build_add_tag_payload
current = await client.get_transaction(123)
updated = await client.update_transaction(
current.id,
TransactionUpdate(tags=build_add_tag_payload(current, "reviewed")),
)
The update examples assume client was created and will be closed as in the
first example. HTTP, timeout, response parsing, and mapping errors are raised
as FireflyAPIError; HTTP errors expose a status_code attribute.
Local Firefly III demo
To experiment without changing your own ledger, run the repository's Docker demo from the repository root:
bash scripts/demo/start.sh
set -a; source .firefly-demo/env; set +a
uv run python examples/min_usage_search.py
The script seeds a SQLite-backed demo at http://127.0.0.1:18080 and reuses
its data on subsequent starts. Stop it with bash scripts/demo/stop.sh.
Credentials in .firefly-demo/ must remain private. The edit examples in the
repository use hardcoded transaction IDs; select an ID from the search output
before running one.