Automated Micro-deposits
Learn how to authenticate your users in a secure and frictionless micro-deposit flow
The Automated Micro-deposit flow
The Automated Micro-deposits authentication flow is supported for over 1,000 financial institutions in the US only, accounting for approximately <1% of depository accounts. Plaid will make a single micro-deposit and then automatically verify it within one to two business days.
You can try out the Automated Micro-deposits flow in Link Demo. See more details in our testing guide.
A user connects their financial institution using the following connection flow:
- Starting on a page in your app, the user clicks an action that opens Plaid Link, with the correct Auth configuration.
- Inside of Plaid Link, the user selects their institution, authenticates with their credentials, provides their account and routing number, and enters in their legal name.
- Upon successful authentication, Link closes with a
public_token
and ametadata
account status ofpending_automatic_verification
. - Behind the scenes, Plaid sends a single micro-deposit to the user's account and will automatically verify the deposited amounts within one to two business days.
- When verification succeeds or fails, Plaid sends an Auth webhook, which you can use to notify the user that their account is ready to move money. Once this step is done, your user's Auth data is verified and ready to fetch.
Configure & Create a link_token
Create a link_token
with the following parameters:
products
array containingauth
ortransfer
-- unlike with Same-Day Micro-deposits, you can also include other products besidesauth
ortransfer
when creating a Link token for use with Automated Micro-deposits, butauth
ortransfer
must be present.country_codes
set to['US']
– Micro-deposit verification is currently only available in the United States.- A
webhook
URL to receive a POST HTTPS request sent from Plaid's servers to your application server, after Automated Micro-deposits succeeds or fails verification of a user's micro-deposits. auth
object should specify"automated_microdeposits_enabled": true
1const request: LinkTokenCreateRequest = {2 user: { client_user_id: new Date().getTime().toString() },3 client_name: 'Plaid App',4 products: [Products.Auth],5 country_codes: [CountryCode.Us],6 language: 'en',7 auth: {8 automated_microdeposits_enabled: true,9 },10};11try {12 const response = await plaidClient.linkTokenCreate(request);13 const linkToken = response.data.link_token;14} catch (error) {15 // handle error16}
Initialize Link with a link_token
After creating a link_token
for the auth
product, use it to initialize Plaid Link.
When the user inputs their username and password, and account and routing numbers for the financial institution,
the onSuccess()
callback function will return a public_token
, with verification_status
equal to 'pending_automatic_verification'
.
1const linkHandler = Plaid.create({2 // Fetch a link_token configured for 'auth' from your app server3 token: (await $.post('/create_link_token')).link_token,4 onSuccess: (public_token, metadata) => {5 // Send the public_token and accounts to your app server6 $.post('/exchange_public_token', {7 publicToken: public_token,8 accounts: metadata.accounts,9 });1011 metadata = {12 ...,13 link_session_id: String,14 institution: { name: 'Bank of the West', institution_id: 'ins_100017' },15 accounts: [{16 id: 'vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D',17 mask: '1234',18 name: null,19 type: 'depository',20 subtype: 'checking' | 'savings',21 verification_status: 'pending_automatic_verification'22 }]23 }24 },25 // ...26});2728// Open Link on user-action29linkHandler.open();
Display a "pending" status in your app
Because Automated verification usually takes between one to two days to complete, we recommend displaying a UI in your app that communicates to a user that verification will occur automatically and is currently pending.
You can use the verification_status
key returned in the onSuccess
metadata.accounts
object once
Plaid Link closes successfully.
1verification_status: 'pending_automatic_verification';
You can also fetch the verification_status
for an
Item's account via the Plaid API to obtain the latest account status.
Exchange the public token
In your own backend server, call the /item/public_token/exchange
endpoint with the Link public_token
received in the onSuccess
callback to obtain an access_token
.
Persist the returned access_token
and item_id
in your database in relation to the user.
Note that micro-deposits will only be delivered to the ACH network in the Production environment. To test your integration outside of Production, see Testing automated micro-deposits in Sandbox.
Select group for content switcher1// publicToken and accountID are sent from your app to your backend-server2const accountID = 'vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D';3const publicToken = 'public-sandbox-b0e2c4ee-a763-4df5-bfe9-46a46bce993d';45// Obtain an access_token from the Link public_token6const response = await client7 .itemPublicTokenExchange({8 public_token: publicToken,9 })10 .catch((err) => {11 // handle error12 });13const accessToken = response.access_token;
1{2 "access_token": "access-sandbox-5cd6e1b1-1b5b-459d-9284-366e2da89755",3 "item_id": "M5eVJqLnv3tbzdngLDp9FL5OlDNxlNhlE55op",4 "request_id": "m8MDnv9okwxFNBV"5}
Handle Auth webhooks
Before you can call /auth/get
to fetch Auth data for a user's access_token
, a micro-deposit first
need to post successfully to the user's bank account. Because Plaid uses Same Day ACH to send a
single micro-deposit amount, this process usually takes between one to two days.
Once the deposit has arrived in the user's account, Plaid will automatically verify the deposit
transaction and send an AUTOMATICALLY_VERIFIED
webhook to confirm the account and routing numbers have been successfully verified.
Attempting to call /auth/get
on an unverified access_token
will result
in a PRODUCT_NOT_READY
error.
1> POST https://your_app_url.com/webhook23{4 "webhook_type": "AUTH",5 "webhook_code": "AUTOMATICALLY_VERIFIED",6 "item_id": "zeWoWyv84xfkGg1w4ox5iQy5k6j75xu8QXMEm",7 "account_id": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D"8}
Occasionally automatic verification may fail, likely due to erroneous user input, such as an incorrect
account and routing number pair. If the Item is unable to be verified within seven days, Plaid will send
a VERIFICATION_EXPIRED
webhook. When verification fails, the Item is permanently locked; we recommend prompting your user to
retry connecting their institution via Link.
1> POST https://your_app_url.com/webhook23{4 "webhook_type": "AUTH",5 "webhook_code": "VERIFICATION_EXPIRED",6 "item_id": "zeWoWyv84xfkGg1w4ox5iQy5k6j75xu8QXMEm",7 "account_id": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D"8}
If Plaid encounters an ITEM_LOGIN_REQUIRED
error during attempted validation, this may mean that Plaid lost access to the user's account after sending this micro-deposit but before being able to verify it. If this occurs, send the user through the update mode flow to re-verify their account.
The example code below shows how to handle AUTOMATICALLY_VERIFIED
and VERIFICATION_EXPIRED
webhooks
and call /auth/get
to retrieve account and routing data.
If you are using the Sandbox environment, you can use
the /sandbox/item/set_verification_status
endpoint to test your integration.
1// This example uses Express to receive webhooks2const app = require('express')();3const bodyParser = require('body-parser');4app.use(bodyParser);56app.post('/webhook', async (request, response) => {7 const event = request.body;89 // Handle the event10 switch (event.webhook_code) {11 case 'AUTOMATICALLY_VERIFIED':12 const accessToken = lookupAccessToken(event.item_id);13 const request: AuthGetRequest = { access_token: accessToken };14 const authResponse = await client.authGet(request);15 const numbers = authResponse.numbers;16 break;17 case 'VERIFICATION_EXPIRED':18 // handle verification failure; prompt user to re-authenticate19 console.error('Verification failed for', event.item_id);20 break;21 default:22 // Unexpected event type23 return response.status(400).end();24 }2526 // Return a response to acknowledge receipt of the event27 response.json({ received: true });28});2930app.listen(8000, () => console.log('Running on port 8000'));
Check the account verification status (optional)
In some cases you may want to implement logic to display the verification_status
of an Item
that is pending automated verification in your app. The /accounts/get
API endpoint allows you to query this information.
1// Fetch the accountID and accessToken from your database2const accountID = 'vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D';3const accessToken = 'access-sandbox-5cd6e1b1-1b5b-459d-9284-366e2da89755';4const request: AccountsGetRequest = {5 access_token: accessToken,6};7const response = await client.accountsGet(request).catch((err) => {8 // handle error9});10const account = response.accounts.find((a) => a.account_id === accountID);11const verificationStatus = account.verification_status;
1{2 "accounts": [3 {4 "account_id": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D",5 "balances": { Object },6 "mask": "0000",7 "name": "Plaid Checking",8 "official_name": "Plaid Gold Checking",9 "type": "depository"10 "subtype": "checking" | "savings",11 "verification_status":12 "pending_automatic_verification" |13 "automatically_verified" |14 "verification_expired",15 },16 ...17 ],18 "item": { Object },19 "request_id": String20}
Fetch Auth data
Finally, we can retrieve Auth data once automated verification has succeeded:
Select group for content switcher1const accessToken = 'access-sandbox-5cd6e1b1-1b5b-459d-9284-366e2da89755';23// Instantly fetch Auth numbers4const request: AuthGetRequest = {5 access_token: accessToken,6};7const response = await client.authGet(request).catch((err) => {8 // handle error9});10const numbers = response.numbers;
1{2 "numbers": {3 "ach": [4 {5 "account_id": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D",6 "account": "1111222233330000",7 "routing": "011401533",8 "wire_routing": "021000021"9 }10 ],11 "eft": [],12 "international": [],13 "bacs": []14 },15 "accounts": [16 {17 "account_id": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D",18 "balances": { Object },19 "mask": "0000",20 "name": "Plaid Checking",21 "official_name": "Plaid Gold Standard 0% Interest Checking",22 "verification_status": "automatically_verified",23 "subtype": "checking" | "savings",24 "type": "depository"25 }26 ],27 "item": { Object },28 "request_id": "m8MDnv9okwxFNBV"29}
Check out the /auth/get
API reference documentation to see the full
Auth request and response schema.
Handling Link events
For a user who goes through the Automated Micro-deposit flow, the TRANSITION_VIEW (view_name = NUMBERS)
event will occur after SUBMIT_CREDENTIALS
, and in the onSuccess
callback the
verification_status
will be pending_automatic_verification
.
1OPEN (view_name = CONSENT)2TRANSITION_VIEW view_name = SELECT_INSTITUTION)3SEARCH_INSTITUTION4SELECT_INSTITUTION5TRANSITION_VIEW (view_name = CREDENTIAL)6SUBMIT_CREDENTIALS7TRANSITION_VIEW (view_name = LOADING)8TRANSITION_VIEW (view_name = MFA, mfa_type = code)9SUBMIT_MFA (mfa_type = code)10TRANSITION_VIEW (view_name = LOADING)11TRANSITION_VIEW (view_name = SELECT_ACCOUNT)12TRANSITION_VIEW (view_name = NUMBERS)13TRANSITION_VIEW (view_name = LOADING)14TRANSITION_VIEW (view_name = CONNECTED)15HANDOFF16onSuccess (verification_status: pending_automatic_verification)