Connector to pull Plaid financial data into the Firefly finance tool.
Inspired by firefly-plaid-connector.
Please note this version of the connector requires at least version v6.1.2 of Firefly.
These are basic instructions for installing and running the connector. See further topics below for more details.
persistence/
subdirectory in your working directory for the connector to persist data to that's writeable
by the user running the connector.application.yml
and modifying as needed.
See below for details on configuration.java -jar connector.jar --spring.config.location=application.yml
New versions of the Docker image are pushed to GHCR with each release.
The latest version is available at ghcr.io/dvankley/firefly-plaid-connector-2:latest
.
You can also build your own with ./gradlew bootBuildImage --imageName=your-docker-registry/firefly-plaid-connector-2
.
HOST_APPLICATION_CONFIG_FILE_LOCATION
environment variable to point to your
config file
(or just manually insert your path in the compose file).docker-compose-polled.yml
), create a directory on your host machine
that is writable by anyone, then pass its location in as HOST_PERSISTENCE_DIRECTORY_LOCATION
.
docker compose up
.
The application container requires the following:
SPRING_CONFIG_LOCATION
environment variable can be
used to set the location (in the container) of the application configuration file.FIREFLYPLAIDCONNECTOR2_POLLED_CURSORFILEDIRECTORYPATH
environment variable can be
used to set the location (in the container) of the directory that will contain the sync cursor file.The example below uses bind mounts for these purposes for
simplicity, but you can also use volumes if you want.
If using volumes you will need to use an intermediate container
to write the application configuration file to a volume, as well as setting permissions to allow the
application user cnb
to write to the cursor file directory's volume.
docker run \
--mount type=bind,source=/host/machine/application/config/file/directory,destination=/opt/fpc-config,readonly \
--mount type=bind,source=/host/machine/writeable/directory,destination=/opt/fpc-cursors \
-e SPRING_CONFIG_LOCATION=/opt/fpc-config/application.yml \
-e FIREFLYPLAIDCONNECTOR2_POLLED_CURSORFILEDIRECTORYPATH=/opt/fpc-cursors \
-t firefly-plaid-connector-2
The connector can be run in either batch
or polled
mode.
Uses the Plaid transactions get endpoint to pull historical Plaid transaction data, convert it to Firefly transactions, and write them to Firefly.
This is typically used when you're first setting up your Firefly instance and you want to backfill existing transactions
before running indefinitely in polled
mode.
Batch
mode can be memory intensive if you're pulling a large volume of transactions, so if your Firefly server is
running on a low-spec VPS (like mine), then I recommend running your large batch
mode pull on a higher spec machine
(like your home computer or whatever). It can still be pointed at your existing Firefly server with no problem.
Uses the Plaid sync endpoint to periodically pull down transaction data, convert it to Firefly transactions, and write them to Firefly.
When started in this mode, the connector will not pull any past transactions, but will check for new transactions every
fireflyPlaidConnector2.polled.syncFrequencyMinutes
.
The last sync position of each account will be stored in persistence/plaid_sync_cursors.txt
.
The most complex part of the connector by far is the transfer matching logic. Firefly has a notion of transfers, which are special transactions that instead of the usual flow of money from an asset account into an expense account or from a revenue account into an asset account, represent the flow of money from one asset account into another.
For me this typically happens when I'm making payments on credit cards or the like (because I have credit cards set up as asset accounts instead of liability accounts because that's how Firefly works).
Plaid has no notion of inter-account transactions; transaction data only references the account that it's on.
We try to bridge these by matching two Plaid transactions on different asset accounts and converting them into a single
Firefly transfer. You can see the full logic in TransactionConverter.sortByPairs
, but the summary is that the
connector searches for pairs of Plaid transfer-type transactions with inverse amounts (i.e. $100 and -$100)
that are within fireflyPlaidConnector2.transferMatchWindowDays
of each other. This isn't flawless, but
is sufficient in most cases.
Note that if the connector attempts to convert an existing non-transfer Firefly transaction and an incoming Plaid transaction to a Firefly transfer, the existing Firefly transaction will be deleted and the new transfer transaction will be created because the Firefly API does not support converting existing transaction types.
Note: Given that the balance endpoint is now $0.10 per call, this feature isn't really worth using anymore.
If fireflyPlaidConnector2.batch.setInitialBalance
is set to true
, the connector will try to create "initial balance"
transactions for each Firefly account that result in the current Firefly balance for each account equalling the
current balance that Plaid reports for that account.
This is determined by summing up all transactions pulled during
this run for that account, then subtracting that from the Plaid-reported current balance to get the amount for the
"initial balance" transaction.
For Firefly asset accounts that are of the "credit card" type, the Plaid balance is interpreted as a negative rather than a positive value. This is because Plaid always reports balances as positive (as far as I can tell), and it's assumed that a Firefly account set as a credit card is linked to a Plaid account that's also a credit card.
Ensure that the current balance in the target Firefly accounts are 0 before using this feature.
Because the initial balance transaction amount is determined from the transactions pulled in this batch, I do not recommend enabling this feature unless you're pulling all of the transactions you intend to backfill for a given account (as opposed to just filling in some gaps).
Note that the Plaid balance endpoint (or the underlying institution data source) is kind of crappy. To wit:
lastUpdatedDatetime
field in the response schema, but according to the Plaid documentation it's only
populated for Capital One for whatever reason,
and due to that it's impossible to tell exactly what point in time the Plaid balance represents.
As you have probably guessed from the name, Plaid is an important part of using this connector. To use Plaid, you will need an account.
Once upon a time, you could use up to 100 items in the Plaid development environment for free, but that is no longer the case.
If you're a new user, you will need to sign up for production environment access. This is a relatively painless process
to go through, but of course the main downside is that you have to pay for it. Plaid bills $0.30/institution/month for
the transactions
product, which is all you need for the connector to work (unless you enable initial balances,
which I feel like doesn't make sense anymore given the billing model).
Note that this is per institution, not per account. For instance if you have 2 accounts on one institution, you will
only be billed $0.30 a month.
If you're an existing user of the development environment, you may be able to get away with "free limited Production access" per this comment, but I wouldn't recommend planning on that.
If you're an existing user of the development environment and looking to migrate to the production environment, see the section on migration.
If you want access to US Oauth institutions, you need to jump through some additional hoops. Based on my brief conversation with Plaid support and my personal experience, you can skim through the company info and security questionnaire pretty quickly, using dummy names, logos, and answering "I'm a hobbyist using this for personal use" for all the security questions.
Once you've completed all the requirements for Oauth access, the applicable institutions should just work in Quickstart (see below).
Once you've signed up for Plaid, you should be provided a client id and secret, which go in the application config
file where you'd expect (fireflyPlaidConnector2.plaid.clientId
and fireflyPlaidConnector2.plaid.secret
).
Next up, you need to connect Plaid to your various financial institutions. The easiest way to do this is to run
Plaid Quickstart locally. I found the Docker experience to be fairly painless.
I recommend copying the .env.example
file to a new .env
file, filling in your credentials, setting PLAID_ENV
to
development
or production
, and setting PLAID_PRODUCTS
to transactions
.
Note that you will need to add balances
to use the initial balances feature, but given that
there's an additional cost for that in production, it's not really worth it.
Note that
if you leave PLAID_PRODUCTS
set to the default auth,transactions
, you won't be able to connect to some of the
financial institutions you might expect because they don't support the auth
product.
Once you have Quickstart running, just follow the UI prompts to connect to your financial institutions.
For each institution you connect to, Plaid should give you an item_id
and an access_token
. Make a note of both.
Each institution can contain multiple accounts (i.e. your bank has both your savings and checking account). If you scroll down in the Quickstart page, you should also see a list of account ids associated with that item. Make a note of each account you want to use with Firefly, as you will need to enter them in the connector's configuration file.
The configuration file is unsurprisingly where most of the configuration of the connector takes place.
I recommend copying the application.yml
file
and customizing it to your preferences. Each property should be well documented in the comments of that file.
This is my workflow for using the connector with Firefly. Of course, you don't have to use it exactly like this, but you may find this useful for reference in thinking through your own workflow.
FOOD_AND_DRINK.BEER_WINE_AND_LIQUOR
and ENTERTAINMENT
to a
"Spending" budget.true
false
plaid-detailed-cat-coffee
etc.batch
mode
fireflyPlaidConnector2.batch.maxSyncDays
property is up to you. I used 2 years for my initial backfill,
but your value will depend on your needs and patience for the process.
polled
mode.
systemd
unit to run the connector on my Debian VPS, your mileage may vary.
[Unit]
Description=Firefly Plaid Connector 2
[Service]
WorkingDirectory=/opt/firefly-plaid-connector
ExecStart=/bin/java -Xms128m -Xmx1024m -jar firefly-plaid-connector.jar --spring.profiles.active=prod
User=firefly-plaid-connector
Type=simple
Restart=on-failure
RestartSec=10
Environment=“SPRING_CONFIG_LOCATION=/opt/firefly-plaid-connector/application-prod.yml”
[Install]
WantedBy=multi-user.target
On occasion, you will get an ITEM_LOGIN_REQUIRED
error in the connector logs. This typically happens when the credentials
for one of the institutional accounts you've linked Plaid to have changed. You can find the access token for the account in question on the log line above the exception log.
There are two methods for resolving the error, described below.
This is the recommended method of resolving this issue, although it's a bit more complex than create mode.
https://localhost:3000
.ITEM_LOGIN_REQUIRED
error (it should be in the connector logs just above the exception).https://localhost:3000?input_access_token=$yourAccessTokenHere
in your browser.After completing these steps, your account credentials should be fixed and the connector should resolve itself on its next run (assuming you're running in polled mode).
This is basically just going through the Connecting Accounts workflow again for that account, replacing the access token and account id in your configuration file, and restarting the connector. Unfortunately, as discussed in https://github.com/dvankley/firefly-plaid-connector-2/issues/39, this method permanently chews through your Item quota and is NOT RECOMMENDED for that reason. At this point it does have the advantage of being simpler than update mode, which is why it's listed here as an option.
If you're getting this error frequently, check if you have MFA enabled on your account with the corresponding financial institution. MFA can cause high frequency invalidation of Plaid account credentials, so consider disabling it. Obviously compromising your security posture to use this connector isn't great, so hopefully your institution provides limited permission accounts for service access.
Also note that CIBC currently has this issue.
If you've been using the development
environment for a while and are now being compelled to move to production
, here's
a checklist of the steps I followed to perform this migration that might be helpful.
plaid.url
should be https://production.plaid.complaid.secret
needs to be updated to your new secret.When setting up access to a provider from the Plaid Quick Start I'm getting a message "Something went wrong".
INSTITUTION_NO_LONGER_SUPPORTED
or UNAUTHORIZED_INSTITUTION
errors.I'm getting an ITEM_LOGIN_REQUIRED
error when running the connector.
The logging
key in the application configuration file controls the logging level of various packages and classes in
the application. Setting logging.level.net.djvk
to DEBUG
or TRACE
is recommended if you're having problems,
as it will log additional info that should help diagnose the issue.
If you have an issue, feel free to report it via the Github issue tracker. I am actively maintaining this project
but my available time is finite, so the odds of your issue being addressed will be increased if you include relevant
logs at the TRACE
level with your issue report.
Writing a test case (i.e. in net.djvk.fireflyPlaidConnector2.transactions.TransactionConverterTest
) to demonstrate
your issue greatly increases the chances of me fixing it quickly. If test infrastructure is missing to test the
element of the code you see an issue with, let me know and I can work on improving that.
Setup should be identical to any other Spring Boot/Gradle application.
I recommend adding an additional configuration file (i.e. application-dev.yml
) and enabling the corresponding Spring
profile (i.e. dev
) to allow you to persist and iterate on your local configuration.
I recommend setting up a local copy of Firefly for development purposes, especially one that you can easily backup and restore the database for to minimize your feedback loop on testing things.
Do you, like me, run Home Assistant and also want real-ish time budget notifications? Then check out this Node-RED flow.