Preventing duplicate Items
Prevent unnecessary billing and confusing application behavior
Prefer to learn by watching? A video guide is available for this topic.
How duplicate Items are created
An Item represents a login at a financial institution. This login typically happens when an end user links an account (or several accounts) using Plaid Link. A duplicate Item will be created if the end user logs into the same institution using the same credentials again using Plaid Link (in the same application), and if an access token is requested for the Item.
Duplicate Items can occur for multiple reasons. For example, a duplicate Item can occur if a user accidentally links the same account more than once, because they do not realize they already linked an account, or because their linked account is no longer working. Duplicate Items can also occur if a user intentionally links multiple Items for abusive purposes (for example, as part of an attempt to receive multiple sign-up bonuses or to evade a ban).
Duplicate Items can create confusing or unwanted behavior in your application and could result in being potentially billed for multiple Items. We recommend building safeguards in your application to help prevent end users from creating duplicate Items. In this article, we'll describe a few ways to prevent and detect Item duplication.
Preventing duplicate Items
Use the onSuccess callback metadata
The onSuccess
callback is called when a user successfully links an Item using Plaid Link. This callback provides metadata that you can use to prevent duplicate Items from being created. One approach is to require a user login prior to launching Plaid Link so that you can retrieve existing Items associated with the user.
Then, before requesting an access_token
, examine and compare the onSuccess
callback metadata to the user's existing Items. You can compare a combination of the accounts’ institution_id
, account name
, and account mask
to determine whether an end user has previously linked an account to your application. Do not exchange a public token for an access token if you detect a duplicate Item.
While the mask
value is usually the same as the last 4 digits of the account number, this is not the case at all institutions. Never detect duplicate Items by attempting to match a mask
with an account number.
1{2 institution: {3 name: 'Wells Fargo',4 institution_id: 'ins_4'5 },6 accounts: [7 {8 id: 'ygPnJweommTWNr9doD6ZfGR6GGVQy7fyREmWy',9 name: 'Plaid Checking',10 mask: '0000',11 type: 'depository',12 subtype: 'checking',13 verification_status: ''14 },15 {16 id: '9ebEyJAl33FRrZNLBG8ECxD9xxpwWnuRNZ1V4',17 name: 'Plaid Saving',18 mask: '1111',19 type: 'depository',20 subtype: 'savings'21 }22 ...23 ],24 link_session_id: '79e772be-547d-4c9c-8b76-4ac4ed4c441a'25}
Note that duplicate Items are not always identical. For example, an Item may have a checking account linked, while its duplicate may have only a savings account linked. While this scenario is rare, if it becomes a problem for your use case, you can switch to using the institution_id
field on a per-user basis to prevent duplicate Items and enforce that each user of your app not link multiple Items with the same institution. However, because this is a legitimate use case for some applications, it is not recommended as the primary means of detecting duplicate Items.
Duplicate Items with certain OAuth institutions
For Chase, PNC, and Charles Schwab, existing Items will be invalidated if an end user adds a second Item using the same credentials, at the point when the user has completed the institution's OAuth flow. For this reason, the onSuccess
metadata approach cannot be used to prevent duplicate Items at these institutions. Instead, use alternative means of preventing duplicate Items, such as providing pre-Link messaging. If a duplicate Item is created, delete the old Item using /item/remove
.
If the user completes the OAuth flow at these institutions but does not successfully complete the Link flow, the existing Item will still be invalidated and eventually enter the ITEM_LOGIN_REQUIRED
state, even though a new Item was never successfully created. If this occurs, the old Item can repaired using update mode. If the user did successfully create a new Item, do not use update mode on the old Item, as it will invalidate the new Item. Instead, delete the old Item using /item/remove
.
For Auth or Transfer customers, Chase or PNC Item invalidation caused by creating a duplicate Item will not invalidate or change the Item's TAN.
Implement Pre-Link messaging
A lightweight but effective method for preventing accidental duplicate Items from being created is by providing relevant messaging and information to end users before they engage with Plaid Link in your application. For example, displaying a list of accounts they've already connected to your application can help prevent end users from inadvertently linking the same accounts again.
Use Link's update mode
From time to time, an Item may become unhealthy due to entering the ITEM_LOGIN_REQUIRED
state. Or, the Item may still be healthy, but you may want your end user to authorize additional accounts or permissions associated with the Item. When either of these scenarios happens, use Link in update mode to refresh the Item instead of creating a new Item.
Example implementation: Preventing accidental duplicate Items
For an example that demonstrates how to prevent accidental duplicate Items, see the Plaid Pattern sample app. Plaid Pattern implements simple server-side logic to check whether the user ID and institution ID pair already exist in the application database. If the pair exists, an access token will not be requested for this Item, thereby preventing a duplicate. In addition, a message is displayed to the end user informing them that they've already linked this Item. The relevant code can be found in /server/routes/items.js and /server/db/queries/items.js.
Identifying existing duplicate Items
To identify existing duplicate Items, use the same matching logic as described above, but retrieve this data via the /accounts/get
endpoint instead of the onSuccess
callback. Occasionally, the mask
or name
fields may be null, in which case you can compare institution_id
and client_user_id
as a fallback. After identifying duplicate Items, use the /item/remove
endpoint to delete an Item.
If you are using Auth via /auth/get
, existing duplicate Items may be detected by using the account and routing number fields and looking for duplicates. Note that this method will not work for Chase Items, as Chase uses tokenized account numbers. To detect existing duplicate Items at Chase, you can use the persistent_account_id
field, which will be the same across duplicate instances of a Chase Item.
Detecting and preventing duplicate Items across user accounts
When attempting to detect or prevent duplicate Items, your approach should depend on the type of duplicate Item you are trying to prevent. For example, you can often scope your search to either a single user's accounts, or to all accounts known to your application. If you are attempting to prevent accidental duplicate Items, you should scope the search to a single user; if you are attempting to detect or prevent abuse, it may make more sense to expand your search to all accounts that have been linked to your app.
Note that there can be legitimate use cases for the same financial institution account to be linked across multiple different user accounts (for example, family members who share a joint bank account, or employees of the same company who share access to a business account); depending on your use case, you may want to incorporate this data into a broader abuse detection framework rather than blocking all duplicate accounts.