Plaid Link Auth Flow

Plaid and Dwolla have partnered to offer frictionless and fully tokenized ACH payments. Use Plaid to instantly authenticate your customer's bank account to set up ACH payments via Dwolla’s API.

Your users verify their accounts in seconds by inputting their banking credentials in Plaid’s front-end module. Plaid’s mobile-friendly module handles input validation, error handling, and multi-factor authentication - providing a seamless experience that converts more users for your business.

As part of the Plaid integration, Dwolla customers can access Plaid’s full suite of APIs for clean, categorized transaction data, real-time balances, and more.

To get started sign up for API keys or try out the Plaid demo

Getting Started

You'll first want to familiarize yourself with Plaid Link, a drop-in integration for the Plaid API that handles input validation, error handling, and multi-factor authentication.

Your customers will use Link to authenticate with their financial institution and select the depository account they wish to use for ACH transactions. From there, you'll receive a Plaid access_token, allowing you to leverage real-time balance checks and transaction data, and a Dwolla processor_token, which allows you to move money via Dwolla's ACH API without ever handling an account or routing number.


Step 1: Set up your Plaid and Dwolla accounts

You'll need accounts at both Plaid and Dwolla in order to use the Plaid Link + Dwolla integration. You'll also need to enable your Plaid account for the Dwolla integration.

To get started, sign up for a Dwolla account if you do not already have one and then verify that it is enabled for ACH access. Then sign up for a Plaid account from the links on this page to ensure that your Plaid account will be enabled for the integration by default.

Step 2: Get your public_key

Your public_key is available from the Plaid Dashboard.

You have three different API keys

View in Dashboard


a non-sensitive, public identifier that is used to initialize Plaid Link

secret client_id

private identifiers that are required for accessing any financial data

these should never be shared in client-side code

Your public_key is a less privileged version of your client_id and secret. It simply associates accounts you create using Plaid Link with your client_id. All Plaid API requests must be made using your private client_id and secret.

Step 3: Integrate with Plaid Link

Integrating with Link is easy. All it takes is a few lines of client-side JavaScript and a small server-side handler to exchange the Link public_token for a Plaid access_token and a Dwolla processor token.

You can either trigger the "Institution Select" view, a general purpose view that lists all Plaid-supported institutions, or trigger a particular institution's login form. See below:

<button id="linkButton">Open Link - Institution Select</button>
<button id="bofaButton">Open Link - Bank of America</button>
<script src="">
var linkHandler = Plaid.create({
  selectAccount: true,
  env: 'sandbox',
  clientName: 'Client Name',
  key: '[YOUR PUBLIC_KEY]',
  product: ['auth'],
  onLoad: function() {
    // The Link module finished loading.
  onSuccess: function(public_token, metadata) {
    // The onSuccess function is called when the user has successfully
    // authenticated and selected an account to use.
    // When called, you will send the public_token and the selected
    // account ID, metadata.account_id, to your backend app server.
    // sendDataToBackendServer({
    //   public_token: public_token,
    //   account_id: metadata.account_id
    // });
    console.log('Public Token: ' + public_token);
    console.log('Customer-selected account ID: ' + metadata.account_id);
  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.

// Trigger the standard Institution Select view
document.getElementById('linkButton').onclick = function() {;

See the parameter reference for complete documentation on possible configurations.

Plaid.create accepts one argument, a configuration Object, and returns an Object with one function, open, and one property, institutions.

The exposed institutions property is an Array of Objects in the form:

    name: 'Bank of America',
    institution_id: 'ins_1',
    auth: true,
    transactions: true,

The institutions property will be populated with all supported institutions for a given product. That is, the list of institutions will be different for auth and transactions.

Step 4: Write server-side handler

The Link module handles the entire onboarding flow securely and quickly but does not actually retrieve account data for a user. Instead, the Link module returns a public_token and an account_id (a property on the metadata object) via the onSuccess callback.

This public_token must be exchanged for a Plaid access_token using the /item/public_token/exchange API endpoint. Once you have the access_token for the Item, you'll create a Dwolla processor_token. You'll send this token to Dwolla and they will use it to securely retrieve account and routing numbers from Plaid.

You can create Dwolla processor_tokens in all three API environments:

// Change sandbox to development to test with live users and change
// to production when you're ready to go live!
var plaid = require('plaid');

var plaidClient = new plaid.Client('[Plaid client ID]',
                                   '[Plaid secret]',
                                   '[Plaid public key]'

plaidClient.exchangePublicToken('[Plaid Link public_token]', function(err, res) {
  var accessToken = res.access_token;
  // Generate a processor token
  plaidClient.createProcessorToken(accessToken, '[Account ID]', 'dwolla', function(err, res) {
    var processor_token = res.processor_token;

# Exchange token
curl -X POST \
-H 'Content-Type: application/json'
-d '{
  "client_id": "[Plaid Client ID],
  "secret": "[Plaid secret]",
  "public_token": "[Public token]"

# Create processor token
curl -X POST \
-H 'Content-Type: application/json'
-d '{
  "client_id": "[Plaid Client ID],
  "secret": "[Plaid secret]",
  "access_token": "[Access token]",
  "account_id": "[Account ID]",

  # Change sandbox to development to test with live users and change
  # to production when you're ready to go live!
  client = :sandbox,
                             client_id: ENV['PLAID_CLIENT_ID'],
                             secret: ENV['PLAID_SECRET'],
                             public_key: ENV['PLAID_PUBLIC_KEY'])

  exchange_token_response ='[Plaid Link public_token]')
  access_token = exchange_response['access_token']

  dwolla_response = client.processor.createProcessorToken(access_token, '[Account ID]', 'dwolla')
  processor_token = dwolla_response['processor_token']

// Change sandbox to development to test with live users and change
// to production when you're ready to go live!
PlaidClient plaidClient = PlaidClient.newBuilder()
  .clientIdAndSecret("[Plaid client ID]", "[Plaid secret]")
  .publicKey("[Plaid public key]")
  .sandboxBaseUrl() // Use the Sandbox. Can also be developmentBaseUrl() or productionBaseUrl()

Response<ItemPublicTokenExchangeResponse> exchangeResponse = plaidClient.service()
    .itemPublicTokenExchange(new ItemPublicTokenExchangeRequest("[Plaid Link public_token]")).execute();

if (exchangeResponse.isSuccessful()) {
  String accessToken = exchangeResponse.body().getAccessToken();
  Response<ItemDwollaProcessorTokenCreateResponse> dwollaResponse =
      client().service().itemDwollaProcessorTokenCreate(new ItemDwollaProcessorTokenCreateRequest(accessToken, "[Account ID]")).execute();

  if (dwollaResponse.isSuccessful()) {
    String dwollaProcessorToken = dwollaResponse.body().getProcessorToken();

# Change sandbox to development to test with live users and change
# to production when you're ready to go live!
client = Client('[Plaid client ID]',
                '[Plaid secret]',
                '[Plaid public key]'],

exchange_token_response ='[Plaid Link public_token]')
access_token = exchange_token_response['access_token']

dwolla_response = client.Processor.createProcessorToken(access_token, '[Account ID]', 'dwolla'])
processor_token = dwolla_response['processor_token']

For a valid request, the API will return a JSON response similar to:

  "processor_token": "processor-sandbox-0asd1-a92nc",
  "request_id": "[Unique request ID]"

For possible error codes, see the full listing of Plaid error codes.

Step 5: Test with sandbox credentials

Link's sandbox mode is compatible with Plaid's Sandbox API environment.

Use Dwolla's Sandbox API environment to create funding sources using the proccessor_tokens you retrieve from Plaid's Sandbox API environment. To test the integration in sandbox mode, simply use the Plaid sandbox credentials along with your Dwolla sandbox credentials, as well as your your public_key.

Step 6: Get ready for production

Your account is immediately enabled for our Sandbox and Development environments ( and, which allows you to test with Sandbox API credentials and up to 100 live users. To move to Production, please request access from the Dashboard.

Support and questions

Find answers to many common integration questions and concerns—such as pricing, sandbox and test mode usage, and more—at our Help Center and docs.