Experimental features
Danger
Experimental features do not have all the testing necessary to ensure correctness compared to the files generated by the JavaScript API. This means that these operations could, in theory, corrupt your data. Make sure you have backups of your data before trying any of these operations.
Bootstrapping a new server and uploading a first file
The following script will generate a new empty budget on the Actual server, even if the server was not bootstrapped with an initial password:
from actual import Actual
with Actual(base_url="http://localhost:5006", password="mypass", bootstrap=True) as actual:
actual.create_budget("My budget")
actual.upload_budget()
You will then have a freshly created new budget to use:

If the encryption_password is set, the budget will additionally also be encrypted on the upload step to the server.
Updating transactions using Bank Sync
If you have either goCardless or SimpleFIN integration configured, you can update transactions using only the Python API. This is possible because the actual queries to the third-party service are handled on the server, so the client doesn't need to make custom API queries.
To sync your account, call the Actual.run_bank_sync method:
from actual import Actual
with Actual(base_url="http://localhost:5006", password="mypass") as actual:
synchronized_transactions = actual.run_bank_sync()
for transaction in synchronized_transactions:
print(f"Added of modified {transaction}")
# sync changes back to the server
actual.commit()
Running Rules
Rules can be run individually via the library. You can filter which rules will run and check beforehand which rules will actually execute, similar to the preview function in Actual.
The simplest case is to run all rules for all transactions at once. This is equivalent to clicking "Apply Actions" for all rules in the frontend:
from actual import Actual
from actual.queries import get_ruleset
with Actual(base_url="http://localhost:5006", password="mypass", file="My budget") as actual:
# print all rules and their human-readable descriptions
print(get_ruleset(actual.session))
# run all rules
actual.run_rules()
# sync changes back to the server
actual.commit()
If you're running bank sync, you can also run rules directly on the imported transactions after performing the sync:
from actual import Actual
with Actual(base_url="http://localhost:5006", password="mypass") as actual:
synchronized_transactions = actual.run_bank_sync(run_rules=True)
You can also manipulate rules individually and validate each rule that runs for each transaction, allowing you to debug rules. This can be useful when multiple rules are modifying the same transaction, but the order of operations is incorrect:
from actual import Actual
from actual.queries import get_ruleset, get_transactions
with Actual(base_url="http://localhost:5006", password="mypass", file="My budget") as actual:
ruleset = get_ruleset(actual.session)
transactions = get_transactions(actual.session)
for rule in ruleset:
for t in transactions:
if rule.evaluate(t):
print(f"Rule {rule} matches for {t}")
# if you are happy with the result from the rule, apply it
rule.run(t)
# if you want to sync the changes back to the server, uncomment the following line
# actual.commit()
When importing transactions, rules don't run automatically: you might need to run them individually. Use the RuleSet.run method to run rules after creating/importing a transaction:
from actual import Actual
from actual.queries import get_ruleset, reconcile_transaction
from datetime import date
with Actual(base_url="http://localhost:5006", password="mypass", file="My budget") as actual:
# we create one transaction
t = reconcile_transaction(actual.session, date.today(), "Bank", "", notes="Coffee", amount=-4.50)
# run the rules on the newly created transaction
ruleset = get_ruleset(actual.session)
ruleset.run(t)
# send the changes back to the server
actual.commit()