Add Income to your app
Use Income to fetch income information about your users
This guide will walk you through how to use Income to retrieve information about your users' current sources of income.
This is a basic quickstart guide that does not cover all features of the Income product. For more complete information about Income endpoints and capabilities, see the individual product pages for Bank Income, Document Income, and Payroll Income.
Get Plaid API keys and complete application and company profile
If you don't already have one, create a Plaid developer account. After creating your account, you can find your API keys under the Team Settings menu on the Plaid Dashboard.
You also need to complete your application profile and company profile in the Dashboard if you wish to retrieve real data in Production. The information in your profile will be shared with users of your application when they manage their connection on the Plaid Portal, and must be completed before connecting to certain institutions.
Install and initialize Plaid libraries
You can use our official server-side client libraries to connect to the Plaid API from your application:
1// Install via npm2npm install --save plaid
After you've installed Plaid's client libraries, you can initialize them by passing in your client_id
, secret
, and the environment you wish to connect to (Sandbox or Production). This will make sure the client libraries pass along your client_id
and secret
with each request, and you won't need to explicitly include them in any other calls.
1// Using Express2const express = require('express');3const app = express();4app.use(express.json());5
6const { Configuration, PlaidApi, PlaidEnvironments } = require('plaid');7
8const configuration = new Configuration({9 basePath: PlaidEnvironments.sandbox,10 baseOptions: {11 headers: {12 'PLAID-CLIENT-ID': process.env.PLAID_CLIENT_ID,13 'PLAID-SECRET': process.env.PLAID_SECRET,14 },15 },16});17
18const client = new PlaidApi(configuration);
Create a User Token
Unlike many other Plaid products, where you start by creating Items
to represent user connections with individual banks, with Income you first start by creating a user_token
that represents an individual user. As you add various sources of income, those will all be associated with this single user_token
, which allows you to receive consolidated income from different sources by requesting an income report for that user_token
.
To create a user_token
, make a call to the /user/create
endpoint. This endpoint requires a unique client_user_id
value to represent the current user. Typically, this value is the same identifier you're using in your own application to represent the currently signed-in user. This call will return a randomly-generated string for the user_token
as well as a separate user ID that Plaid includes in webhooks to represent this user.
You can only create one user_token
per client_user_id
. If you try to create a user_token
with a client_user_id
that you have previously sent to Plaid, you will receive an error.
Depending on your application, you might wish to create this user_token
as soon as your user creates an account, or right before they begin the process of confirming their income data with you.
1const { IdentityGetRequest } = require('plaid');2
3// Pull Identity data for an Item4const request: IdentityGetRequest = {5 access_token: accessToken,6};7try {8 const response = await plaidClient.identityGet(request);9 const identities = response.data.accounts.flatMap(10 (account) => account.owners,11 );12} catch (error) {13 // handle error14}15
16// The userId here represents the user's internal user ID with your17// application18const createUserToken = async (userId) => {19 const response = await plaidClient.userCreate({20 client_user_id: userId,21 });22 const newUserToken = response.data.user_token;23 const userIdForWebhooks = response.data.user_id;24 await updateUserRecordWithIncomeInfo(userId, newUserToken, userIdForWebhooks);25};
Decide what income verification method(s) you want to support
Income supports three different ways that a user can verify their sources of income.
- Payroll Income allows Plaid to retrieve information such as recent pay stubs and W-2 forms directly from the user's payroll provider. This tends to provide the most comprehensive data, but is dependent upon the user being able to sign in with their payroll provider.
- Document Income allows the user to upload images of income-related documents (such as pay stubs and W-2 forms), which Plaid can scan and interpret for you.
- Bank Income allows the user to connect with their bank to identify deposits that represent sources of income.
Depending on which methods you want to support (and it's perfectly acceptable to support all three), you will need to implement slightly different processes. While you can collect Payroll and Document Income in the same Link flow, you cannot collect Payroll or Document Income in the same Link flow as Bank Income.
Fetching Payroll or Document Income data
The process for implementing Payroll and Document Income is very similar, so we'll cover these two scenarios next.
Create a Link token for Payroll or Document Income
Plaid Link is a drop-in module that provides a secure, elegant UI flow to guide your users through the process of connecting Plaid with their financial institutions. With Income, Link can help your user search for and connect to their payroll provider as well as assist them in uploading documents.
Note that these instructions cover Link on the web. For instructions on using Link within mobile apps, see the appropriate section in the Link documentation.
Before initializing Link, you will need to create a new link_token
on the server side of your application. A link_token
is a short-lived, single-use token that is used to authenticate your app with Link. You can create one using the /link/token/create
endpoint. Then, on the client side of your application, initialize Link with the link_token
that you just created.
When calling the /link/token/create
endpoint, you'll include an object telling Plaid about your application as well as how to customize the Link experience. When creating a link_token
for Payroll or Document Income, there are a few extra values you'll need to supply in this object:
- You will need to pass in the
user_token
that you created earlier. - You can only list
"income_verification"
in the list of products - You will need to create an object with
income_source_types
set to["payroll"]
and pass that as the value forincome_verification
Note that in the code sample below, in addition to passing in a user_token
, we are also passing in the signed in user's ID as the user.client_user_id
value. These are fundamentally different user IDs used for different purposes. The user.client_user_id
value is primarily used for logging purposes and allows you to search for activity in the Plaid Dashboard based on the user ID. While its value is most likely the same user ID that you passed in when creating the user_token
above, they are otherwise unrelated.
1// Using Express2
3app.post('/api/create_link_token_for_payroll_income', async function (4 request,5 response,6) {7 // Get the client_user_id by searching for the current user.8 const clientUserId = await GetSignedInUserId();9 // Get the Plaid user token that we stored in an earlier step10 const userToken = await GetPlaidTokenForUser();11 const request = {12 user: {13 // This should correspond to a unique id for the current user.14 client_user_id: clientUserId,15 },16 client_name: 'Plaid Test App',17 products: ['income_verification'],18 user_token: userToken,19 income_verification: {20 income_source_types: ['payroll'],21 },22 language: 'en',23 webhook: 'https://webhook.example.com',24 country_codes: ['US'],25 };26 try {27 const createTokenResponse = await client.linkTokenCreate(request);28 response.json(createTokenResponse.data);29 } catch (error) {30 // handle error31 }32});
By default, a link_token
created this way will allow the user to collect income information using both the Payroll and Document methods. However, in some cases you might want to permit the user to only use one of these methods. To do that, you can specify the flow_types
, as in the example below.
1income_verification: {2 income_source_types: ["payroll"],3 payroll_income: { flow_types: ["payroll_digital_income"] },4},
Install the Link library
You need to install the Link JavaScript library from Plaid in order to use Link in your web application.
1<head>2 <title>Connect a bank</title>3 <script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>4</head>
Configure the client-side Link handler
To run Link, you'll first need to retrieve the link_token
from the server using the call to /link/token/create
described above. Then, call Plaid.create()
, passing along that token alongside other callbacks you might want to define. This will return a handler that has an open
method. Call that method to open up the Link UI and start the connection process.
1const linkHandler = Plaid.create({2 token: (await $.post('/api/create_link_token_for_payroll_income')).link_token,3 onSuccess: (public_token, metadata) => {4 // Typically, you'd exchange the public_token for an access token.5 // While you can still do that here, it's not strictly necessary.6 },7 onExit: (err, metadata) => {8 // Optionally capture when your user exited the Link flow.9 // Storing this information can be helpful for support.10 },11 onEvent: (eventName, metadata) => {12 // Optionally capture Link flow events, streamed through13 // this callback as your users connect an Item to Plaid.14 },15});16
17linkHandler.open();
If you've had experience with other Plaid products, you're probably used to taking the public_token
received from Link and exchanging it on your server for a persistent access_token
. However, because Payroll and Document Income are fetched once (and don't require persistent connections with your user's bank), and all of your reports are associated with the user's user_token
, there's no need to retrieve or store an access_token
in this case.
Listen for webhooks
After a user has finished using Link, it may take some time before Plaid has the user's income information available for you to download. In the case of Payroll Income, this typically takes a few seconds. For Document Income, this may take several minutes. Listen for the INCOME: INCOME_VERIFICATION
webhook to know when this user's data is ready.
1app.post('/server/receive_webhook', async (req, res, next) => {2 const product = req.body.webhook_type;3 const code = req.body.webhook_code;4 if (product === 'INCOME' && code === 'INCOME_VERIFICATION') {5 const plaidUserId = req.body.user_id;6 const verificationStatus = req.body.verification_status;7 if (verificationStatus === 'VERIFICATION_STATUS_PROCESSING_COMPLETE') {8 await retrieveIncomeDataForUser(plaidUserId);9 } else {10 // Handle other cases11 }12 }13 // Handle other types of webhooks14});
The user_id
value included in this webhook is the same user_id
that was returned by Plaid when you first created a user_token
for this user.
Fetch income data
Now that Plaid has confirmed it has finished processing this user's data, you can fetch the data by making a call to the /credit/payroll_income/get
endpoint. Pass in the user_token
, and Plaid will return all Payroll and Document Income sources associated with that token.
1try {2 const response = await plaidClient.creditPayrollIncomeGet({3 user_token: userToken,4 });5 const incomeData = response.data;6 // Do something interesting with the income data here.7} catch (error) {8 // Handle error9}
This call will typically return an array of items
, each of which represents a connection with a payroll provider. These items
, in turn, contain one or more payroll_income
objects that contain detailed payroll information for the user. This can include individual pay stubs (with a full breakdown of gross pay, deductions, net pay, and more), as well as W-2 forms and all of their information. See the sample response object in the documentation for a full example of what this response might look like.
You can distinguish between income that was retrieved through Payroll Income and income that was retrieved through Document Income by looking for an account_id
value on the payroll_income
object. If the data was retrieved through scanning user documents, this value will be null.
Fetching Bank Income data
As an alternative to downloading income data from the user's payroll provider or W-2 forms, Plaid can also find income data in the user's bank account. Plaid will look for deposits that might be sources of income and ask the user to identify which deposits represent income that they wish to share with your application.
Create a Link token for Bank Income
Creating a link_token
for Bank Income is similar to the process for creating a link_token
for Payroll or Document Income. The main differences are:
- While you still must include
"income_verification"
as a product, you are allowed to combine this product with other products that you might want to use with this financial institution. - Your
income_source_types
must be set to["bank"]
. - Your
income_verification
object must also include abank_income
object, where you have set the value ofdays_requested
. This is the number of days back that Plaid will search for regularly occurring deposits.
The value of days_requested
should a large enough number that you find all relevant deposits, but not so large that the user gets tired waiting for Plaid to retrieve all the relevant data. We recommend 120 days as good balance between the two.
1app.post('/api/create_link_token_for_bank_income', async function (2 request,3 response,4) {5 // Get the client_user_id by searching for the current user.6 const clientUserId = await GetSignedInUserId();7 // Get the Plaid user token that we stored in an earlier step8 const userToken = await GetPlaidTokenForUser();9 const request = {10 user: {11 // This should correspond to a unique id for the current user.12 client_user_id: clientUserId,13 },14 client_name: 'Plaid Test App',15 products: ['income_verification', 'transactions', 'assets'],16 user_token: userToken,17 income_verification: {18 income_source_types: ['bank'],19d bank_income: { days_requested: 120 },20 },21 language: 'en',22 webhook: 'https://webhook.example.com',23 country_codes: ['US'],24 };25 try {26 const createTokenResponse = await client.linkTokenCreate(request);27 response.json(createTokenResponse.data);28 } catch (error) {29 // handle error30 }31});
Install the Link library
As described earlier, you need to install the Link JavaScript library from Plaid to use Link in your web application.
1<head>2 <title>Connect a bank</title>3 <script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>4</head>
Configure the client-side Link handler
Retrieve the link_token
from the server, then call Plaid.create()
, passing along the link_token
alongside other callbacks you might want to define. This will return a handler that has an open
method, which you can call to start the Link process. This is similar to the process described above, but with Bank Income you will probably want to keep the public_token
and exchange it for an access_token
, as described in the next step.
1const linkHandler = Plaid.create({2 token: (await $.post('/api/create_link_token_for_bank_income')).link_token,3 onSuccess: (public_token, metadata) => {4 // Send the public_token to your app server.5 $.post('/exchange_public_token', {6 public_token: public_token,7 });8 },9 onExit: (err, metadata) => {10 // Optionally capture when your user exited the Link flow.11 // Storing this information can be helpful for support.12 },13 onEvent: (eventName, metadata) => {14 // Optionally capture Link flow events, streamed through15 // this callback as your users connect an Item to Plaid.16 },17});18
19linkHandler.open();
Retrieve metadata about the Link session
Call /link/token/get
in your server after receiving onSuccess
, passing in the link_token
. If you enabled Multi-Item Link when calling /link/token/create
, you should instead wait for the SESSION_FINISHED
webhook rather than the onSuccess
frontend callback, to ensure that the Link flow is complete, and all Items have been linked. For more details, see the Multi-Item Link docs.
Previously, customers were instructed to call /credit/sessions/get
to obtain the public token. While this flow is still supported, all customers are encouraged to use the /link/token/get
endpoint to obtain the public token instead, for improved consistency with other Plaid products and flows.
1try {2 const response = await plaidClient.linkTokenGet({3 link_token: LinkToken,4 });5 const sessionData = response.data;6} catch (error) {7 // Handle this error8}
If you are using other Plaid products such as Auth or Balance alongside Bank Income, make sure to capture the public_token
(or tokens) from the results.item_add_result
field and exchange it for an access_token
.
Get a persistent access token (for other products)
For the purpose of retrieving income data, you don't necessarily need an access_token
. Plaid will retrieve the income data for you, and then that data will be associated with the user_token
that you created when first configuring Link.
However, if you are using any other product with this financial institution (such as Transactions, Balance, or Assets), you will need to exchange your public_token
for an access_token
and item_id
. The access_token
lets you make authenticated calls to these other products in the Plaid API.
Exchanging a public_token
for an access_token
is as easy as calling the /item/public_token/exchange
endpoint from the server-side handler. Store the access_token
and item_id
that get returned in a secure server-side location. Never store this information on the client.
1app.post('/api/exchange_public_token', async function (2 request,3 response,4 next,5) {6 const publicToken = request.body.public_token;7 try {8 const response = await client.itemPublicTokenExchange({9 public_token: publicToken,10 });11
12 // These values should be saved to a persistent database and13 // associated with the currently signed-in user14 const accessToken = response.data.access_token;15 const itemID = response.data.item_id;16
17 res.json({ public_token_exchange: 'complete' });18 } catch (error) {19 // handle error20 }21});
Fetch income data
You can fetch income data by calling the /credit/bank_income/get
endpoint using the Plaid client library, passing in the user_token
you created earlier. Note that, similar to Document or Payroll Income, this data is static -- it is a snapshot of the user's income data that was retrieved by Plaid when the user ran Link. It does not update or change over time.
By default, Plaid will only return the most recent report in its response. However, you might want to retrieve more than one report if your user has intentionally run Link multiple times. You can do this by passing an options
object with a count
value set to an integer.
1try {2 const response = await plaidClient.creditBankIncomeGet({3 user_token: userRecord[FIELD_USER_TOKEN],4 options: {5 count: 3,6 },7 });8 const bankIncomeData = response.data;9} catch (error) {10 // Handle this error11}
This call typically returns a bank_income
array, which consists of a number of different objects that represent the report generated when the user ran Link. These individual reports contain an items
array, which in turn contains one or more objects that represent the financial institutions associated with this report. These objects contain a bank_income_accounts
array of objects, which gives you information about the individual accounts, as well as a bank_income_sources
array of objects, which in turn contains the total amount of income reported, along with historical transactions about that income.
Each report also contains a bank_income_summary
object, that summarizes the total bank income identified across all items in this report.
Example code
For an example of an app that incorporates Document, Payroll and Bank Income, see the React and Node-based Income Sample app. The Income Sample app is an application that uses Income and Liability data to help determine whether the user can qualify for financing on a pre-owned hoverboard. It supports the use of all three types of income data.
Next steps
If you're ready to launch to Production, see the Launch checklist.