Documentation

Overview

Introduction

Welcome to Plaid! Here you’ll find comprehensive information for integrating with Link and our API endpoints. We’ve tried to make this documentation user-friendly and example-filled, but if you have any questions, please head to our Help Center. If you’re planning to use our API in production, take a look at our privacy policy.

The fastest way to get your integration up and running is to use our quickstart guide, which walks through your entire Plaid integration step-by-step. You’ll integrate Plaid Link into your site or app and then use one of our client libraries to retrieve the data you need from our API.

Product Endpoint
Auth POST /auth/get
Transactions POST /transactions/get
Identity POST /identity/get
Income POST /income/get
Balance POST /accounts/balance/get

The Plaid API uses POST requests to communicate and HTTP response codes to indicate status and errors. All responses come in standard JSON. The Plaid API is served over HTTPS TLS v1.1+ to ensure data privacy; HTTP and HTTPS with TLS versions below 1.1 are not supported. All requests must include a content-type of application/json and the body must be valid JSON.

API Host

https://sandbox.plaid.com (Sandbox)
https://development.plaid.com (Development)
https://production.plaid.com (Production)

The Sandbox environment is unrestricted and supports only test Items. The Development environment supports up to 100 live Items. All testing should be done in our Sandbox and Development environments. All requests to Production will be billed. When you’re getting ready to launch into Production, please request Production API access via the Dashboard.

Product access endpoints:

/auth/get
/transactions/get
/income/get
/identity/get
/accounts/balance/get
/item/public_token/exchange
/item/public_token/create

Item management:

/accounts/get
/item/get
/item/webhook/update
/item/access_token/invalidate
/item/access_token/update_version
/item/delete

Institutions endpoints:

/institutions/get
/institutions/get_by_id
/institutions/search

Categories endpoints:

/categories/get

API keys and access

To gain access to the Plaid API, please create an account on our Dashboard. Once you’ve completed the signup process and acknowledged our terms, we’ll provide a live client_id, secret, and public_key on the Dashboard.

Glossary

  • Item: A set of credentials at a financial institution; each Item can have many Accounts, and some Accounts have Transactions associated with them
  • client_id and secret: two private API keys; used in conjunction with an access_token to access data for an Item
  • public_key: a public API identifier; used to initialize Link and identify Items you create or update via Link
  • access_token: A rotatable token unique to a single Item; used to access data for that Item
  • public_token: A short-lived token that can be exchanged for an access_token or used to initialize Link in update mode for an Item

Breaking changes

We strive to avoid making any breaking changes to our API, but we do make changes over time that may result in changes to the data that you pull from Plaid.

We consider the following changes to be backwards compatible:

  • Adding new API endpoints
  • Adding new options parameters to existing endpoints
  • Adding new data elements to existing response schemas
  • Adding new error_types and error_codes
  • Adding new webhook_types and webhook_codes
  • Changing the length or content of any API identifier

Storing API response data

It's important to store the access_token and item_id associated with an Item. Note that each of your users may have many Items. The access_token is used to access data for the Item (such as transactions) and to generate public_tokens for the Item for use with Link’s update mode. The item_id is included as the identifying property in all webhooks. You should securely store both of these values.

You may also store transaction and high-level account data.

All API responses and Link client-side callbacks include a unique request_id, even when an error occurs. We recommend persisting this value for internal logging purposes, as well as for support-related escalations. More information about how to access a request_id can be found in the Help Center.

Example Item

{
  "access_token": "access-sandbox-5c224a01-8314-4491-a06f-39e193d5cddc",
  "item": {
    "available_products": [
      "balance",
      "auth"
    ],
    "billed_products": [
      "identity",
      "transactions"
    ],
    "error": null,
    "institution_id": "ins_109508",
    "item_id": "Ed6bjNrDLJfGvZWwnkQlfxwoNz54B5C97ejBr",
    "webhook": "https://plaid.com/example/hook"
  },
  "request_id": "qpCtl"
}

Creating Items with Plaid Link

Plaid Link Auth Flow

Plaid Link is a drop-in module that provides a secure, elegant authentication flow for each institution that Plaid supports. Link makes it secure and easy for users to connect their bank accounts to Plaid.

Explore some sample apps, or tinker with the demo to see Link in action.

<button id="link-button">Link Account</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>
<script type="text/javascript">
(function($) {
  var handler = Plaid.create({
    clientName: 'Plaid Walkthrough Demo',
    env: 'sandbox',
    // Replace with your public_key from the Dashboard
    key: '[PUBLIC_KEY]',
    product: ['transactions'],
    // Optional, use webhooks to get transaction and error updates
    webhook: 'https://requestb.in',
    onLoad: function() {
      // Optional, called when Link loads
    },
    onSuccess: function(public_token, metadata) {
      // Send the public_token to your app server.
      // The metadata object contains info about the institution the
      // user selected and the account ID, if the Account Select view
      // is enabled.
      $.post('/get_access_token', {
        public_token: public_token,
      });
    },
    onExit: function(err, metadata) {
      // The user exited the Link flow.
      if (err != null) {
        // The user encountered a Plaid API error prior to exiting.
      }
      // metadata contains information about the institution
      // that the user selected and the most recent API request IDs.
      // Storing this information can be helpful for support.
    },
    onEvent: function(eventName, metadata) {
      // Optionally capture Link flow events, streamed through
      // this callback as your users connect an Item to Plaid.
      // For example:
      // eventName = "TRANSITION_VIEW"
      // metadata  = {
      //   link_session_id: "123-abc",
      //   mfa_type:        "questions",
      //   timestamp:       "2017-09-14T14:42:19.350Z",
      //   view_name:       "MFA",
      // }
    }
  });

  $('#link-button').on('click', function(e) {
    handler.open();
  });
})(jQuery);
</script>
npm install express body-parser plaid
node server.js
var bodyParser = require('body-parser');
var express = require('express');
var plaid = require('plaid');

// We store the access_token in memory - in production, store it in a secure
// persistent data store
var ACCESS_TOKEN = null;
var PUBLIC_TOKEN = null;

var client = new plaid.Client(
  '[PLAID_CLIENT_ID]',
  '[PLAID_SECRET]',
  '[PLAID_PUBLIC_KEY]',
  plaid.environments.sandbox
);

// Accept the public_token sent from Link
var app = express();
app.post('/get_access_token', function(request, response, next) {
  PUBLIC_TOKEN = request.body.public_token;
  client.exchangePublicToken(PUBLIC_TOKEN, function(error, tokenResponse) {
    if (error != null) {
      console.log('Could not exchange public_token!' + '\n' + error);
      return response.json({error: msg});
    }
    ACCESS_TOKEN = tokenResponse.access_token;
    ITEM_ID = tokenResponse.item_id;
    console.log('Access Token: ' + ACCESS_TOKEN);
    console.log('Item ID: ' + ITEM_ID);
    response.json({'error': false});
  });
});
app.listen(8000);
gem install sinatra plaid
ruby server.rb
require 'sinatra'
require 'plaid'

set :public_folder, File.dirname(__FILE__) + '/public'
set :port, 8000

client = Plaid::Client.new(env: :sandbox,
                           client_id: '[PLAID_CLIENT_ID]',
                           secret: '[PLAID_SECRET]',
                           public_key: '[PLAID_PUBLIC_KEY]')

access_token = nil

post '/get_access_token' do
  exchange_token_response = client.item.public_token.exchange(params['public_token'])
  access_token = exchange_token_response['access_token']
  item_id = exchange_token_response['item_id']
  puts "access token: #{access_token}"
  puts "item ID: #{item_id}"
  content_type :json
  exchange_token_response.to_json
end
pip install plaid-python flask
python server.py
import plaid
from flask import Flask
from flask import render_template
from flask import request
from flask import jsonify

app = Flask(__name__)

client = plaid.Client('[PLAID_CLIENT_ID]',
                      '[PLAID_SECRET]',
                      '[PLAID_PUBLIC_KEY]',
                      'sandbox')

access_token = None
public_token = None

@app.route("/get_access_token", methods=['POST'])
def get_access_token():
  global access_token
  public_token = request.form['public_token']
  exchange_response = client.Item.public_token.exchange(public_token)
  print 'access token: ' + exchange_response['access_token']
  print 'item ID: ' + exchange_response['item_id']

  return jsonify(exchange_response)

if __name__ == "__main__":
  app.run(port=8000)

See the parameter reference below for complete documentation on possible configurations.

Plaid.create accepts one argument, a configuration Object, and returns an Object with two functions, open and exit. Calling open will display the "Institution Select" view and calling exit will close Link.

Parameter reference

Parameter Description
clientName
required
Displayed once a user has successfully linked his or her Item.
product
required
A list of Plaid product(s) you wish to use. Valid products are : transactions, auth, and identity. Only institutions that support all requested products will be shown.

Example: ['auth', 'transactions']
key
required
The public_key associated with your account; available from the Dashboard.
env
required
The Plaid API environment on which to create user accounts. For development and testing, use sandbox or development. For production use, use production.

Note: all production requests are billed.
onSuccess
required
A function that is called when a user has successfully onboarded an Item. The function should expect two arguments, the public_token and a metadata object.
onExit
optional
A function that is called when a user has specifically exited the Link flow. The function should expect two arguments, a nullable error object and a metadata object. See onExit.
onEvent
optional
A function that is called when a user reaches certain points in the Link flow. The function should expect two arguments, an eventName string and a metadata object. See onEvent.
onLoad
optional
A function that is called when the Link module has finished loading. Calls to plaidLinkHandler.open() prior to the onLoad callback will be delayed until the module is fully loaded.
webhook
optional
Specify a webhook to associate with an Item. Plaid fires a webhook when the Item requires updated credentials or when new data is available.
token
optional
Specify a public_token to launch Link in update mode for a particular Item. This will cause Link to open directly to the authentication step for that Item's institution.

Use the POST /item/public_token/create endpoint to generate a public_token for an Item.
isWebview
optional
Set to true if launching Link within a WebView.

Note: The selectAccount Link initialization parameter has been deprecated and will be removed in a future release. Control whether or not your Link integration uses the Select Account view from the Dashboard.

onSuccess callback

The onSuccess callback should take two arguments, the public_token and a metadata object. The metadata object provides the following information:

Parameter Description
link_session_id
String
A unique identifier associated with a user's actions and events through the Link flow. Include this identifier when opening a support ticket for faster turnaround.
institution
Object
An Object with two properties:
- name: The full institution name, such as 'Bank of America'.
- institution_id: The institution ID, such as ins_100000.
accounts
[Object]
An list of objects with two properties:
- id: the account id selected
- name: the name of the selected account.

Enable the Select Account view to collect this data.

Note: If you are triggering the Select Account view via the deprecated selectAccount Link initialization flag, the onSuccess metadata key will be account rather than accounts.

onSuccess Example

Plaid.create({
  ...,
  onSuccess: function(public_token, metadata) {
    // public_token = "public-sandbox-5c224a01-8314-4491-a06f-39e193d5cddc"
    // metadata = {
    //  link_session_id: "123-abc",
    //  institution: {
    //    name: "Wells Fargo",
    //    institution_id: "ins_4"
    //  },
    //  accounts: [{
    //    id: "QPO8Jo8vdDHMepg41PBwckXm4KdK1yUdmXOwK".
    //    name: "Plaid Checking"
    //  }]
    // }

    // Send the public_token to an internal server
    // and exchange it for an access_token.
    fetch("/get_access_token", {
      method: "POST",
      body: {
        public_token: public_token,
        accounts: metadata.accounts,
        institution: metadata.institution,
        link_session_id: metadata.link_session_id,
      },
    });
  },
})

Metadata schema

{
  "link_session_id": String,
  "institution": {
    "name": String,
    "institution_id": String
  },
  "accounts": [
    {
      "id": String
      "name": String
    },
    ...
  ]
}

onExit callback

The onExit callback is called when a user exits the Link flow. It takes two arguments, a nullable error object and a metadata object.

Parameter Description
link_session_id
String
A unique identifier associated with a user's actions and events through the Link flow. Include this identifier when opening a support ticket for faster turnaround.
error
Object
A nullable object that contains the error type, code, and message of the error that was last encountered by the user. If no error was encountered, error will be null.
metadata
Object
An object containing information about the user's Link session, institution selected by the user, and Plaid API request IDs.

If an error didn't occur, the error argument will be null. The metadata parameter is always present, though some values may be null.

Metadata status

The value of the status key indicates the point at which the user exited the Link flow. status may be one of the following values:

Status Description
requires_questions User prompted to answer security question(s)
requires_selections User prompted to answer multiple choice question(s)
requires_code User prompted to provide a one-time passcode
choose_device User prompted to select a device on which to receive a one-time passcode
requires_credentials User prompted to provide credentials for the selected financial institution or has not yet selected a financial institution
institution_not_found User exited the Link flow after unsuccessfully (no results returned) searching for a financial institution

The arguments in the onExit function are meant to help you guide your users after they have exited Link. We recommend storing the error and metadata information server-side in a way that can be associated with the user. You’ll also need to include this and any other relevant info in Plaid Support requests for the user.

onExit Example

Plaid.create({
  ...,
  onExit: function(error, metadata) {
    // error = {
    //  display_message: "The credentials were ...",
    //  error_code: "INVALID_CREDENTIALS",
    //  error_message: "the credentials were ...",
    //  error_type: "ITEM_ERROR",
    // }
    // metadata = {
    //  link_session_id: "dc21685c-192e-4969-b4e9-bab890daae31",
    //  institution: {
    //   name: "Wells Fargo",
    //   institution_id: "ins_4"
    //  },
    //  status: "requires_credentials"
    // }

    // Save data from the onExit handler
    supportHandler.report({
      error: error,
      institution: metadata.institution,
      link_session_id: metadata.link_session_id,
      status: metadata.status,
    });
  },
})

Error Object schema

{
  "display_message": String,
  "error_code": String,
  "error_message": String,
  "error_type": String
}

Metadata schema

{
  "link_session_id": String,
  "institution": {
    "name": String,
    "institution_id": String
  },
  "status": String
}

onEvent callback

The onEvent callback is called at certain points in the Link flow. It takes two arguments, an eventName string and a metadata object.

Parameter Description
eventName
String
A string representing the event that has just occurred in the Link flow.
metadata
Object
An object containing information about the event.

The metadata parameter is always present, though some values may be null. Please note that new event names, metadata keys, or view names may be added without notice.

Event names

Event Description
ERROR A recoverable error occurred in the Link flow, see the error_code metadata.
EXIT The user has exited without completing the Link flow and the onExit callback is fired.
HANDOFF The user has completed the Link flow and the onSuccess callback is fired.
OPEN The user has opened Link.
SEARCH_INSTITUTION The user has searched for an institution.
SELECT_INSTITUTION The user selected an institution.
TRANSITION_VIEW The TRANSITION_VIEW event indicates that the user has moved from one view to the next.

Metadata Reference

Field Description
error_code The error code that the user encountered. Emitted by: ERROR, EXIT.
error_message The error message that the user encountered. Emitted by: ERROR, EXIT.
error_type The error type that the user encountered. Emitted by: ERROR, EXIT.
exit_status The status key indicates the point at which the user exited the Link flow. Emitted by: EXIT.
institution_id The ID of the selected institution. Emitted by: SELECT_INSTITUTION, OPEN.
institution_name The name of the selected institution. Emitted by SELECT_INSTITUTION, OPEN.
institution_search_query The query used to search for institutions. Emitted by: SEARCH_INSTITUTION.
request_id The request ID for the last request made by Link. This can be shared with Plaid Support to expedite investigation. Emitted by all events.
link_session_id The link_session_id is a unique identifier for a single session of Link. It's always available and will stay constant throughout the flow. Emitted by all events.
mfa_type If set, the user has encountered one of the following MFA types: code, device, questions, selections. Emitted by: TRANSITION_VIEW when view_name is MFA.
view_name The name of the view that is being transitioned to. Emitted by TRANSITION_VIEW.
timestamp An ISO 8601 representation of when the event occurred. For example 2017-09-14T14:42:19.350Z. Emitted by all events.

Metadata view_name

View Displayed when
CONNECTED The user has connected their account.
CREDENTIAL Asking the user for their account credentials.
ERROR An error has occurred.
EXIT Confirming if the user wishes to close Link.
LOADING Link is making a request to our servers.
MFA The user is asked by the institution for additional MFA authentication.
SELECT_ACCOUNT We ask the user to choose an account.
SELECT_INSTITUTION We ask the user to choose their institution.

onEvent Example

Plaid.create({
  ...,
  onEvent: function(eventName, metadata) {
    // eventName = "TRANSITION_VIEW"
    // metadata  = {
    //   link_session_id: "1dc21685c-192e-4969-b4e9-bab890daae31",
    //   mfa_type:        "questions",
    //   timestamp:       "2017-09-14T14:42:19.350Z",
    //   view_name:       "MFA",
    // }
    // send the event and data to your own analytics service
    analytics.send(eventName, metadata);
  },
})

EventNames Enum

enum (
  "ERROR"
  "EXIT"
  "HANDOFF"
  "OPEN"
  "SEARCH_INSTITUTION"
  "SELECT_INSTITUTION"
  "TRANSITION_VIEW"
)

Metadata schema

{
  "error_code": String,
  "error_message": String,
  "error_type": String,
  "exit_status": String,
  "institution_id": String,
  "institution_name": String,
  "institution_search_query": String,
  "link_session_id": String,
  "mfa_type": String,
  "request_id": String,
  "timestamp": String,
  "view_name": String
}

open() function

Calling open will display the "Institution Select" view to your user, starting the Link flow. Once open is called, you will begin receiving events via the onEvent callback.

Open to the Select Institution view

Open Link to the Select Institution view Link will handle the whole flow for connecting your users' bank

// Configure link
var linkHandler = Plaid.create(...)

// Open Link
linkHandler.open();

exit() function

The exit function allows you to programmatically close Link. Calling exit will trigger either the onExit or onSuccess callbacks.

The exit function takes a single, optional argument, a configuration Object. The configuration options are:

Option Description
force
Boolean
If true, Link will exit immediately. If false, or the option is not provided, an exit confirmation screen may be presented to the user.

exit() works on desktop and mobile but isn’t supported for WebView integrations. To exit Link in a WebView, you must programmatically close the iOS or Android WebView.

.exit() example

// Initialize Link
var linkHandler = Plaid.create(...)

// Force exit - Link exits immediately
linkHandler.exit({ force: true })

// Graceful exit - Link may display a confirmation screen
// depending on how far the user is in the flow
linkHandler.exit()

// This is equivalent to the above:
linkHandler.exit({ force: false })

Exchange Token flow

Exchange a Link public_token for an API access_token. Link hands off the public_token client-side via the onSuccess callback once a user has successfully created an Item. The public_token is ephemeral and expires after 30 minutes. A public_token becomes invalidated once it has been successfully exchanged for an access_token.

The response also includes an item_id that should be stored with the access_token. The item_id is used to identify an Item in a webhook. The item_id can also be retrieved by making an /item/get request.

Field Required?
client_id
String
yes
secret
String
yes
public_token
String
yes

Exchange Token

POST /item/public_token/exchange

Exchange token request

curl -X POST https://sandbox.plaid.com/item/public_token/exchange \
  -H 'content-type: application/json' \
  -d '{
    "client_id": String,
    "secret": String,
    "public_token": "public-sandbox-5c224a01-8314-4491-a06f-39e193d5cddc"
  }'
plaidClient.exchangePublicToken(public_token, function(err, apiResponse) {
  var accessToken = apiResponse.access_token;
  var itemId = apiResponse.item_id;
});
response = client.item.public_token.exchange(public_token)
access_token = response['access_token']
item_id = response['item_id']
response = client.Item.public_token.exchange(public_token)
access_token = response['access_token']
item_id = response['item_id']
Response<ItemPublicTokenExchangeResponse> response =
  client()
  .service()
  .itemPublicTokenExchange(new ItemPublicTokenExchangeRequest(publicToken))
  .execute();
String accessToken = response.body().getAccessToken();

Exchange Token response

http code 200
{
  "access_token": "access-sandbox-de3ce8ef-33f8-452c-a685-8671031fc0f6",
  "item_id": "M5eVJqLnv3tbzdngLDp9FL5OlDNxlNhlE55op",
  "request_id": "Aim3b"
}

Creating Public Tokens

A public_token is one-time use and expires after 30 minutes. You use a public_token to initialize Link in update mode for a particular Item.

If you need your user to take action to restore or resolve an error associated with an Item, generate a public token with the POST /item/public_token/create endpoint and then initialize Link with that public_token.

You can generate a public_token for an Item even if you did not use Link to create the Item originally.

Field Required?
client_id
String
yes
secret
String
yes
access_token
String
yes

Create Public Token

POST /item/public_token/create

Create Public Token request

curl -X POST https://sandbox.plaid.com/item/public_token/create \
  -H 'content-type: application/json' \
  -d '{
    "client_id": String,
    "secret": String,
    "access_token": "access-sandbox-de3ce8ef-33f8-452c-a685-8671031fc0f6"
  }'
# create a public_token for use with Plaid Link's update mode
response = client.item.public_token.create(access_token)
# use the generated public_token to initialize Plaid Link in update
# mode for a user's Item so that they can provide updated credentials
# or MFA information
public_token = response['public_token']
# create a public_token for use with Plaid Link's update mode
create_response = client.Item.public_token.create(access_token)
# use the generated public_token to initialize Plaid Link in update
# mode for a user's Item so that they can provide updated credentials
# or MFA information
public_token = response['public_token']
// Create a public_token for use with Plaid Link's update mode
client.createPublicToken(ACCESS_TOKEN, (err, result) => {
  // Handle err
  // Use the generated public_token to initialize Plaid Link in update
  // mode for a user's Item so that they can provide updated credentials
  // or MFA information
  const publicToken = result.public_token;
});
// Create a public_token for use with Plaid Link's update mode
Response<ItemPublicTokenCreateResponse> response =
  client().service().itemPublicTokenCreate(
   new ItemPublicTokenCreateRequest("ACCESS_TOKEN")).execute();
String publicToken;
if (response.isSuccessful()) {
  // Use the generated public_token to initialize Plaid Link in update
  // mode for a user's Item so that they can provide updated credentials
  // or MFA information
  publicToken = response.body().getPublicToken();
}

Create Public Token response

http code 200
{
  "public_token": "public-sandbox-b0e2c4ee-a763-4df5-bfe9-46a46bce993d",
  "request_id": "Aim3b"
}

Over time, Items may need to refresh authentication information. This can happen if the user changes a password, if MFA requirements change, or if the login becomes locked. Link’s update mode makes the reauthentication process secure and painless.

To use update mode for an Item, initialize Link with a public_token for the Item that you wish to update. Link auto-detects the appropriate institution and handles the credential and multi-factor authentication process, if needed.

An Items access_token does not change when using Link in update mode, so there is no need to repeat the exchange token process.

<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js">
</script>
<script>
// Initialize Link with the `token` parameter
// set to the generated public_token for the Item
var linkHandler = Plaid.create({
  env: 'sandbox',
  clientName: 'Client Name',
  key: '[PUBLIC_KEY]',
  product: ['transactions'],
  token: '[GENERATED_PUBLIC_TOKEN]',
  onSuccess: function(public_token, metadata) {
    // You do not need to repeat the /item/public_token/exchange
    // process when a user uses Link in update mode.
    // The Item's access_token has not changed.
  },
  onExit: function(err, metadata) {
    // The user exited the Link flow.
    if (err != null) {
      // The user encountered a Plaid API error prior
      // to exiting.
    }
    // metadata contains information about the institution
    // that the user selected and the most recent API request
    // IDs. Storing this information is helpful for support.
  },
});
// Trigger the authentication view
document.getElementById('linkButton').onclick = function() {
  // Link will automatically detect the institution ID
  // associated with the public token and present the
  // credential view to your user.
  linkHandler.open();
};
</script>

Link will automatically detect the institution ID associated with the public_token and present the appropriate credential view to your user.

iOS bindings

Plaid Link WebView example

Link iOS is a native SDK for iOS 8+ that bring the same features and functionality that exist with Link on the web to iOS. Best of all, Link iOS requires zero changes to your backend integration.

Looking to get started right away?
Jump to the iOS examples for complete sample apps in Objective-C, Swift and Swift 2. At the center of it all lies LinkKit.framework an embeddable framework managing the details of linking an account with Plaid.
Check out example apps ▸

WebView integration

Plaid Link WebView example

Link is optimized to work within WebViews, including on iOS and Android. The Link initialization URL that’s optimized for WebViews is:

https://cdn.plaid.com/link/v2/stable/link.html

The Link configuration options for a WebView integration are passed via querystring rather than via a client-side Javascript call. See the parameter reference for complete documentation. Read on for example WebView initialization URls for common Link use cases.

Looking to get started right away?
Jump to the WebView examples for sample apps for iOS WKWebView and Android WebView! The sample code includes examples to initialize Link and process events communicated from Link to your app.
Check out example apps ▸

Communication between the WebView and your app is handled by HTTP redirects rather than client-side JavaScript callbacks. These redirects should be intercepted by your app. The example apps include sample code to do this.

All redirect URLs have the scheme plaidlink. The event type is communicated via the URL host and data is passed via the querystring. There are two supported events, connected and exit, which are documented below.

connected event

The connected event is analogous to the onSuccess callback and is sent when the user completes the Link flow. The following information is available from the querystring:

Field Description
public_token Link public_token that is exchanged for an API access_token
accounts JSON-stringified representation of the account(s) selected by the user in the shape of [Object].

Enable the Select Account view to collect this data.
institution_id The institution ID, such as 'ins_100000'
institution_name The full institution name, such as 'Bank of America'

Note: If you are using the deprecated selectAccount Link initialization flag, account information will be available via the account_id and account_name keys:

plaidlink://connected
  ?public_token=public-sandbox-fb7cca4a-82e6-4707
  &account_id=QPO8Jo8vdDHMepg41PBwckXm4KdK1yUdmXOwK
  &account_name=Plaid%20Savings
  &institution_id=ins_3
  &institution_name=Chase

exit event

The exit event is analogous to the onExit callback and is sent when the user exits the Link flow. The following information is available from the querystring:

Field Description
status The user’s status in the Link flow when they exited. See the possible values
error_code The error code that the user encountered
error_message The error message that the user encountered
institution_id The institution ID, such as 'ins_100000'
institution_name The full institution name, such as 'Bank of America'
link_session_id A unique identifier for a single session of Link. It's always available and will stay constant throughout the flow

WebView examples

To get your Link WebView integration started, check out our example apps, available for iOS and Android.

Each example app is runnable (on both simulators and devices) and includes code to initialize Link and process events sent from Link to your app via HTTP redirects.

https://cdn.plaid.com/link/v2/stable/link.html
  ?isWebview=true
  &key=[PUBLIC_KEY]
  &env=sandbox
  &product=transactions,auth
  &clientName=Plaid%20Demo
https://cdn.plaid.com/link/v2/stable/link.html
  ?isWebview=true
  &key=[PUBLIC_KEY]
  ...
  &token=[GENERATED_PUBLIC_TOKEN]
plaidlink://connected
 ?public_token=public-sandbox-fb7cca4a-82e6-4707
 &accounts='[{"name":"Plaid Savings","id":"QPO8Jo8vdDHMepg41PBwckXm4KdK1yUdmXOwK"}]'
 &institution_id=ins_3
 &institution_name=Chase
plaidlink://exit
  ?status=requires_credentials
  &error_code=ITEM_LOGIN_REQUIRED
  &error_display_message=The%20provided%20credentials%20were%20not%20correct.%20Please%20try%20again.
  &error_message=the%20provided%20credentials%20were%20not%20correct
  &error_type=ITEM_ERROR
  &institution_id=ins_3
  &institution_name=Chase
  &request_id=2ZPIa

Browser support

Desktop

Mobile

Modern mobile browsers are supported, including most iPhone and Android devices. If you encounter any inconsistencies, head to the Help Center.





Item product access

Auth

The /auth/get endpoint allows you to retrieve the bank account and routing numbers associated with an Item’s checking and savings accounts, along with high-level account data and balances.

The Auth product performs two crucial functions. It translates bank access credentials (username and password) into an account and routing number. No input of account or routing number is necessary. It also validates the owner of this account number in a NACHA-compliant manner. This eliminates the need for micro-deposits or any other secondary authentication.

Note: This request may take some time to complete if auth was not specified as an initial product when creating the Item. This is because Plaid must communicate directly with the institution to retrieve the data.

Field Required?
client_id
String
yes
secret
String
yes
access_token
String
yes
options
Object
no
Field Default Description
account_ids
[String]
null A list of account_ids to retrieve for the Item.

Note: An error will be returned if a provided account_id is not associated with the Item.

Retrieve Auth

POST /auth/get

Retrieve Auth Request

curl -X POST https://sandbox.plaid.com/auth/get \
-H 'content-type: application/json' \
-d '{
  "client_id": String,
  "secret": String,
  "access_token": String
}'
# Use Auth and pull account and routing numbers for an Item
response = @client.Auth.get(@access_token)
numbers = response['numbers']
# Use Auth and pull account and routing numbers for an Item
response = client.Auth.get(access_token)
numbers = response['numbers']
// Use Auth and pull account and routing numbers for an Item
client.getAuth(accessToken, {}, (err, results) => {
  // Handle err
  // Pull account and routing numbers for depository accounts
  const accountData = results.accounts;
  const accountAndRoutingNumbers = results.numbers;
});
// Use Auth and pull account and routing numbers for an Item
Response<AuthGetResponse> response =
  client().service().authGet(new AuthGetRequest("ACCESS_TOKEN")).execute();
for (AuthGetResponse.Numbers auth : response.body().getAuth()) { ... }

Retrieve Auth Response

http code 200
{
  "accounts": [{
    "account_id": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D",
    "balances": {
      "available": 100,
      "current": 110,
      "limit": null
    },
    "mask": "0000",
    "name": "Plaid Checking",
    "official_name": "Plaid Gold Checking",
    "subtype": "checking",
    "type": "depository"
  }],
  "numbers": [{
    "account": "9900009606",
    "account_id": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D",
    "routing": "011401533",
    "wire_routing": "021000021"
   }],
  "item": {Object},
  "request_id": "45QSn"
}

Transactions

The /transactions/get endpoint allows developers to receive user-authorized transaction data for credit and depository-type Accounts. Transaction data is standardized across financial institutions, and in many cases transactions are linked to a clean name, entity type, location, and category. Similarly, account data is standardized and returned with a clean name, number, balance, and other meta information where available.

Transaction data elements

Key Description
transaction_id
String
The unique id of the transaction.
account_id
String
The id of the account in which this transaction occurred.
category
[String]
A hierarchical array of the categories to which this transaction belongs. See Categories.
category_id
String
The id of the category to which this transaction belongs. See Categories.
transaction_type
String
Place, Digital, Special, or Unresolved.
amount
Number
The settled dollar value. Positive values when money moves out of the account; negative values when money moves in. For example, purchases are positive; credit card payments, direct deposits, refunds are negative.
date
String
For pending transactions, Plaid returns the date the transaction occurred; for posted transactions, Plaid returns the date the transaction posts. Both dates are returned in an ISO 8601 format (YYYY-MM-DD).
location and payment_meta
Object, Object
See location and payment data.
pending
Boolean
When true, identifies the transaction as pending or unsettled. Pending transaction details (name, type, amount) may change before they are settled.
pending_transaction_id
String, nullable
The id of a posted transaction's associated pending transaction—where applicable.
account_owner
String
The name of the account owner. This field is not typically populated and only relevant when dealing with sub-accounts.

Transaction location and payment data

Key Description
location Detailed merchant location data including address, city, state, zip, lat (latitude), and lon (longitude) where available.
payment Detailed payment and payment processor data including reference_number, ppd_id, and payee_name where available.

Retrieve Transactions

POST /transactions/get

Retrieve Transactions Request

curl -X POST https://sandbox.plaid.com/transactions/get \
-H 'content-type: application/json' \
-d '{
  "client_id": String,
  "secret": String,
  "access_token": String,
  "start_date": "2017-01-01",
  "end_date": "2017-02-01",
  "options": {
    "count": 250,
    "offset": 100
  }
}'
# Pull transactions by date and filter by an account ID
response = @client.transactions.get(@access_token,
                                    '2017-01-01',
                                    '2017-01-01',
                                    account_ids: [account_id])
# Manipulate the `count` and `offset parameters to paginate transactions
# and retrieve all available data
response = @client.transactions.get(@access_token,
                                    '2016-01-01',
                                    '2017-01-01',
                                    count: 250,
                                    offset: 0)
total_transactions = response['total_transactions']
// Retrieve transactions from Jan 1 until Feb 15
// NOTE: This endpoint may return a `PRODUCT_NOT_READY` error if transactions
// are not yet processed for the Item.
client.getTransactions(accessToken, '2017-01-01', '2017-02-15', {
  count: 250,
  offset: 0,
}, (err, result) => {
  // Handle err
  const transactions = result.transactions;
});
response = client.Transactions.get(access_token, start_date='2016-07-12', end_date='2017-01-09')
transactions = response['transactions']

# the transactions in the response are paginated, so make multiple calls while increasing the offset to
# retrieve all transactions
while len(transactions) < response['total_transactions']:
    response = client.Transactions.get(access_token, start_date='2016-07-12', end_date='2017-01-09',
                                       offset=len(transactions)
                                      )
    transactions.extend(response['transactions'])
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
startDate = simpleDateFormat.parse("2017-01-01");
endDate = simpleDateFormat.parse("2017-02-01");

Response<TransactionsGetResponse> response = client().service().transactionsGet(
  new TransactionsGetRequest(
    "ACCESS_TOKEN",
    startDate,
    endDate))
  .execute();

Response<TransactionsGetResponse> response = client().service().transactionsGet(
  new TransactionsGetRequest(
    accessToken,
    startDate,
    endDate)
    .withAccountIds(Arrays.asList(someAccountId))
    .withCount(numTxns)
    .withOffset(1)).execute();

for (TransactionsGetResponse.Transaction txn : response.body().getTransactions()) { ... }

Retrieve Transactions Response

http code 200
{
 "accounts": [{object}],
 "transactions": [{
    "account_id": "vokyE5Rn6vHKqDLRXEn5fne7LwbKPLIXGK98d",
    "amount": 2307.21,
    "category": [
      "Shops",
      "Computers and Electronics"
    ],
    "category_id": "19013000",
    "date": "2017-01-29",
    "location": {
     "address": "300 Post St",
     "city": "San Francisco",
     "state": "CA",
     "zip": "94108",
     "lat": null,
     "lon": null
    },
    "name": "Apple Store",
    "payment_meta": Object,
    "pending": false,
    "pending_transaction_id": null,
    "account_owner": null,
    "transaction_id": "lPNjeW1nR6CDn5okmGQ6hEpMo4lLNoSrzqDje",
    "transaction_type": "place"
   }, {
    "account_id": "XA96y1wW3xS7wKyEdbRzFkpZov6x1ohxMXwep",
    "amount": 78.5,
    "category": [
      "Food and Drink",
      "Restaurants"
    ],
    "category_id": "13005000",
    "date": "2017-01-29",
    "location": {
      "address": "262 W 15th St",
      "city": "New York",
      "state": "NY",
      "zip": "10011",
      "lat": 40.740352,
      "lon": -74.001761
    },
    "name": "Golden Crepes",
    "payment_meta": Object,
    "pending": false,
    "pending_transaction_id": null,
    "account_owner": null,
    "transaction_id": "4WPD9vV5A1cogJwyQ5kVFB3vPEmpXPS3qvjXQ",
    "transaction_type": "place"
  }],
  "item": {Object},
  "total_transactions": Number,
  "request_id": "45QSn"
}

Transactions request

To retrieve transaction data for an Item, use the /transactions/get endpoint.

Due to the potentially large number of transactions associated with an Item, results are paginated. Manipulate the count and offset parameters in conjunction with the total_transactions response body field to fetch all available Transactions.

Field Description
client_id
String
secret
String
access_token
String
start_date
Date
Dates should be formatted as YYYY-MM-DD
end_date
Date
Dates should be formatted as YYYY-MM-DD
options
Object, optional
If provided, must be non-null.
Field Default Description
account_ids
[String]
null A list of account_ids to retrieve for the Item.

Note: An error will be returned if a provided account_id is not associated with the Item
count
Number
100 The number of transactions to fetch, where 0 < count <= 500.
offset
Number
0 The number of transactions to skip, where offset >= 0.

Item transaction lifecyle

After an Item is added, Plaid begins a process to collect, parse, and clean all of the Item's most recent transactions over the next 30-240 seconds. If a webhook is provided, you’ll get a notification as soon as that process is complete. After that, we’ll update the Item’s data at set intervals throughout the day to collect all of the most recent transactions. An Item’s account and transaction data may be retrieved at any time from our /transactions/get endpoint.

Transactions are pulled as they are posted to the issuing institution. Dependent on the merchant acquirer, processor, gateway and issuer, the time from when a transaction occurs to when it's posted can take from a few minutes to a few days. The date listed in transaction will be as close to the original transaction date as possible.

Full History Update

Within five minutes of when we finish the initial Item transaction pull, we will pull all the available transactional history for the Item.

We work hard to provide as much historical data as possible; however, there are limiting factors in the amount of information an institution holds and the length of time a user has had an account. To see more information on data availability by institution, please visit our Help Center.

Identity

The Identity endpoint allows you to retrieve various account holder information on file with the financial institution, including names, emails, phone numbers, and addresses.

Note: This request may take some time to complete if identity was not specified as an initial product when creating the Item. This is because Plaid must communicate directly with the institution to retrieve the data.

Field Required?
client_id
String
yes
secret
String
yes
access_token
String
yes

Retrieve Identity

POST /identity/get

Retrieve Identity

curl -X POST https://sandbox.plaid.com/identity/get \
-H 'content-type: application/json' \
-d '{
  "client_id": String,
  "secret": String,
  "access_token": String
}'
# Pull identity data for an item
response = @client.identity.get(@access_token)
# Pull identity data for an item
response = client.Identity.get(access_token)
identity = response['identity']
// Retrieve Identity data for an Item
client.getIdentity(accessToken, function(err, result) {
  // Handle err
  const info = result.info;
});
// Retrieve Identity data for an Item
Response<IdentityGetResponse> response = client().service().identityGet(
  new IdentityGetRequest("ACCESS_TOKEN")
).execute();
IdentityGetResponse.Identity info = response.body().getIdentity();

Retrieve Identity Response

http code 200
{
  "accounts": [{object}],
  "identity": {
    "addresses": [
      {
        "accounts": [
          "Plaid Checking 0000",
          "Plaid Saving 1111",
          "Plaid CD 2222"
        ],
        "data": {
          "city": "Malakoff",
          "state": "NY",
          "street": "2992 Cameron Road",
          "zip": "14236"
        },
        "primary": true
      },
      {
        "accounts": [
          "Plaid Credit Card 3333"
        ],
        "data": {
          "city": "San Matias",
          "state": "CA",
          "street": "2493 Leisure Lane",
          "zip": "93405-2255"
        },
        "primary": false
      }
    ],
    "emails": [
      {
        "data": "accountholder0@example.com",
        "primary": true,
        "type": "primary"
      }
    ],
    "names": [
      "Alberta Bobbeth Charleson"
    ],
    "phone_numbers": [{
      "primary": true,
      "type": "home",
      "data": "4673956022"
    }],
  },
  "item": {object},
  "request_id": "dd4K4"
}

Income

The Income endpoint allows you to retrieve information pertaining to a Item’s income. In addition to the annual income, detailed information will be provided for each contributing income stream (or job). Details on each of these fields can be found below.

Field Required?
client_id
String
yes
secret
String
yes
access_token
String
yes

Income data elements

Key Description
last_year_income
Number
The sum of the Item’s income over the past 365 days. If we have less than 365 days of data this will be less than a full year's income.
last_year_income_before_tax
Number
last_year_income interpolated to value before taxes. This is the minimum pre-tax salary that assumes a filing status of single with zero dependents.
projected_yearly_income
Number
Item’s income extrapolated over a year based on current, active income streams. Income streams become inactive if they have not recurred for more than two cycles. For example, if a weekly paycheck hasn’t been seen for the past two weeks, it's no longer active.
projected_yearly_income_before_tax
Number
projected_yearly_income interpolated to value before taxes. This is the minimum pre-tax salary that assumes a filing status of single with zero dependents.
income_streams
[Object]
An array of income streams with detailed information on each. See income streams.
max_number_of_overlapping_income_streams
Number
Max number of income streams present at the same time over the past 365 days.
number_of_income_streams
Number
Total number of distinct income streams received over the past 365 days.

Income streams:

Key Description
monthly_income
Number
The monthly income associated with the income stream
confidence
Number
A numeric representation of our confidence in the income data associated with this particular income stream, with 0 being the lowest confidence and 1 being the highest
days
Number
Extent of data found for this income stream
name
String
Name of the entity associated with this income stream

Retrieve Income

 POST /income/get

Retrieve Income request

curl -X POST https://sandbox.plaid.com/income/get \
-H 'content-type: application/json' \
-d '{
  "client_id": String,
  "secret": String,
  "access_token": String
}'
# retrieve Income data for an Item
income_response = client.income.get(access_token)
# retrieve Income data for an Item
income_response = client.Income.get(access_token)
// Retrieve Income data for an Item
client.getIncome(accessToken, function(err, result) {
  // Handle err
  var income = result.income;
});
// Retrieve Income data for an Item
Response<IncomeGetResponse> response =
  client().service().incomeGet(new IncomeGetRequest(ACCESS_TOKEN)).execute();
Income income = response.getIncome();
List<IncomeStreams> incomeStreams = income.getIncomeStreams();

Retrieve Income response

http code 200
{
  "item": {Object},
  "income": {
    "income_streams": [
      {
        "confidence": 1,
        "days": 518,
        "monthly_income": 1601,
        "name": "PLAID"
      },
      {
        "confidence": 0.95,
        "days": 415,
        "monthly_income": 1530,
        "name": "BAGUETTES INC"
      }
    ],
    "last_year_income": 28072,
    "last_year_income_before_tax": 38681,
    "projected_yearly_income": 19444,
    "projected_yearly_income_before_tax": 26291,
    "max_number_of_overlapping_income_streams": 2,
    "number_of_income_streams": 2
  },
  "request_id": "x9a1xa"
}

Balance

The POST /accounts/balance/get endpoint returns the real-time balance for each of an Item’s accounts. It can be used for existing Items that were added via any of Plaid’s other products.

The current balance is the total amount of funds in the account. The available balance is the current balance less any outstanding holds or debits that have not yet posted to the account.

Note that not all institutions calculate the available balance. In the event that available balance is unavailable from the institution, Plaid will return an available balance value of null.

Field Required?
client_id
String
yes
secret
String
yes
access_token
String
yes
options
Object
no

The following options are available:

Field Default Description
account_ids
[String]
null A list of account_ids to retrieve for the Item.

Note: An error will be returned if a provided account_id is not associated with the Item.

Retrieve Balance

POST /accounts/balance/get

Retrieve Balance Request

curl -X POST https://sandbox.plaid.com/accounts/balance/get \
-H 'content-type: application/json' \
-d '{
  "client_id": String,
  "secret": String,
  "access_token": String
  "options": {
    "account_ids": [String],
  }
}'
# Pull real-time balance information for each
# account associated with the Item
response = @client.accounts.balance.get(@access_token)
# Pull real-time balance information for each
# account associated with the Item
response = client.Accounts.balance.get(access_token)
// Each account has up-to-date balance information associated with it
accounts = response['accounts']
// Pull real-time balance information for each account associated with the Item
client.getBalance(ACCESS_TOKEN, (err, result) => {
  // Handle err
  // Each account has up-to-date balance information associated with it
  const item = result.accounts;
});
Response<AccountsBalanceGetResponse> response = client().service().accountsBalanceGet(
  new AccountsBalanceGetRequest("ACCESS_TOKEN"))
  .execute();
List<Account> accounts = response.body().getAccounts();

Retrieve Balance Response

http code 200
{
  "accounts": [{
     "account_id": "QKKzevvp33HxPWpoqn6rI13BxW4awNSjnw4xv",
     "balances": {
       "available": 100,
       "current": 110,
       "limit": null
     },
     "mask": "0000",
     "name": "Plaid Checking",
     "official_name": "Plaid Gold Checking",
     "subtype": "checking",
     "type": "depository"
  }],
  "item": {object},
  "request_id": "1zlMf"
}

Item management

Accounts

Account data elements

Key Description
account_id
String
The unique ID of the account.

Note: In some instances, account IDs may change.
item_id
String
The unique ID of the Item.
institution_id
String
The financial institution associated with the Account. See financial institutions.
balances
Object
The current balance is the total amount of funds in the account. The available balance is the current balance less any outstanding holds or debits that have not yet posted to the account.

Note: Not all institutions calculate the available balance. In the event that available balance is unavailable from the institution, Plaid will return an available balance value of null.
name
String
The name of the Account, either assigned by the user or the financial institution itself.
mask
String
The last four digits of the Account's number.
official_name
String
The official name of the Account as given by the financial institution.
type
String
See account types below.
subtype
String
See account subtypes below.

Retrieve Accounts

POST /accounts/get

Retrieve Accounts Request

curl -X POST https://sandbox.plaid.com/accounts/get \
-H 'content-type: application/json' \
-d '{
  "client_id": String,
  "secret": String,
  "access_token": String
}'
# Pull the accounts associated with the Item
response = @client.accounts.get(@access_token)
# Pull the accounts associated with the Item
# associated with the Item is available
response = client.Accounts.get(access_token)
accounts = response['accounts']
// Pull the accounts associated with the Item
client.getAccounts(ACCESS_TOKEN, (err, result) => {
  // Handle err
  // High-level information about each account associated with the Item is available
  const accounts = result.accounts;
});
// Pull the accounts associated with the Item
Response<AccountsGetResponse> response = client().service().accountsGet(
  new AccountsGetRequest("ACCESS_TOKEN"))
  .execute();
List<Account> accounts = response.body().getAccounts();

Retrieve Accounts Response

http code 200
{
  "accounts": [{
    "account_id": "vzeNDwK7KQIm4yEog683uElbp9GRLEFXGK98D",
    "balances": {
      "available": 100,
      "current": 110,
      "limit": null
    },
    "mask": "0000",
    "name": "Plaid Checking",
    "official_name": "Plaid Gold Checking",
    "subtype": "checking",
    "type": "depository"
  }, {
    "account_id": "6Myq63K1KDSe3lBwp7K1fnEbNGLV4nSxalVdW",
    "balances": {
      "available": null,
      "current": 410,
      "limit": 2000
    },
    "mask": "3333",
    "name": "Plaid Credit Card",
    "official_name": "Plaid Diamond Credit Card",
    "subtype": "credit card",
    "type": "credit"
  }],
  "item": {Object},
  "request_id": "45QSn"
}

Retrieve Item

The POST /item/get endpoint returns information about the status of an Item:

  • Available products
  • Billed products
  • Error status
  • Institution ID (institution_id)
  • Item ID (item_id)
  • Webhook
Field Required?
client_id
String
yes
secret
String
yes
access_token
String
yes

Retrieve Item

POST /item/get

Retrieve Item Request

curl -X POST https://sandbox.plaid.com/item/get \
  -H 'content-type: application/json' \
  -d '{
    "client_id": String,
    "secret": String,
    "access_token": String
  }'
# Pull information about the Item
response = client.item.get(access_token)
item = response['item']
# Pull information about the Item
response = client.Item.get(access_token)
item = response['item']
// Pull information about the Item
client.getItem(ACCESS_TOKEN, (err, result) => {
  // Handle err
  // The Item has a list of available products, billed products, error status,
  // webhook information, and more.
  const item = result.item;
});
// Pull information about the Item
Response<ItemGetResponse> response =
  client().service().itemGet(new ItemGetRequest("ACCESS_TOKEN")).execute();
// The Item has a list of available products, billed products, error status,
// webhook information, and more.
Item item = response.body().getItem();

Retrieve Item Response

http code 200
{
  "item": {
    "available_products": [
      "balance",
      "auth"
    ],
    "billed_products": [
      "identity",
      "transactions"
    ],
    "error": null,
    "institution_id": "ins_109508",
    "item_id": "Ed6bjNrDLJfGvZWwnkQlfxwoNz54B5C97ejBr",
    "webhook": "https://plaid.com/example/hook"
  },
  "request_id": "qpCtl"
}

Update webhook

The POST /item/webhook/update allows you to update the webhook associated with an Item. This request triggers a WEBHOOK_UPDATE_ACKNOWLEDGED webhook.

Field Required? Description
client_id
String
yes
secret
String
yes
access_token
String
yes
webhook
String
Yes The new webhook to associate with the Item.

Update Webhook

POST /item/webhook/update

Update Webhook request

curl -X POST https://sandbox.plaid.com/item/webhook/update \
  -H 'content-type: application/json' \
  -d '{
    "client_id": String,
    "secret": String,
    "access_token": String,
    "webhook": "https://plaid.com/updated/hook"
  }'
# Update the webhook associated with an Item
webhook_response = client.item.webhook.update(item['access_token'],
                                              'https://my-new-webhook.com/plaid-webhook')
# Update the webhook associated with an Item
webhook_response = client.Item.webhook.update(
    access_token, 'https://my-new-webhook.com/plaid-webhook')
client.updateItemWebhook(ACCESS_TOKEN, "https://my-new-webhook.com/plaid-webhook", (err, result) => {
  // Handle err
  // A successful response indicates that the webhook has been updated. An
  // acknowledgement webhook will also be fired.
  const item = result.item;
});
Response<ItemWebhookUpdateResponse> webhookResponse = client().service().itemWebhookUpdate(
    new ItemWebhookUpdateRequest(ACCESS_TOKEN, "https://my-new-webhook.com/plaid-webhook")).execute();
ItemStatus itemStatus = webhookResponse.body().getItem();
String webhook = itemStatus.getWebhook();

Update Webhook Response

http code 200
{
  "item": {
    "available_products": [
      "balance",
      "auth"
    ],
    "billed_products": [
      "identity",
      "transactions"
    ],
    "error": null,
    "institution_id": "ins_109508",
    "item_id": "Ed6bjNrDLJfGvZWwnkQlfxwoNz54B5C97ejBr",
    "webhook": "https://plaid.com/updated/webhook"
  },
  "request_id": "qpCtl"
}

Rotate Access Token

By default, the access_token associated with an Item does not expire and should be stored in a persistent, secure manner.

You can use the POST /item/access_token/invalidate endpoint to rotate the access_token associated with an Item. The endpoint returns a new access_token and immediately invalidates the previous access_token.

Field Required?
client_id
String
yes
secret
String
yes
access_token
String
yes

Rotate Access Token

POST /item/access_token/invalidate

curl -X POST https://sandbox.plaid.com/item/access_token/invalidate \
  -H 'content-type: application/json' \
  -d '{
    "client_id": String,
    "secret": String,
    "access_token": String
  }'
# Generate a new access_token for an Item and invalidate the old one
response = client.item.access_token.invalidate(access_token)
# Store the new access_token in a persistent, secure datastore
new_access_token = response['acccess_token']
# Generate a new access_token for an Item and invalidate the old one
response = client.Item.access_token.invalidate(access_token)
# Store the new access_token in a persistent, secure datastore
new_access_token = response['acccess_token']
// Generate a new access_token for an Item and invalidate the old one
client.invalidateAccessToken(ACCESS_TOKEN, (err, result) => {
  // Handle err
  // Store the new access_token in a persistent, secure datastore
  const accessToken  = result.access_token;
});
Response<ItemAccessTokenInvalidateResponse> response = client().service().itemAccessTokenInvalidate(
  new ItemAccessTokenInvalidateRequest("ACCESS_TOKEN")).execute();

String newAccessToken;
if (response.isSuccessful()) {
  newAccessToken = response.body().getNewAccessToken();
}

Rotate Access Token Response

http code 200
{
  "new_access_token": "access-sandbox-7c69d345-fd46",
  "request_id": "ou2XQ"
}

Update Access Token version

If you have an access_token from the legacy version of Plaid’s API, you can use the /item/access_token/update_version endpoint to generate an access_token for the Item that works with the current API.

Calling this endpoint does not revoke the legacy API access_token. You can still use the legacy access_token in the legacy API environment to retrieve data. You can also begin using the new access_token with our current API immediately.

If there is a webhook associated with the Item, you will begin receiving current API webhooks as soon as a new access_token is generated for the Item.

The response includes an item_id that should be stored along the new access_token. The item_id is used to identify items in webhooks. The item_id can always be retrieved by making an /item/get request.

Field Required? Description
client_id
String
yes
secret
String
yes
access_token_v1
String
yes The legacy API access_token (160 character hexadecimal string)

Update Access Token version

POST /item/access_token/update_version

curl -X POST https://sandbox.plaid.com/item/access_token/update_version \
  -H 'content-type: application/json' \
  -d '{
    "client_id": String,
    "secret": String,
    "access_token_v1": String
  }'
# generate an updated access token for the legacy token
response = client.item.access_token.update_version("LEGACY_API_ACCESS_TOKEN")
# The response includes an access token compatible with Plaid's new API and
# the item ID for the access_token, which is used to identify the Item in 
# webhook payloads from Plaid.
# The old access token will still work with Plaid's legacy API endpoints.
# Store the new access_token and the item_id in a persistent, secure data store.
newAccessToken = response['access_token']
itemId = response['item_id']
# generate an updated access token for the legacy token
response = client.Item.access_token.update_version("LEGACY_API_ACCESS_TOKEN")
# The response includes an access token compatible with Plaid's new API and
# the item ID for the access_token, which is used to identify the Item in 
# webhook payloads from Plaid.
# The old access token will still work with Plaid's legacy API endpoints.
# Store the new access_token and the item_id in a persistent, secure data store.
newAccessToken = response.access_token
itemId = response.item_id
// Generate an updated access token for the legacy token
client.updateAccessTokenVersion("LEGACY_API_ACCESS_TOKEN", (err, result) => {
  // Handle err
  // The response includes an access token compatible with Plaid's new API and
  // the item ID for the access_token, which is used to identify the Item in 
  // webhook payloads from Plaid.
  // The old access token will still work with Plaid's legacy API endpoints.
  // Store the new access_token and the item_id in a persistent, secure data store.
  const newAccessToken = result.access_token;
  const itemId = result.item_id;
});
// Generate an updated access token for the legacy token
Response<ItemAccessTokenUpdateVersionResponse> response = client().service().itemAccessTokenUpdateVersion(
  new ItemAccessTokenUpdateVersionRequest("LEGACY_API_ACCESS_TOKEN"))
  .execute();

String newAccessToken;
String itemId;
if (response.isSuccessful()) {
  // The response includes an access token compatible with Plaid's new API and
  // the item ID for the access_token, which is used to identify the Item in 
  // webhook payloads from Plaid.
  // The old access token will still work with Plaid's legacy API endpoints.
  // Store the new access_token and the item_id in a persistent, secure data store.
  newAccessToken = response.body().getAccessToken();
  itemId = response.body().getItemId();
}

Update Access Token version response

http code 200
{
  "access_token": "access-production-8acd3678-3aa8-411e-bf5a-ee7851e0c75d",
  "item_id": "XkW36J3gewh9wE69VkyzSxyXwEBewBio4wwJ3",
  "request_id": "c92aB"
}

Delete an Item

The /item/delete endpoint allows you to delete an Item. Once deleted, the access_token associated with the Item is no longer valid and cannot be used to access any data that was associated with the Item.

Field Required?
client_id
String
yes
secret
String
yes
access_token
String
yes

Delete Item

POST /item/delete

curl -X POST https://sandbox.plaid.com/item/delete \
  -H 'content-type: application/json' \
  -d '{
    "client_id": String,
    "secret": String,
    "access_token": String
  }'
# Provide the access token for the Item you want to delete
client.item.delete(access_token)
# Provide the access token for the Item you want to delete
response = client.Item.delete(access_token)
client.deleteItem(ACCESS_TOKEN, (err, result) => {
  // Handle err
  // The Item has been deleted and the
  // access token is now invalid
  const isDeleted = result.deleted;
});
Response<ItemDeleteResponse> response = client().service().itemDelete(
  new ItemDeleteRequest(getItemCreateResponse().getAccessToken())
).execute();
// The Item has been deleted and the access token is now invalid
Boolean isDelete = response.body().getDeleted();

Delete Item Response

http code 200
{
  "deleted": true,
  "request_id": String,
}

Errors

Errors overview

We use standard HTTP response codes for success and failure notifications, and our errors are further classified by error_type. In general, 200 HTTP codes correspond to success, 40X codes are for developer- or user-related failures, and 50X codes are for Plaid-related issues. We’re always working to minimize API errors related to Plaid integrations and to address connectivity issues across bank infrastructure. The best resource related to error code resolution is the Help Center.

Error schema

{
  "error_type": String,
  "error_code": String,
  "error_message": String,
  "display_message": String
}

All errors returned by the API include the following data elements:

Field Description
error_type
String
A broad categorization of the error. One of: INVALID_REQUEST, INVALID_INPUT, RATE_LIMIT_EXCEEDED, API_ERROR, or ITEM_ERROR.

Safe for programmatic use.
error_code
String
The particular error code. Each error_type has a specific set of error_codes.

Safe for programmatic use.
error_message
String
A developer-friendly representation of the error code.

This may change over time and is not safe for programmatic use.
display_message
String, nullable
A user-friendly representation of the error code. null if the error is not related to user action.

This may change over time and is not safe for programmatic use.

Invalid request errors

Returned when the request is malformed and cannot be processed.

Error type

INVALID_REQUEST

Invalid request error

{
  "error_type": "INVALID_REQUEST",
  "http_code": Enum (400, 404),
  "error_code": Enum (
    "MISSING_FIELDS",
    "UNKNOWN_FIELDS",
    "INVALID_FIELD",
    "INVALID_BODY",
    "INVALID_HEADERS",
    "NOT_FOUND",
    "SANDBOX_ONLY"
  )
  "error_message": String
  "display_message": Null,
  "request_id": String
}
Error code Notes
MISSING_FIELDS
HTTP 400
The request was missing one or more required fields. The error_message field will list the missing field(s).
UNKNOWN_FIELDS
HTTP 400
The request included a field that is not recognized by the endpoint. The error_message field will list the extraneous field(s).
INVALID_FIELD
HTTP 400
One or more of the request body fields was improperly formatted or an invalid type.
INVALID_BODY
HTTP 400
The request body was invalid. Only JSON bodies are accepted.
INVALID_HEADERS
HTTP 400
The request was missing a required header, most typically the content-type header.
NOT_FOUND
HTTP 404
The endpoint requested does not exist.
SANDBOX_ONLY
HTTP 400
The requested endpoint is only available in the Sandbox API environment.

Invalid input errors

Returned when all fields are provided and are in the correct format, but the values provided are incorrect in some way.

Error type

INVALID_INPUT

Invalid input error

{
  "error_type": "INVALID_INPUT",
  "http_code": 400,
  "error_code": Enum (
    "INVALID_API_KEYS",
    "UNAUTHORIZED_ENVIRONMENT",
    "INVALID_ACCESS_TOKEN",
    "INVALID_PUBLIC_TOKEN",
    "INVALID_PRODUCT",
    "INVALID_ACCOUNT_ID",
    "INVALID_INSTITUTION"
  )
  "error_message": String
  "display_message": Null,
  "request_id": String
}
Error code Notes
INVALID_API_KEYS
HTTP 400
The client ID and secret included in the request body were invalid. Find your API keys in the Dashboard.
UNAUTHORIZED_ENVIRONMENT
HTTP 400
Your client ID does not have access to this API environment. See which environments you are enabled for from the Dashboard.
INVALID_ACCESS_TOKEN
HTTP 400
Access tokens are in the format:

access-<environment>-<identifier>

This error can happen when the access_token you provided is invalid, from a different API environment, or has been deleted.
INVALID_PUBLIC_TOKEN
HTTP 400
Public tokens are in the format:

public-<environment>-<identifier>

This error can happen when the public_token you provided is invalid, from a different API environment, or expired.
INVALID_PRODUCT
HTTP 400
Your client ID does not have access to this product. Contact us to gain access.
INVALID_ACCOUNT_ID
HTTP 400
One of the account_id(s) specified is invalid or does not exist.
INVALID_INSTITUTION
HTTP 400
The institution_id specified is invalid or does not exist.

Rate limit exceeded errors

Returned when the request is valid but has exceeded established rate limits. All API endpoints are rate limited and all data-access endpoints are rate limited by access_token. Exact limits are dynamic and are designed to prevent any single source of traffic from impacting overall API stability.

Error type

RATE_LIMIT_EXCEEDED

Rate limit error schema

{
  "error_type": "RATE_LIMIT_EXCEEDED",
  "http_code": 429,
  "error_code": Enum (
    "ADDITION_LIMIT",
    "AUTH_LIMIT",
    "TRANSACTIONS_LIMIT",
    "IDENTITY_LIMIT",
    "INCOME_LIMIT",
    "ITEM_GET_LIMIT",
    "RATE_LIMIT"
  )
  "error_message": String
  "display_message": nullable String,
  "request_id": String
}
Error code Notes
ADDITION_LIMIT
HTTP 429
You have exceeded your addition limit in our Development environment. To increase it, or raise it from zero, contact us.
AUTH_LIMIT
HTTP 429
Too many requests were made to the /auth/get endpoint.
TRANSACTIONS_LIMIT
HTTP 429
Too many requests were made to the /transactions/get endpoint.
IDENTITY_LIMIT
HTTP 429
Too many requests were made to the /identity/get endpoint.
INCOME_LIMIT
HTTP 429
Too many requests were made to the /income/get endpoint.
RATE_LIMIT
HTTP 429
Too many requests were made.
ITEM_GET_LIMIT
HTTP 429
Too many requests were made to the /item/get endpoint.

API errors

Returned during planned maintenance windows and in response to API errors.

Error type

API_ERROR

API error schema

{
  "error_type": "API_ERROR",
  "http_code": 500,
  "error_code": Enum (
    "INTERNAL_SERVER_ERROR",
    "PLANNED_MAINTENANCE"
  )
  "error_message": String
  "display_message": nullable String,
  "request_id": String
}
Error code Notes
INTERNAL_SERVER_ERROR
HTTP 500
Plaid was unable to process the request, either due to an internal system issue or an unsupported response from a financial institution.
PLANNED_MAINTENANCE
HTTP 500
Plaid's systems are in maintenance mode and API operations are disabled. Advanced notice will be provided if a maintenance window is ever planned.

Item errors

An ITEM_ERROR indicates that information provided for the Item (such as credentials or MFA) may be invalid or that the Item is not supported on Plaid's platform. You'll encounter ITEM_ERRORs as your users use Link via the onExit() callback.

Error type

ITEM_ERROR

Item error schema

{
  "error_type": "ITEM_ERROR",
  "http_code": 400,
  "error_code": Enum (
    "INVALID_CREDENTIALS",
    "INVALID_MFA",
    "ITEM_LOCKED",
    "ITEM_LOGIN_REQUIRED",
    "ITEM_NO_ERROR",
    "ITEM_NOT_SUPPORTED",
    "USER_SETUP_REQUIRED",
    "MFA_NOT_SUPPORTED",
    "NO_ACCOUNTS",
    "NO_AUTH_ACCOUNTS",
    "PRODUCT_NOT_READY",
    "PRODUCT_NOT_SUPPORTED"
  )
  "error_message": String
  "display_message": nullable String,
  "request_id": String
}
Error code Notes
INVALID_CREDENTIALS
HTTP 400
The financial institution indicated that the credentials provided were invalid.
INVALID_MFA
HTTP 400
The financial institution indicated that the MFA response(s) provided were invalid.
ITEM_LOCKED
HTTP 400
The financial institution indicated that the user's account is locked. The user will need to work with the institution directly to unlock their account.
ITEM_LOGIN_REQUIRED
HTTP 400
The financial institution indicated that the user's password or MFA information has changed. They will need to reauthenticate via Link's update mode
ITEM_NO_ERROR
HTTP 400
Link was initialized in update mode for an Item that is in a good state. No further action is required.
ITEM_NOT_SUPPORTED
HTTP 400
Plaid is unable to support this user's accounts due to restrictions in place at the financial institution.
USER_SETUP_REQUIRED
HTTP 400
The user must log in directly to the financial institution and take some action (agree to updated terms and conditions, change their password, etc.) before Plaid can access their accounts.
MFA_NOT_SUPPORTED
HTTP 400
Returned when the user requires a form of MFA that Plaid does not support for a given financial institution.
NO_ACCOUNTS
HTTP 400
Returned when there are no open accounts associated with the Item.
NO_AUTH_ACCOUNTS
HTTP 400
Returned from POST /auth/get when there are no valid checking or savings account(s) for which account and routing numbers could be retrieved.
PRODUCT_NOT_READY
HTTP 400
Returned when a data request has been made for a product that is not yet ready. This primarily happens when attempting to pull transactions prior to the initial pull.
PRODUCT_NOT_SUPPORTED
HTTP 400
Returned when a data request has been made for an Item for a product that it does not support. Use the /item/get endpoint to find out which products an Item supports.

Institution errors

Returned when there are errors for the requested financial institution.

Error type

INSTITUTION_ERROR

Institution error schema

{
  "error_type": "INSTITUTION_ERROR",
  "http_code": 400,
  "error_code": Enum (
    "INSTITUTION_DOWN",
    "INSTITUTION_NOT_RESPONDING",
    "INSTITUTION_NOT_AVAILABLE",
    "INSTITUTION_NO_LONGER_SUPPORTED"
  )
  "error_message": String
  "display_message": nullable String,
  "request_id": String
}
Error code Notes
INSTITUTION_DOWN
HTTP 400
The financial institution is down, either for maintenance or due to an infrastructure issue with their systems.
INSTITUTION_NOT_RESPONDING
HTTP 400
The financial institution is failing to respond to some of our requests. Your user may be successful if they retry another time.
INSTITUTION_NOT_AVAILABLE
HTTP 400
The financial institution is not available this time.
INSTITUTION_NO_LONGER_SUPPORTED
HTTP 400
Plaid no longer supports this financial institution.

Webhooks

Transactions webhooks

You can receive notifications via a webhook whenever there are new transactions associated with an Item, including when Plaid’s initial and historical transaction pull are completed. All webhooks related to transactions have a webhook_type of TRANSACTIONS.

Code Details
INITIAL_UPDATE Fired when an Item’s initial transaction pull is completed.

Note: The default pull is 30 days.
HISTORICAL_UPDATE Fired when an Item’s historical transaction pull is completed. Plaid fetches as much data as is available from the financial institution. See data availability by institution.
DEFAULT_UPDATE Fired when new transaction data is available as Plaid performs its regular updates of the Item.

The webhook must be in the standard format of http(s)://(www.)domain.com/. The response will contain a corresponding success message and code along with the same item_id that was returned in the initial call (examples below). Once the transaction processing has finished, you can use the Item's access_token to collect the full account and transaction information for that user.

All transactions webhooks will have a webhook_type equal to TRANSACTIONS. Each webhook payload will also include a unique webhook_code and the item_id for which the webhook is being fired.

Webhook Body

Initial Transaction Webhook

{
  "webhook_type": "TRANSACTIONS",
  "webhook_code": "INITIAL_UPDATE",
  "item_id": "wz666MBjYWTp2PDzzggYhM6oWWmBb",
  "error": null,
  "new_transactions": 19
}

Historical Transaction Webhook

{
  "webhook_type": "TRANSACTIONS",
  "webhook_code": "HISTORICAL_UPDATE",
  "item_id": "wz666MBjYWTp2PDzzggYhM6oWWmBb",
  "error": null,
  "new_transactions": 231
}

Default Transaction Webhook

{
  "webhook_type": "TRANSACTIONS",
  "webhook_code": "DEFAULT_UPDATE",
  "item_id": "wz666MBjYWTp2PDzzggYhM6oWWmBb",
  "error": null,
  "new_transactions": 3
}

Removed Transaction Webhook

{
  "webhook_type": "TRANSACTIONS",
  "webhook_code": "TRANSACTIONS_REMOVED",
  "item_id": "wz666MBjYWTp2PDzzggYhM6oWWmBb",
  "removed_transactions": [
    "yBVBEwrPyJs8GvR77N7QTxnGg6wG74H7dEDN6",
    "kgygNvAVPzSX9KkddNdWHaVGRVex1MHm3k9no"
  ],
  "error": null
}

Item's Webhook Updated

{
  "webhook_type": "ITEM",
  "webhook_code": "WEBHOOK_UPDATE_ACKNOWLEDGED",
  "item_id": "wz666MBjYWTp2PDzzggYhM6oWWmBb",
  "error": null
}

Item webhooks

Webhooks are also used to communicate changes to an Item, such as an updated webhook, or errors encountered with an Item. The error typically requires user action to resolve, such as when a user changes their password. For a complete list of possible errors, see Errors.

Code Details
WEBHOOK_UPDATE_ACKNOWLEDGED Fired when an Item’s webhook is updated.
ERROR Fired when an error is encountered with an Item. The error can be resolved by having the user go through Link’s update mode.

Item's Webhook Updated

{
  "webhook_type": "ITEM",
  "webhook_code": "WEBHOOK_UPDATE_ACKNOWLEDGED",
  "item_id": "wz666MBjYWTp2PDzzggYhM6oWWmBb",
  "error": null,
  "new_webhook": "https://plaid.com/example/webhook"
}

Error Response Webhook Example

{
  "webhook_type": "ITEM",
  "webhook_code": "ERROR",
  "item_id": "wz666MBjYWTp2PDzzggYhM6oWWmBb",
  "error": {
    "display_message": "The provided credentials were not correct. Please try again.",
    "error_code": "ITEM_LOGIN_REQUIRED",
    "error_message": "the provided credentials were not correct",
    "error_type": "ITEM_ERROR",
    "status": 400
  }
}

Income webhooks

If you're using webhooks with the Income product, you'll receive a webhook when Plaid calculates the Income data for the Item. Once you receive this webhook, you can make an /income/get API request to retrieve Income data.

Income ready webhook

{
  "webhook_type": "INCOME",
  "webhook_code": "PRODUCT_READY",
  "item_id": "wz666MBjYWTp2PDzzggYhM6oWWmBb",
  "error": null
}

Institutions

Institution overview

Plaid supports thousands of financial institutions, and we’re always working to add support for more. The /institutions/search endpoint makes it easy to stay up-to-date with supported institutions and help your users quickly find their institutions.

You can also use the /institutions/get endpoint to retrieve a complete list of supported institutions. This data changes frequently, and we recommend that you do not store it on your system. If you do store it, be sure to update it regularly.

Institutions endpoints

POST /institutions/get
POST /institutions/get_by_id
POST /institutions/search

Institutions by product

This is not a comprehensive list, but below you can find product coverage information for some of our most popular institutions:

Auth Transactions Balance Identity Income
amex
ID: ins_10
bbt
ID: ins_2
bbvac
ID: ins_23
bofa
ID: ins_1
capone
ID: ins_9
chase
ID: ins_3
citizens
ID: ins_20
citi
ID: ins_5
huntington
ID: ins_21
keybank
ID: ins_29
mtb
ID: ins_27
nfcu
ID: ins_15
pnc
ID: ins_13
regions
ID: ins_19
schwab
ID: ins_11
simple
ID: ins_24
suntrust
ID: ins_16
td
ID: ins_14
us
ID: ins_6
usaa
ID: ins_7
wells
ID: ins_4

Information about transaction data availability for each of these financial institutions can be found at our Help Center.

To see a full list of supported institutions across all products, use the /institutions/get and /institutions/search endpoints.

Note: While we do our best to streamline the majority of bank interactions, it’s worth noting a few rare inconsistencies with certain banks and account types. For example, some newly opened accounts may be missing certain information for a short period of time while the data propagates through the bank’s systems. A detailed list of such exceptions can be found below.

Returns a JSON response containing details for all institutions that match the query parameters.

Field Required? Description
query
String
Yes The search query. Institutions with names matching the query are returned.
products
[String]
Yes Filter the Institutions based on whether they support all products listed in products. Provide null to get institutions regardless of supported products.
public_key
String
Yes
options
Object
No If provided, must be non-null.
POST /institutions/search

Search by Bank and Product

curl -X POST https://sandbox.plaid.com/institutions/search \
  -H 'content-type: application/json' \
  -d '{
    "query": "BB&T",
    "products": ["auth", "identity"],
    "public_key": String
  }'
response = client.institutions.search(SEARCH_QUERY)
# search with products
response = client.institutions.search(SEARCH_QUERY, [:transactions])
response = client.Institutions.search(SEARCH_QUERY)
# search with products
response = client.Institutions.search(SEARCH_QUERY, products=['transactions'])
client.searchInstitutionsByName(SEARCH_QUERY, ['transactions'],
function(err, response) {
  // Handle err
  institutions = response.institutions;
});
Response<InstitutionsSearchResponse> response =
  client().service().institutionsSearch(new InstitutionsSearchRequest(SEARCH_QUERY).withProducts(Product.AUTH)).execute();
List<Institution> results = response.body().getInstitutions();

Institutions search response

http code 200
{
  "institutions": [{
    "credentials": [{
      "label": "User ID",
      "name": "username",
      "type": "text"
    }, {
      "label": "Password",
      "name": "password",
      "type": "password"
    }],
    "has_mfa": true,
    "institution_id": "ins_109509",
    "mfa": [
      "code",
      "list",
      "questions",
      "selections"
    ],
    "name": "First Gingham Credit Union",
    "products": [
      "balance",
      "identity",
      "auth",
      "transactions"
    ]
  }],
  "request_id": "DLVvK"
}

All Institutions

Returns a JSON response containing details on all financial institutions currently supported by Plaid. Because we support thousands of institutions, results are paginated.

Use the count and offset query parameters to retrieve the desired institution data.

Field Required? Description
client_id
String
Yes
secret
String
Yes
count
Number
Yes The total number of Institutions to return, with 0 < count <= 500.
offset
Number
Yes The number of Institutions to skip before returning results, with offset >= 0.
options
Object
No If provided, must be non-null.

The following options are available:

Field Default Description
products
[String]
null Filter the Institutions based on whether they support all products listed in products.

All Institutions

 POST /institutions/get

Retrieve all Institutions

curl -X POST https://sandbox.plaid.com/institutions/get \
  -H 'content-type: application/json' \
  -d '{
    "client_id": String,
    "secret":String,
    "count": Number,
    "offset": Number
  }'
response = client.institutions.get(count: count, offset: offset)
institutions = response['institutions']
response = client.Institutions.get(count, offset=offset)
institutions = response['institutions']
// Pull institutions
client.getInstitutions(count, offset, (err, result) => {
  // Handle err
  const institutions = result.institutions;
});
Response<InstitutionsGetResponse> response =
  client().service().institutionsGet(new InstitutionsGetRequest(count, offset)).execute();
List<Institution> institutions = response.body().getInstitutions();

All Institutions response

http code 200
{
  "institutions": [
    {
      "credentials": [{
        "label": "User ID",
        "name": "username",
        "type": "text"
       }, {
        "label": "Password",
        "name": "password",
        "type": "password"
      }],
      "has_mfa": true,
      "institution_id": "ins_109508",
      "mfa": [
        "code",
        "list",
        "questions",
        "selections"
      ],
      "name": "First Platypus Bank",
      "products": [
        "balance",
        "identity",
        "auth",
        "transactions"
      ]
    }, {
    "credentials": [{
      "label": "User ID",
      "name": "username",
      "type": "text"
    }, {
      "label": "Password",
      "name": "password",
      "type": "password"
    }],
    "has_mfa": true,
    "institution_id": "ins_109509",
    "mfa": [
      "code",
      "list",
      "questions",
      "selections"
    ],
    "name": "First Gingham Credit Union",
    "products": [
      "balance",
      "identity",
      "auth",
      "transactions"
    ]
  }],
  "request_id": "lHkKq",
  "total": 5
}

Institutions by ID

Returns a JSON response containing details on a specified financial institution currently supported by Plaid.

Field Required? Description
institution_id
String
Yes
public_key
String
Yes
options
Object
No If provided, must be non-null.

Institutions by ID

 POST /institutions/get_by_id

Institutions by ID request

curl -X POST https://sandbox.plaid.com/institutions/get_by_id \
  -H 'content-type: application/json' \
  -d '{
    "institution_id": "ins_109512",
    "public_key": String
  }'
response = client.institutions.get_by_id(INSTITUTION_ID)
response = client.Institutions.get_by_id(INSTITUTION_ID)
// Pull institution by ID
client.getInstitutionById(institutionId, (err, result) => {
  // Handle err
  const institution = result.institution;
});
// Pull institution by ID
Response<InstitutionsGetByIdResponse> response = client().service().institutionsGetById(new InstitutionsGetByIdRequest(INSTITUTION_ID))
  .execute();
Institution institution = response.body().getInstitution();

Institutions by ID Response

http code 200
{
  "institution": {
    "credentials": [{
      "label": "User ID",
      "name": "username",
      "type": "text"
     }, {
      "label": "Password",
      "name": "password",
      "type": "password"
    }],
    "has_mfa": true,
    "institution_id": "ins_109512",
    "mfa": [
      "code",
      "list",
      "questions",
      "selections"
    ],
    "name": "Houndstooth Bank",
    "products": [
      "auth",
      "balance",
      "identity",
      "transactions"
    ]
  },
  "request_id": "9VpnU"
}

Categories

Category overview

Send a request to the /categories/get endpoint to get detailed information on categories returned by Plaid. This endpoint does not require authentication.

Category

POST /categories/get

All Categories request

curl -X POST https://sandbox.plaid.com/categories/get \
  -H 'content-type: application/json' \
  -d '{}'
response = client.categories.get()
categories = response['categories']
`
response = client.Categories.get()
categories = response['categories']
`
client.getCategories(function(err, response) {
  // Handle err
  var categories = response.categories;
});
Response<CategoriesGetResponse> response = client().service().categoriesGet(
  new CategoriesGetRequest()
).execute()
List<Category> categories = response.body().getCategories();
`

All Categories response

http code 200
{
  "categories": [
    {
      "group": "place",
      "hierarchy": [
        "Recreation",
        "Arts & Entertainment",
        "Circuses and Carnivals"
      ],
      "category_id": "17001013"
    },
    ...
  ],
  "request_id": "qpCtl"
}

Sandbox

To use Link in the API sandbox, simply initialize Link with the env parameter set to sandbox.

Sandbox institutions

All institutions that are available in our Development and Production environments are available in our Sandbox. Only certain test credentials are valid in the Sandbox and no interaction with the financial institutions occurs.

There are also five supported Sandbox-only Institutions that are suitable to write integration tests against:

Name ID
First Platypus Bank ins_109508
First Gingham Credit Union ins_109509
Tattersall Federal Credit Union ins_109510
Tartan Bank ins_109511
Houndstooth Bank ins_109512

Complete information about Sandbox institutions is available from the /institutions/get endpoint in the Sandbox API environment.

Sandbox API host

https://sandbox.plaid.com

Retrieve all Institutions

curl -X POST https://sandbox.plaid.com/institutions/get \
-H 'Content-type: application/json' \
-d '{
  "client_id": "[PUBLIC_KEY]",
  "secret": "[SECRET]",
  "count": 200,
  "offset": 0
}'

Retrieve Tartan Bank (institution_id: ins_109511)

curl -X POST https://sandbox.plaid.com/institutions/get_by_id \
-H 'Content-type: application/json' \
-d '{
  "public_key": "[PUBLIC_KEY]",
  "institution_id": "ins_109511"
}'

Creating Items in the Sandbox

Each institution works with Plaid’s Sandbox credentials. These special credentials allow you to simulate successful requests, requests that require various types of MFA, and failed requests. The default credentials are:

username: user_good
password: pass_good
pin: credential_good (when required)

You can trigger any type of MFA flow that Plaid supports when creating an Item. Do so by using username user_good and modifying the password:

Password Notes
mfa_device
Device MFA
Code for all devices: 1234
mfa_questions_<n>_<m>
Questions MFA
n-rounds of m-questions per round; answer_<i>_<j>, for j-th question in i-th round.
0 < i, j <= 9
mfa_selections
Selections MFA (simple)
Answer for all selections: "Yes"
mfa_selections_<n>_<m>_<o> Selections MFA (multiple) n-rounds of m-questions with o-answers per question; answer_<i>_<j>_0, for j-th question in i-th round.
0 < n, m < 10 and 2 < o < 10

You can trigger any ITEM_ERROR or INSTITUTION_ERROR that you could typically receive when creating an Item. Do so by using username user_good and modifying the password:

error_[ERROR_CODE]

For example, the password error_ITEM_LOCKED allows you to simulate an ITEM_LOCKED error.

Managing Item states

An Item may transition into an error state in response to changes made by the user or financial institution. The most common scenarios are when a user changes their password or when the financial institution changes their multi-factor authentication flow. Plaid Link makes it easy to restore a user's Item to a good state by having them provide updated credentials and MFA information, if needed.

In the Sandbox, Items transition to an ITEM_LOGIN_REQUIRED error state automatically after 30 days. You can also simulate this event via an API request.

Simulating ITEM_LOGIN_REQUIRED errors

The /sandbox/item/reset_login endpoint allows you put an Item in an ITEM_LOGIN_REQUIRED error state. You can then use Plaid Link update mode to restore the Item to a good state.

Field Required?
client_id
String
Yes
secret
String
Yes
access_token
String
Yes

Note: This endpoint is only available in the Sandbox API environment.

Simulate Item error

 POST /sandbox/item/reset_login

Sandbox reset Item login request

curl -X POST https://sandbox.plaid.com/sandbox/item/reset_login \
  -H 'content-type: application/json' \
  -d '{
    "client_id": String,
    "secret": String,
    "access_token": String
  }'
# Force a Sandbox Item into an error state
client.sandbox.sandbox_item.reset_login(access_token)
# create a public_token for the Item and use it to initialize Link in
# update mode.
public_token_response = client.item.public_token.create(access_token)
# Force a Sandbox Item into an error state
client.Sandbox.item.reset_login(access_token)
# create a public_token for the Item and use it to initialize Link in
# update mode.
public_token_response = client.Item.public_token.create(access_token)
client.resetLogin(access_token, function(err, reset_login_response) {
  // Handle err
  // create a public_token for the Item
  client.createPublicToken(access_token, function(err, public_token_response) {
    // Handle err
    // Use the generated public_token to
    // initialize Link in update mode
  });
});
Response<ItemResetLoginResponse> response = client().service().itemResetLogin(
  new ItemResetLoginRequest(ACCESS_TOKEN)
).execute();

Sandbox reset Item login response

http code 200
{
  "reset_login": true,
  "request_id": String
}