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 create confusing 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 accidentally creating duplicate Items. In this article, we'll describe a few ways to prevent 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}
For Items linked via OAuth or Account Selection v2, 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 institutions
For Chase or Charles Schwab, existing Items will be invalidated if an end user adds a second Item using the same credentials, at the point when the onSuccess
callback is returned. 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, described below. If a duplicate Item is created, delete the old Item using /item/remove
.
Implement Pre-Link messaging
A lightweight but effective method for preventing 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 duplicate Items
For an example that demonstrates how to prevent 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.
1...23const existingItem = await retrieveItemByPlaidInstitutionId(4 institutionId,5 userId6 );7 if (existingItem)8 throw new Boom('You have already linked an item at this institution.', {9 statusCode: 409,10});1112...
1/**2 * Retrieves a single item.3 *4 * @param {string} plaidInstitutionId the Plaid institution ID of the item.5 * @param {number} userId the ID of the user.6 * @returns {Object} an item.7 */8const retrieveItemByPlaidInstitutionId = async (plaidInstitutionId, userId) => {9 const query = {10 text:11 'SELECT * FROM items WHERE plaid_institution_id = $1 AND user_id = $2',12 values: [plaidInstitutionId, userId],13 };14 const { rows: existingItems } = await db.query(query);15 return existingItems[0];16};
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.