This is a sample Personal Finance Manager application demonstrating an end-to-end Plaid integration, focused on linking items and fetching transaction data. You can view a simplified version of this demonstration app at pattern.plaid.com.
You may also be interested in the Plaid Transactions tutorial sample app which has an accompanying YouTube video tutorial.
The full Plaid collection of sample apps includes:
Plaid Pattern Personal Finance Manager (you are here) - Demonstrates the Plaid Transactions API
Plaid Pattern Account Funding App - Demonstrates the Plaid Auth, Balance, and Identity APIs
Plaid Transfer Quickstart App - Demonstrates the Transfer API (up to date)
Plaid Pattern Transfer App (deprecated) - Demonstrates the Transfer API (this sample app is deprecated, use the Quickstart app instead)
Plaid Pattern apps are provided for illustrative purposes and are not meant to be run as production applications.
- Node.js v20 or higher
- PostgreSQL v16 or higher
- Plaid API keys - sign up for a free Sandbox account if you don't already have one
- ngrok to expose the server for Plaid webhooks — sign up for a free account to get an authtoken
Windows users: We recommend using WSL (Windows Subsystem for Linux) and following the Linux instructions below.
macOS (with Homebrew):
brew install node postgresql@16
brew services start postgresql@16
brew install ngrok/ngrok/ngrokLinux / WSL (Debian/Ubuntu):
sudo apt update && sudo apt install -y nodejs npm postgresql
sudo systemctl start postgresql
snap install ngrok # or download from https://ngrok.com/downloadNote: We recommend running these commands in a unix terminal. Windows users can use a WSL terminal.
-
Clone the repo.
git clone https://github.com/plaid/pattern.git cd pattern -
Create the
.envfile.cp .env.template .env
-
Update the
.envfile with your Plaid API keys. -
Install dependencies.
npm run install:all
-
Set up the database. Create a
postgressuperuser if one doesn't exist, then initialize the tables.createuser -s postgres # skip if the postgres role already exists npm run db:createOn Linux/WSL, if your PostgreSQL requires a password, set one for the
postgresrole and updatePOSTGRES_PASSWORDin.envto match:psql -U postgres -c "ALTER USER postgres PASSWORD 'password';" -
Configure ngrok with your authtoken (one-time setup):
ngrok config add-authtoken <your-authtoken>
-
Start the app. Run each command in a separate terminal:
ngrok http 5001 # exposes the server for Plaid webhooks npm run server # starts the backend on port 5001 npm run client # starts the frontend on port 3001
-
Open http://localhost:3001 in a web browser.
| Command | Description |
|---|---|
npm run install:all |
Install client and server dependencies |
npm run server |
Start the backend server |
npm run client |
Start the frontend dev server |
npm run db:create |
Initialize the database tables |
npm run db:reset |
Drop and recreate all tables |
Pattern consists of multiple components:
clientruns a React-based single-page web frontend on Viteserverruns an application back-end server using NodeJS and Expressdatabaseuses a PostgreSQL database
The Pattern web client is written in JavaScript using React. It presents a basic Link workflow to the user, including an implementation of OAuth as well as a demonstration of Link update mode. The sample app presents a user's net worth, categorized spending as well as a simple dashboard displaying linked accounts and transactions. The app runs on port 3001 by default.
Aside from websocket listeners (see below), all HTTP calls to the Pattern server are defined in src/services/api.tsx.
The Pattern server is configured to send a message over a websocket whenever it receives a webhook from Plaid. On the client side have websocket listeners defined in src/components/Sockets.jsx that wait for these messages and update data in real time accordingly.
A view of all users is provided to developers on http://localhost:3001/admin. Developers have the ability to remove a user here.
The application server is written in JavaScript using Node.js and Express. It interacts with the Plaid API via the Plaid Node SDK, and with the database using node-postgres. While we've used Node for the reference implementation, the concepts shown here will apply no matter what language your backend is written in.
Plaid does not have a user data object for tying multiple items together, so it is up to application developers to define that relationship. For an example of this, see the root items route (used to store new items) and the users routes.
By default, Plaid Link will let a user link to the same institution multiple times. Some developers prefer disallowing duplicate account linkages because duplicate connections still come at an additional cost. It is entirely possible for a user to create multiple items linked to the same financial institution. In practice, you probably want to prevent this. The easiest way to do this is to check the institution id of a newly created item before performing the token exchange and storing the item. For an example of this, see the root items route.
Plaid uses webhooks to notify you whenever there are changes in the transactions associated with an item. This allows you to make a call to Plaid's transactions sync endpoint only when changes have occurred, rather than polling for them. For an example of this, see the transactions webhook handler. This sample app also demonstrates the use of the sandboxItemResetLogin endpoint to test the webhook used to notify you when a user needs to update their login information at their financial institution.
For webhooks to work, the server must be publicly accessible on the internet. For development purposes, this application uses ngrok to accomplish that. Therefore, if the server is re-started, any items created in this sample app previous to the current session will have a different webhook address attached to it. As a result, webhooks are only valid during the session in which an item is created; for previously created items, no transactions webhooks will be received, and no webhook will be received from the call to sandboxItemResetLogin. In addition, ngrok webhook addresses are only valid for 2 hours. If you are not receiving webhooks in this sample application, restart your server to reset the ngrok webhook address.
Important: When your ngrok session expires or when you restart ngrok (which creates a new URL), any Items that were previously linked will stop receiving webhooks because they're still registered with the old ngrok URL. To receive webhooks for these Items, you'll need to:
- Delete the old Items from the app
- Re-link them using Plaid Link
This will register the Items with the new webhook URL. You can check if webhooks are being received by visiting localhost:4040.
Upon the creation of a new item or receipt of the SYNC_UPDATES_AVAILABLE transactions webhook a call will be made to Plaid's transactions sync endpoint. This will return any changes to transactions that have occurred since you last called the endpoint (or all transactions upon creation of a new item). These changes are then reflected in the database. For an example, see the update_transactions file.
The special test credentials user_transactions_dynamic can be used together with the "Refresh Transactions" button to trigger simulated transaction updates in Sandbox.
To test with user_transactions_dynamic:
- Create an account in the Pattern app (with any username)
- Link a bank account using a non-OAuth test institution such as First Platypus Bank (
ins_109508)- Note: OAuth institutions like most major banks and Playtypus OAuth Bank will not work with these test credentials - you will be able to complete Link, but you will see the same data as the regular
user_goodtest user and not the specialuser_transactions_dynamicdata.
- Note: OAuth institutions like most major banks and Playtypus OAuth Bank will not work with these test credentials - you will be able to complete Link, but you will see the same data as the regular
- When prompted for credentials in the Plaid Link flow, enter:
- Username:
user_transactions_dynamic - Password: any non-blank password
- Username:
- An Item will be created with approximately 50 transactions
- Click the "Refresh Transactions" button next to the linked bank to simulate new transaction activity
What happens when you click refresh:
- New pending transactions are generated
- All previously pending transactions are moved to posted
- All appropriate transaction webhooks are fired
For more realistic testing, Plaid also provides persona-based test users: user_ewa_user, user_yuppie, and user_small_business. These accounts simulate real life personas, so new transactions will appear at a more realistic rate and will not appear every time /transactions/refresh is called. These users have three months of transactions, including some recurring transactions.
To test with persona-based users:
- Link a bank account using a non-OAuth test institution such as First Platypus Bank (
ins_109508) - When prompted for credentials in the Plaid Link flow, enter one of:
- Username:
user_ewa_user(any non-blank password) - Username:
user_yuppie(any non-blank password) - Username:
user_small_business(any non-blank password)
- Username:
- Transactions will update at a more realistic rate when you click "Refresh Transactions"
You can debug the server using Node's built-in inspector:
cd server && node --inspect index.jsThen open chrome://inspect in Chrome, or use the VS Code debugger to attach to the process.
The database is a PostgreSQL instance running locally.
Connect using psql -U postgres or any PostgreSQL client. Default credentials are in .env (user: postgres, password: password).
API and Link Identifiers are crucial for maintaining a scalable and stable integration. Occasionally, an Institution error may occur due to a bank issue, or a live product pull may fail on request. To resolve these types of issues, Plaid Identifiers are required to open a Support ticket in the Dashboard.
access_tokens and item_ids are the core identifiers that map end-users to their financial institutions.
As such, we are storing them in the database associated with our application users.
These identifiers should never be exposed client-side.
Plaid returns a unique request_id in all server-side responses and Link callbacks.
A link_session_id is also returned in Link callbacks.
These values can be used for identifying the specific network request or Link session for a user, and associating that request or session with other events in your application.
We store these identifiers in database tables used for logging Plaid API requests, as they can be useful for troubleshooting.
For more information, see the docs page on storing Plaid API identifiers.
The *.sql scripts in the database/init directory define the schema. Run npm run db:create to initialize, or npm run db:reset to drop and recreate.
See the create.sql initialization script to see some brief notes for and the schemas of the tables used in this application. While most of them are fairly self-explanatory, we've added some additional notes for some of the tables below.
This table stores responses from the Plaid API for client requests to the Plaid Link client.
User flows that this table captures (based on the client implementation, which hooks into the onExit and onSuccess Link callbacks):
- User opens Link, closes without trying to connect an account.
This will have type
exitbut norequest_id,error_type, orerror_code. - User tries to connect an account, fails, and closes link.
This will have type
exitand will have arequest_id,error_type, anderror_code. - User successfully connects an account.
This will have type
successbut norequest_id, error_type, orerror_code.
This table stores responses from the Plaid API for server requests to the Plaid client.
The server stores the responses for all of the requests it makes to the Plaid API.
Where applicable, it also maps the response to an item and user.
If the request returned an error, the error_type and error_code columns will be populated.
The sections below are optional: on desktop, OAuth will work without a redirect URI configured. However, using redirect URIs is recommended for best conversion on mobile web, and mandatory when using a Plaid mobile SDK. For more details, see the documentation on redirect URIs on desktop and mobile web.
To test with an OAuth redirect URI, in the .env file, set your PLAID_SANDBOX_REDIRECT_URI to 'http://localhost:3001/oauth-link' and then register this URI in your Plaid Dashboard at https://dashboard.plaid.com/team/api.
If you want to test OAuth redirect URIs in Production, you need to use https and set PLAID_PRODUCTION_REDIRECT_URI=https://localhost:3001/oauth-link in .env. In order to run your localhost on https, you will need to create a self-signed certificate and add it to the client root folder. MacOS users can use the following instructions to do this. Note that self-signed certificates should be used for testing purposes only, never for actual deployments.
In your terminal, change to the client folder:
cd clientUse homebrew to install mkcert:
brew install mkcertThen create your certificate for localhost:
mkcert -install
mkcert localhostThis will create a certificate file localhost.pem and a key file localhost-key.pem inside your client folder.
Then in vite.config.ts in the client folder, add the https option to the server config:
import fs from 'fs';
export default defineConfig({
// ...
server: {
port: 3001,
https: {
key: fs.readFileSync('localhost-key.pem'),
cert: fs.readFileSync('localhost.pem'),
},
// ...
},
});After starting the client, you can view it at https://localhost:3001.
If you are on a Windows machine, follow the same vite.config.ts changes described in the MacOS section above, but skip the mkcert steps. Vite will use a self-signed certificate.
After starting the client, you can view it at https://localhost:3001. Your browser will alert you with an invalid certificate warning; click on "advanced" and proceed.
- For an overview of the Plaid platform and products, refer to this Quickstart guide.
- Check out this high-level introduction to Plaid Link.
- Find comprehensive information on Plaid API endpoints in the API documentation.
- Questions? Please head to the Help Center or open a Support ticket.
Plaid Pattern is a demo app that is intended to be used only for the purpose of demonstrating how you can integrate with Plaid. You are solely responsible for ensuring the correctness, legality, security, privacy, and compliance of your own app and Plaid integration. The Pattern code is licensed under the MIT License and is provided as-is and without warranty of any kind. Plaid Pattern is provided for demonstration purposes only and is not intended for use in production environments.
