Maintain an existing public key integration



Overview

This is a reference guide that covers how to use the legacy public_key integration for Plaid Link.

In July 2020, Plaid introduced the link_token, which replaces the static public_key. While we are still currently supporting integrations using the public_key, we encourage you to upgrade your integration to use link_tokens instead since we'll be building more features using the link_tokens infrastructure. To start upgrading, see the migration guide.


Link service

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.

Note: If you want to initialize Link for European countries, you must specify a European country code using the ISO-3166-1 alpha-2 standard. This will also require the European consent panel to display to end users during item add flows.

Client-side Link integration

<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 Quickstart',
    // Optional, specify an array of ISO-3166-1 alpha-2 country
    // codes to initialize Link; European countries will have GDPR
    // consent panel
    countryCodes: ['US'],
    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',
    // Optional, specify a language to localize Link
    language: 'en',
    token: 'public-sandbox-5bbe4a5a-5e78-4e2a-ae0a-3751bc19fc09', // optional
    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 or IDs, if the
      // Select Account 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>

<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 Quickstart',
    // Optional, specify an array of ISO-3166-1 alpha-2 country
    // codes to initialize Link; European countries will have GDPR
    // consent panel
    countryCodes: ['US'],
    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',
    // Optional, specify a language to localize Link
    language: 'en',
    token: 'public-sandbox-5bbe4a5a-5e78-4e2a-ae0a-3751bc19fc09', // optional
    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 or IDs, if the
      // Select Account 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>

<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 Quickstart',
    // Optional, specify an array of ISO-3166-1 alpha-2 country
    // codes to initialize Link; European countries will have GDPR
    // consent panel
    countryCodes: ['US'],
    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',
    // Optional, specify a language to localize Link
    language: 'en',
    token: 'public-sandbox-5bbe4a5a-5e78-4e2a-ae0a-3751bc19fc09', // optional
    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 or IDs, if the
      // Select Account 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>

<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 Quickstart',
    // Optional, specify an array of ISO-3166-1 alpha-2 country
    // codes to initialize Link; European countries will have GDPR
    // consent panel
    countryCodes: ['US'],
    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',
    // Optional, specify a language to localize Link
    language: 'en',
    token: 'public-sandbox-5bbe4a5a-5e78-4e2a-ae0a-3751bc19fc09', // optional
    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 or IDs, if the
      // Select Account 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>

<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 Quickstart',
    // Optional, specify an array of ISO-3166-1 alpha-2 country
    // codes to initialize Link; European countries will have GDPR
    // consent panel
    countryCodes: ['US'],
    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',
    // Optional, specify a language to localize Link
    language: 'en',
    token: 'public-sandbox-5bbe4a5a-5e78-4e2a-ae0a-3751bc19fc09', // optional
    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 or IDs, if the
      // Select Account 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>

<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 Quickstart',
    // Optional, specify an array of ISO-3166-1 alpha-2 country
    // codes to initialize Link; European countries will have GDPR
    // consent panel
    countryCodes: ['US'],
    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',
    // Optional, specify a language to localize Link
    language: 'en',
    token: 'public-sandbox-5bbe4a5a-5e78-4e2a-ae0a-3751bc19fc09', // optional
    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 or IDs, if the
      // Select Account 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>

<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 Quickstart',
    // Optional, specify an array of ISO-3166-1 alpha-2 country
    // codes to initialize Link; European countries will have GDPR
    // consent panel
    countryCodes: ['US'],
    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',
    // Optional, specify a language to localize Link
    language: 'en',
    token: 'public-sandbox-5bbe4a5a-5e78-4e2a-ae0a-3751bc19fc09', // optional
    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 or IDs, if the
      // Select Account 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>

<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 Quickstart',
    // Optional, specify an array of ISO-3166-1 alpha-2 country
    // codes to initialize Link; European countries will have GDPR
    // consent panel
    countryCodes: ['US'],
    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',
    // Optional, specify a language to localize Link
    language: 'en',
    token: 'public-sandbox-5bbe4a5a-5e78-4e2a-ae0a-3751bc19fc09', // optional
    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 or IDs, if the
      // Select Account 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>
Install dependencies

npm install express body-parser plaid
node server.js

gem install sinatra plaid
ruby server.rb

<dependency>
  <groupId>com.plaid</groupId>
  <artifactId>plaid-java</artifactId>
  <version>{...}</version>
  // e.g.: <version>5.1.0</version>
  // Source the latest plaid-java version from
  // https://github.com/plaid/plaid-java/releases
</dependency>

npm install express body-parser plaid
node server.js

pip install plaid-python flask
python server.py

npm install express body-parser plaid
node server.js

npm install express body-parser plaid
node server.js

npm install express body-parser plaid
node server.js
Server-side Link handler

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({
  clientID: 'PLAID_CLIENT_ID',
  secret: 'PLAID_SECRET',
  env: 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);

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({
  clientID: 'PLAID_CLIENT_ID',
  secret: 'PLAID_SECRET',
  env: 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);

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')

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

import java.net.*;
import java.io.*;
import com.sun.net.httpserver.*;

import com.plaid.client;
import com.plaid.client.request.ItemPublicTokenExchangeRequest;
import com.plaid.client.response.ItemPublicTokenExchangeResponse;


public class PlaidExample {
  private static final String CLIENT_ID = "PLAID_CLIENT_ID";
  private static final String SECRET = "PLAID_SECRET";

  public static void main(String[] args) {
    HttpServer server = HttpServer.create(
      new InetSocketAddress("localhost", 8000), 0);
    server.createContext("/get_access_token", new GetAccessToken());
    hs.setExecutor(null);
    server.start();
  }

  static class GetAccessToken implements HttpHandler {
    private static PlaidClient plaidClient;

    private String publicToken;
    private String accessToken;
    private String itemId;

    public void handle(HttpExchange t) throws IOException {
      // Simplified psuedo-code for obtaining public_token
      InputStream is = t.getRequestBody();
      publicToken = is.publicToken();

      // Build your Plaid client
      PlaidClient plaidClient = PlaidClient.newBuilder()
        .clientIdAndSecret(CLIENT_ID, SECRET)
        .sandboxBaseUrl() // sandbox Plaid environment
        .logLevel(HttpLoggingInterceptor.Level.BODY)
        .build();

      // Exchange public_token for an access_token
      Response<ItemPublicTokenExchangeResponse> plaidResponse =
        plaidClient()
          .service()
          .itemPublicTokenExchange(
            new ItemPublicTokenExchangeRequest(publicToken))
          .execute();

      accessToken = plaidResponse.body().getAccessToken();
      itemId      = plaidResponse.body().getItemId();
    }
  }
}

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(client_id: 'PLAID_CLIENT_ID',
                      secret: 'PLAID_SECRET',
                      environment: '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)

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({
  clientID: 'PLAID_CLIENT_ID',
  secret: 'PLAID_SECRET',
  env: 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);

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({
  clientID: 'PLAID_CLIENT_ID',
  secret: 'PLAID_SECRET',
  env: 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);

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({
  clientID: 'PLAID_CLIENT_ID',
  secret: 'PLAID_SECRET',
  env: 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);

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

ParameterDescription
clientName
required
Displayed once a user has successfully linked their Item.
product
required
A list of Plaid product(s) you wish to use. Valid products are: transactions, auth, identity, income, assets, investments, liabilities, and payment_initiation. Only institutions that support all requested products will be shown. In Production, you will be billed for each product that you specify when initializing Link. If Link is launched with multiple countryCodes, only products that you are enabled for in all countries will be used by Link.

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 Sandbox, use development or sandbox, respectively. 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 to indicate that the user has reached 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.
language
required
Specify a Plaid-supported language to localize Link. English will be used by default.

Supported languages:
  • English ( 'en' )
  • French ( 'fr' )
  • Spanish ( 'es' )
  • Dutch ( 'nl' )
countryCodes
optional
Specify an array of Plaid-supported country codes using the ISO-3166-1 alpha-2 country code standard. Note that if you initialize with a European country code, your users will see the European consent panel during the Link flow.
webhook
optional
Specify a webhook to associate with an Item. Plaid fires a webhook when the Item requires updated credentials, when new data is available, or when Auth numbers have been successfully verified.
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 /item/public_token/create endpoint to generate a public_token for an Item.
isWebview
optional
Set to true if launching Link within a WebView.
linkCustomizationName
optional
Specify the name of a Link customization created in the Dashboard. The default customization is used if none is provided. Learn more
accountSubtypes
optional
Configures Link to return only accounts that are specified by these filters and only display institutions that support the specified subtypes. Must match the format:

{
  "<ACCOUNT_TYPE>": ["<ACCOUNT_SUBTYPE>"]
}
                      
Learn more
oauthNonce
optional
An oauthNonce is required to support OAuth authentication flows when launching or re-launching Link on a mobile device and using one or more European country codes. The nonce must be at least 16 characters long.
oauthRedirectUri
optional
An oauthRedirectUri is required to support OAuth authentication flows when launching Link on a mobile device and using one or more European country codes.
oauthStateId
optional
An oauthStateId is required to support OAuth authentication flows when re-launching Link on a mobile device and using one or more European country codes.
paymentToken
optional
A paymentToken must be specified if you are using the payment_initiation product. This will cause Link to open directly to the Payment Initiation flow.

Use the /payment_initiation/payment/token/create endpoint to generate a payment_token.

Note: Control whether or not your Link integration uses the Select Account view from the Dashboard.


Plaid Link for iOS is an embedabble framework that is bundled and distributed within your application. There are several ways to obtain the necessary files and keep them up-to-date, we recommend using CocoaPods or Carthage. Regardless of what you choose, submitting a new version of your application with the updated LinkKit.framework to the App Store is required.


For more information on how to install and set up the iOS Plaid Link integration, refer to our iOS docs.

There are two ways to configure Plaid Link for iOS:

  1. By creating a custom instance of PLKConfiguration and passing it to the PLKPlaidLinkViewController.
  2. By adding a custom entry named PLKPlaidLinkConfiguration to the Info.plist of the application and adding the following configuration items

Required configs

ConfigDescription
clientName
String
Displayed to the user once they have successfully linked their account
env
String
The API environment to use. see below
key
String
Your Plaid public_key available from the Plaid dashboard
product
String or Array of Strings
Select the Plaid products you would like to use, to learn more visit the Plaid Products page
Available API environments
  • sandbox: Stateful sandbox environment; use test credentials and build out and test your integration
  • development: Test your integration with live credentials; you will need to request access before you can use our Development environment
  • production: Production API environment; all requests are billed

Optional configs

ConfigDescription
webhook
String
The webhook will receive notifications once a userʼs transactions have been processed and are ready for use. The webhook must be a valid URL. For details refer to the Plaid API documentation.
oauthStateId
String
An oauthStateId is required to support OAuth authentication flows when re-launching Link using one or more European country codes.
oauthRedirectUri
String
An oauthRedirectUri is required to support OAuth authentication flows when launching Link and using one or more European country codes.
oauthNonce
String
An oauthNonce is required to support OAuth authentication flows when launching or re-launching Link and using one or more European country codes.
countryCodes
Array of Strings
Specify an array of Plaid-supported country codes. If used, a non-empty array must be supplied. If not used, the default is US-only.
language
String
Specify a Plaid-supported language to localize Link. English will be used by default.
Supported languages:
  • English ( 'en')
  • French ('fr')
  • Spanish ('es')
  • Dutch ('nl' )
linkCustomizationName
String
Specify the name of a Link customization created in the Dashboard. The default customization is used if none is provided. Learn more

Deprecated configs

The following configuration items have been deprecated and will be removed in a future release.

ConfigDescription
selectAccount
Boolean
Whether the user should select a specific account after successfully linking their bank account (default: NO ).
Note: Use the Select Account view from the Dashboard to control whether or not your Link integration uses the Select Account view

In the next example the values for clientName, key, and env will be set to the value of Xcode build settings, PRODUCT_NAME usually expands to the application name, the custom build settings LINK_KEY and LINK_ENV need to be added manually in Xcode should you want to use this approach. This allows use of a different key and env per build configurations (e.g. Debug, Release).

Edit Info PlistAdd Custom Build Setting

If you prefer using the commandline over adding the entries to your applicationʼs Info.plist manually, the following command adds what is necessary. Unless you are using the build settings based approach as outlined above replace $(PRODUCT_NAME), $(LINK_KEY), and $(LINK_ENV) with your specific values and replace "<PATH_TO_THE_APPLICATIONS>"/Info.plist with the path to your applicationʼs Info.plist.


/usr/libexec/PlistBuddy "<PATH_TO_THE_APPLICATIONS>"/Info.plist \
  -c 'Add PLKPlaidLinkConfiguration:clientName string $(PRODUCT_NAME)' \
  -c 'Add PLKPlaidLinkConfiguration:key string $(LINK_KEY)' \
  -c 'Add PLKPlaidLinkConfiguration:env string $(LINK_ENV)' \
  -c 'Add PLKPlaidLinkConfiguration:product string auth' \
  -c 'Add PLKPlaidLinkConfiguration:selectAccount bool NO'.sh

Implementation Steps

Plaid Link for iOS presents itself through the PLKPlaidLinkViewController class.

The steps to implement Plaid Link for iOS in your application are:

  1. Import LinkKit
  2. Adopt the PLKPlaidLinkViewDelegate protocol
  3. Implement the delegate methods
  4. Present the PLKPlaidLinkViewController

This section will only cover step 4 as that is the only difference between the legacy integration path and the new link_token integration path. To learn more about the earlier steps, visit the iOS docs.

PLKPlaidLinkViewController

Starting the Plaid Link for iOS experience is as simple as creating and presenting an instance of PLKPlaidLinkViewController.

Present PLKPlaidLinkViewController

// With shared configuration from Info.plist
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With shared configuration from Info.plist
id<PLKPlaidLinkViewDelegate> linkViewDelegate  = self;
PLKPlaidLinkViewController* linkViewController = [[PLKPlaidLinkViewController alloc] initWithDelegate:linkViewDelegate];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    linkViewController.modalPresentationStyle = UIModalPresentationFormSheet;
}
[self presentViewController:linkViewController animated:YES completion:nil];

// With shared configuration from Info.plist
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With shared configuration from Info.plist
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With shared configuration from Info.plist
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With shared configuration from Info.plist
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With shared configuration from Info.plist
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With shared configuration from Info.plist
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

When you would like to have more control over the configuration during runtime you can create an instance of PLKConfiguration and pass that during the initialization of the PLKPlaidLinkViewController.

Present PLKPlaidLinkViewController with custom configuration

// With custom configuration
let linkConfiguration = PLKConfiguration(key: "<#YOUR_PLAID_PUBLIC_KEY#>", env: .sandbox, product: .auth)
linkConfiguration.clientName = "Link Demo"
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(configuration: linkConfiguration, delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With custom configuration
PLKConfiguration<em> linkConfiguration;
@try {
    linkConfiguration = [[PLKConfiguration alloc] initWithKey:@"<#YOUR_PLAID_PUBLIC_KEY#>" env:PLKEnvironmentSandbox product:PLKProductAuth];
    linkConfiguration.clientName = @"Link Demo";
    id<PLKPlaidLinkViewDelegate> linkViewDelegate  = self;
    PLKPlaidLinkViewController</em> linkViewController = [[PLKPlaidLinkViewController alloc] initWithConfiguration:linkConfiguration delegate:linkViewDelegate];
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        linkViewController.modalPresentationStyle = UIModalPresentationFormSheet;
    }
    [self presentViewController:linkViewController animated:YES completion:nil];
} @catch (NSException *exception) {
    NSLog(@"Invalid configuration: %@", exception);
}

// With custom configuration
let linkConfiguration = PLKConfiguration(key: "<#YOUR_PLAID_PUBLIC_KEY#>", env: .sandbox, product: .auth)
linkConfiguration.clientName = "Link Demo"
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(configuration: linkConfiguration, delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With custom configuration
let linkConfiguration = PLKConfiguration(key: "<#YOUR_PLAID_PUBLIC_KEY#>", env: .sandbox, product: .auth)
linkConfiguration.clientName = "Link Demo"
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(configuration: linkConfiguration, delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With custom configuration
let linkConfiguration = PLKConfiguration(key: "<#YOUR_PLAID_PUBLIC_KEY#>", env: .sandbox, product: .auth)
linkConfiguration.clientName = "Link Demo"
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(configuration: linkConfiguration, delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With custom configuration
let linkConfiguration = PLKConfiguration(key: "<#YOUR_PLAID_PUBLIC_KEY#>", env: .sandbox, product: .auth)
linkConfiguration.clientName = "Link Demo"
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(configuration: linkConfiguration, delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With custom configuration
let linkConfiguration = PLKConfiguration(key: "<#YOUR_PLAID_PUBLIC_KEY#>", env: .sandbox, product: .auth)
linkConfiguration.clientName = "Link Demo"
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(configuration: linkConfiguration, delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

// With custom configuration
let linkConfiguration = PLKConfiguration(key: "<#YOUR_PLAID_PUBLIC_KEY#>", env: .sandbox, product: .auth)
linkConfiguration.clientName = "Link Demo"
let linkViewDelegate = self
let linkViewController = PLKPlaidLinkViewController(configuration: linkConfiguration, delegate: linkViewDelegate)
if (UI_USER_INTERFACE_IDIOM() == .pad) {
    linkViewController.modalPresentationStyle = .formSheet;
}
present(linkViewController, animated: true)

Here you find instructions on how to integrate and use Plaid Link for Android. At the center of it lies LinkSdk: an embeddable framework managing the details of linking an account with Plaid.

For more information on how to get up and running quickly with Plaid Link on Android, visit the android docs.

To integrate Link inside of your application, follow these steps:

  1. Initialize Plaid Link Instance
  2. Configure and open Link
  3. Handle Link responses

Note that only the second step is covered below since this is the only place where the public_key Link integration and the link_token integration path diverges. To learn more about the remaining steps, visit the Android docs.

When you want to open Link call Plaid.openLink() with the correct parameters for your integration and product use. See the Link parameter reference below for complete documentation on possible configurations. Whenever Link finishes, the result will be delivered back in the OnActivityResult of the calling Activity or Fragment.

MainActivity


import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

import com.plaid.link.Plaid
import com.plaid.link.linkConfiguration
import com.plaid.link.openPlaidLink
import com.plaid.link.configuration.AccountSubtype
import com.plaid.link.configuration.LinkLogLevel
import com.plaid.link.configuration.PlaidEnvironment
import com.plaid.link.configuration.PlaidProduct
import com.plaid.link.event.LinkEvent
import java.util.Locale

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Optional
    Plaid.setLinkEventListener { event -> Log.i("Event", event.toString()) }

    // Open Link – put this inside of a Button / Fab click listener
    this@MainActivity.openPlaidLink(
      linkConfiguration {
        // required
        clientName = "My Application name"
        products = listOf(PlaidProduct.TRANSACTIONS)
        environment = PlaidEnvironment.SANDBOX // Defaults to SANDBOX

        // optional
        accountSubtypeFilter = listOf(AccountSubtype.DEPOSITORY.CHECKING)
        countryCodes = listOf(Locale.US.country) // Defaults to US
        language = Locale.ENGLISH.language // Defaults to English
        linkCustomizationName = "Customization"
        logLevel = LinkLogLevel.WARN // Defaults to ASSERT
        paymentToken = "GENERATED_PAYMENT_TOKEN"
        publicKey = "PUBLIC_KEY"
        token = "GENERATED_TOKEN"
        userEmailAddress = "John Appleseed"
        userLegalName = "jappleseed@example.net"
        userPhoneNumber = "+1 (512) 555-1234"
        webhook = "https://requestb.in"
      }
    );
  }
}


import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

import com.plaid.link.Plaid
import com.plaid.link.linkConfiguration
import com.plaid.link.openPlaidLink
import com.plaid.link.configuration.AccountSubtype
import com.plaid.link.configuration.LinkLogLevel
import com.plaid.link.configuration.PlaidEnvironment
import com.plaid.link.configuration.PlaidProduct
import com.plaid.link.event.LinkEvent
import java.util.Locale

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Optional
    Plaid.setLinkEventListener { event -> Log.i("Event", event.toString()) }

    // Open Link – put this inside of a Button / Fab click listener
    this@MainActivity.openPlaidLink(
      linkConfiguration {
        // required
        clientName = "My Application name"
        products = listOf(PlaidProduct.TRANSACTIONS)
        environment = PlaidEnvironment.SANDBOX // Defaults to SANDBOX

        // optional
        accountSubtypeFilter = listOf(AccountSubtype.DEPOSITORY.CHECKING)
        countryCodes = listOf(Locale.US.country) // Defaults to US
        language = Locale.ENGLISH.language // Defaults to English
        linkCustomizationName = "Customization"
        logLevel = LinkLogLevel.WARN // Defaults to ASSERT
        paymentToken = "GENERATED_PAYMENT_TOKEN"
        publicKey = "PUBLIC_KEY"
        token = "GENERATED_TOKEN"
        userEmailAddress = "John Appleseed"
        userLegalName = "jappleseed@example.net"
        userPhoneNumber = "+1 (512) 555-1234"
        webhook = "https://requestb.in"
      }
    );
  }
}


import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

import com.plaid.link.Plaid
import com.plaid.link.linkConfiguration
import com.plaid.link.openPlaidLink
import com.plaid.link.configuration.AccountSubtype
import com.plaid.link.configuration.LinkLogLevel
import com.plaid.link.configuration.PlaidEnvironment
import com.plaid.link.configuration.PlaidProduct
import com.plaid.link.event.LinkEvent
import java.util.Locale

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Optional
    Plaid.setLinkEventListener { event -> Log.i("Event", event.toString()) }

    // Open Link – put this inside of a Button / Fab click listener
    this@MainActivity.openPlaidLink(
      linkConfiguration {
        // required
        clientName = "My Application name"
        products = listOf(PlaidProduct.TRANSACTIONS)
        environment = PlaidEnvironment.SANDBOX // Defaults to SANDBOX

        // optional
        accountSubtypeFilter = listOf(AccountSubtype.DEPOSITORY.CHECKING)
        countryCodes = listOf(Locale.US.country) // Defaults to US
        language = Locale.ENGLISH.language // Defaults to English
        linkCustomizationName = "Customization"
        logLevel = LinkLogLevel.WARN // Defaults to ASSERT
        paymentToken = "GENERATED_PAYMENT_TOKEN"
        publicKey = "PUBLIC_KEY"
        token = "GENERATED_TOKEN"
        userEmailAddress = "John Appleseed"
        userLegalName = "jappleseed@example.net"
        userPhoneNumber = "+1 (512) 555-1234"
        webhook = "https://requestb.in"
      }
    );
  }
}


import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

import com.plaid.link.Plaid
import com.plaid.link.linkConfiguration
import com.plaid.link.openPlaidLink
import com.plaid.link.configuration.AccountSubtype
import com.plaid.link.configuration.LinkLogLevel
import com.plaid.link.configuration.PlaidEnvironment
import com.plaid.link.configuration.PlaidProduct
import com.plaid.link.event.LinkEvent
import java.util.Locale

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Optional
    Plaid.setLinkEventListener { event -> Log.i("Event", event.toString()) }

    // Open Link – put this inside of a Button / Fab click listener
    this@MainActivity.openPlaidLink(
      linkConfiguration {
        // required
        clientName = "My Application name"
        products = listOf(PlaidProduct.TRANSACTIONS)
        environment = PlaidEnvironment.SANDBOX // Defaults to SANDBOX

        // optional
        accountSubtypeFilter = listOf(AccountSubtype.DEPOSITORY.CHECKING)
        countryCodes = listOf(Locale.US.country) // Defaults to US
        language = Locale.ENGLISH.language // Defaults to English
        linkCustomizationName = "Customization"
        logLevel = LinkLogLevel.WARN // Defaults to ASSERT
        paymentToken = "GENERATED_PAYMENT_TOKEN"
        publicKey = "PUBLIC_KEY"
        token = "GENERATED_TOKEN"
        userEmailAddress = "John Appleseed"
        userLegalName = "jappleseed@example.net"
        userPhoneNumber = "+1 (512) 555-1234"
        webhook = "https://requestb.in"
      }
    );
  }
}

import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;

import com.plaid.link.Plaid
import com.plaid.link.openPlaidLink;
import com.plaid.link.configuration.AccountSubtype;
import com.plaid.link.configuration.LinkConfiguration;
import com.plaid.link.configuration.LinkLogLevel;
import com.plaid.link.configuration.PlaidEnvironment;
import com.plaid.link.configuration.PlaidProduct;
import com.plaid.link.event.LinkEvent;
import java.util.Locale;
import kotlin.Unit;

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Optional
    Plaid.setLinkEventListener(linkEvent -> {
      Log.i("Event", linkEvent.toString());
      return Unit.INSTANCE;
    });

    // Open Link – put this inside of a Button / Fab click listener
    Plaid.openLink(
        this,
        new LinkConfiguration.Builder()
            .clientName("My Application name")
            .products(Arrays.asList(PlaidProduct.TRANSACTIONS))
            .environment(PlaidEnvironment.SANDBOX) // Defaults to SANDBOX
            .accountSubtypeFilter(Arrays.asList(AccountSubtype.DEPOSITORY.CHECKING.INSTANCE))
            .countryCodes(Arrays.asList(Locale.US.getCountry())) // Defaults to US
            .language(Locale.ENGLISH.getLanguage()) // Defaults to English
            .linkCustomizationName("Customization")
            .logLevel(LogLevel.WARN) // Defaults to ASSERT
            .paymentToken("GENERATED_PAYMENT_TOKEN")
            .publicKey("PUBLIC_KEY")
            .token("GENERATED_TOKEN")
            .userEmailAddress("John Appleseed")
            .userLegalName("jappleseed@example.net")
            .userPhoneNumber("+1 (512) 555-1234")
            .webhook("https://requestb.in")
            .build());
  }
}


import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

import com.plaid.link.Plaid
import com.plaid.link.linkConfiguration
import com.plaid.link.openPlaidLink
import com.plaid.link.configuration.AccountSubtype
import com.plaid.link.configuration.LinkLogLevel
import com.plaid.link.configuration.PlaidEnvironment
import com.plaid.link.configuration.PlaidProduct
import com.plaid.link.event.LinkEvent
import java.util.Locale

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Optional
    Plaid.setLinkEventListener { event -> Log.i("Event", event.toString()) }

    // Open Link – put this inside of a Button / Fab click listener
    this@MainActivity.openPlaidLink(
      linkConfiguration {
        // required
        clientName = "My Application name"
        products = listOf(PlaidProduct.TRANSACTIONS)
        environment = PlaidEnvironment.SANDBOX // Defaults to SANDBOX

        // optional
        accountSubtypeFilter = listOf(AccountSubtype.DEPOSITORY.CHECKING)
        countryCodes = listOf(Locale.US.country) // Defaults to US
        language = Locale.ENGLISH.language // Defaults to English
        linkCustomizationName = "Customization"
        logLevel = LinkLogLevel.WARN // Defaults to ASSERT
        paymentToken = "GENERATED_PAYMENT_TOKEN"
        publicKey = "PUBLIC_KEY"
        token = "GENERATED_TOKEN"
        userEmailAddress = "John Appleseed"
        userLegalName = "jappleseed@example.net"
        userPhoneNumber = "+1 (512) 555-1234"
        webhook = "https://requestb.in"
      }
    );
  }
}


import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

import com.plaid.link.Plaid
import com.plaid.link.linkConfiguration
import com.plaid.link.openPlaidLink
import com.plaid.link.configuration.AccountSubtype
import com.plaid.link.configuration.LinkLogLevel
import com.plaid.link.configuration.PlaidEnvironment
import com.plaid.link.configuration.PlaidProduct
import com.plaid.link.event.LinkEvent
import java.util.Locale

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Optional
    Plaid.setLinkEventListener { event -> Log.i("Event", event.toString()) }

    // Open Link – put this inside of a Button / Fab click listener
    this@MainActivity.openPlaidLink(
      linkConfiguration {
        // required
        clientName = "My Application name"
        products = listOf(PlaidProduct.TRANSACTIONS)
        environment = PlaidEnvironment.SANDBOX // Defaults to SANDBOX

        // optional
        accountSubtypeFilter = listOf(AccountSubtype.DEPOSITORY.CHECKING)
        countryCodes = listOf(Locale.US.country) // Defaults to US
        language = Locale.ENGLISH.language // Defaults to English
        linkCustomizationName = "Customization"
        logLevel = LinkLogLevel.WARN // Defaults to ASSERT
        paymentToken = "GENERATED_PAYMENT_TOKEN"
        publicKey = "PUBLIC_KEY"
        token = "GENERATED_TOKEN"
        userEmailAddress = "John Appleseed"
        userLegalName = "jappleseed@example.net"
        userPhoneNumber = "+1 (512) 555-1234"
        webhook = "https://requestb.in"
      }
    );
  }
}


import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity

import com.plaid.link.Plaid
import com.plaid.link.linkConfiguration
import com.plaid.link.openPlaidLink
import com.plaid.link.configuration.AccountSubtype
import com.plaid.link.configuration.LinkLogLevel
import com.plaid.link.configuration.PlaidEnvironment
import com.plaid.link.configuration.PlaidProduct
import com.plaid.link.event.LinkEvent
import java.util.Locale

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Optional
    Plaid.setLinkEventListener { event -> Log.i("Event", event.toString()) }

    // Open Link – put this inside of a Button / Fab click listener
    this@MainActivity.openPlaidLink(
      linkConfiguration {
        // required
        clientName = "My Application name"
        products = listOf(PlaidProduct.TRANSACTIONS)
        environment = PlaidEnvironment.SANDBOX // Defaults to SANDBOX

        // optional
        accountSubtypeFilter = listOf(AccountSubtype.DEPOSITORY.CHECKING)
        countryCodes = listOf(Locale.US.country) // Defaults to US
        language = Locale.ENGLISH.language // Defaults to English
        linkCustomizationName = "Customization"
        logLevel = LinkLogLevel.WARN // Defaults to ASSERT
        paymentToken = "GENERATED_PAYMENT_TOKEN"
        publicKey = "PUBLIC_KEY"
        token = "GENERATED_TOKEN"
        userEmailAddress = "John Appleseed"
        userLegalName = "jappleseed@example.net"
        userPhoneNumber = "+1 (512) 555-1234"
        webhook = "https://requestb.in"
      }
    );
  }
}

The table below describes the parameters of LinkConfiguration to configure the Android Link SDK.

ParameterDescription
clientName
String, required
Your company name which will be displayed for consent and after successfully linking an Item.
environment
List, required
The Plaid API environment on which to create user accounts.

Available environments:
  • Sandbox: PlaidEnvironment.SANDBOX
  • Development: PlaidEnvironment.DEVELOPMENT
  • Production: PlaidEnvironment.PRODUCTION
products
List, required
A list of Plaid product(s) you wish to use.

Valid products are:
  • Auth: PlaidProduct.AUTH
  • Transactions: PlaidProduct.TRANSACTIONS
  • Identity: PlaidProduct.IDENTITY
  • Income: PlaidProduct.INCOME
  • Assets: PlaidProduct.ASSETS
  • Investments: PlaidProduct.INVESTMENTS
  • Liabilities: PlaidProduct.LIABILITIES
accountSubtypeFilter
List, optional
Plaid will simply return all accounts that are of the specified subtypes. If you have the Select Account pane disabled through the developer dashboard, the filter will still apply; Furthermore, Link will display only the institutions that support the specified account subtype at the Institution Select pane.
countryCodes
List, optional
Specify an array of Plaid-supported country codes using the ISO-3166-1 alpha-2 country code standard. Accepted values must use the native Android Locale country.

Supported countries include:
  • Canada: Locale.CA.country
  • France: Locale.FR.country
  • Ireland: Locale.IE.country
  • Netherlands: Locale.NL.country
  • Spain: Locale.ES.country
  • United Kingdom: Locale.UK.country
  • United States: Locale.US.country
  • more coming soon
language
String, optional
Specify a Plaid-supported language to localize Link. Accepted values must use the native Android Locale Language. English will be used by default.

Supported languages:
  • English: Locale.ENGLISH.language
  • French: Locale.FRENCH.language
  • Spanish: Locale.SPANISH.language
  • Dutch: Locale.DUTCH.language
logLevel
String, optional
There are various logs within the plaid link sdk. Setting the loglevel will allow you to see those logs at the level you specify (or higher levels).

Supported log levels:
  • ASSERT
  • DEBUG
  • ERROR
  • INFO
  • VERBOSE
  • WARN
linkCustomizationName
String, optional
Specify the name of a Link customization created in the Dashboard. The default customization is used if none is provided. Learn more
paymentToken
String, optional
A paymentToken must be specified if you are using the payment_initiation product. This will cause Link to open directly to the Payment Initiation flow.

Use the /payment_initiation/payment/token/create endpoint to generate a payment_token.
public_key
String, optional
The public_key associated with your account; available from the Dashboard. This field is being deprecated in favor of using tokens (see below).
token
String, optional
Specify a 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 /item/public_token/create endpoint to generate a public_token for an Item.
userEmailAddress
String, optional
Specify a userEmailAddress to enable all Auth features. Note that userLegalName must also be set.
userLegalName
String, optional
Specify a userLegalName to enable all Auth features. Note that userEmailAddress must also be set.
userPhoneNumber
String, optional
The user’s phone number
Format: “+{country_code}{area code and subscriber number}”
e.g. “+14155555555” (known as E.164 format)
webhook
String, optional
Specify a webhook to associate with an Item. Plaid fires a webhook when the Item requires updated credentials, when new data is available, or when Auth numbers have been successfully verified.

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.

Plaid Link makes it easy for your user to update their credentials as necessary. Update mode enables an end-user to re-authenticate an Item, at which point Plaid will resolve that Item into a functioning state. Once an Item has been updated, data access will be restored and transaction updates, if you're using them, will automatically resume. Check out an overivew of the process below.

1

Plaid sends an Item error webhook to your app server

2

You make a request with an access_token to create a temporary public_token

3

You send the public_token to your client and have the user re-authenticate with Plaid

4

The onSuccess callback will indicate that the user has successfully re-authenticated

Attempting to initialize Link in update mode for an Item that is not in an error state will result in an ITEM_NO_ERROR error. You can use the /sandbox/item/reset_login endpoint to put an Item into an error state in the Sandbox.

To configure update mode, generate a public_token for the Item server-side and then use that public_token to initialize Link. The Item’s access_token will not change.

Resolve an Item error

// Create a one-time use public_token for the Item.
// This public_token can be used to initialize Link
// in update mode for the user
app.get('/create_public_token', function(request, response, next) {
  client.createPublicToken(ACCESS_TOKEN, function(err, res) {
    if(error != null) {
      console.log(msg + "\n" + JSON.stringify(err));
      response.json({error: JSON.stringify(err)}):
    } else {
      // Use the public_token to initialize Link
      var PUBLIC_TOKEN = res.public_token;
      response.json({public_token: PUBLIC_TOKEN});
    }
  });
});

# Create a one-time use public_token for the Item.
# This public_token can be used to initialize Link
# in update mode for the user.
get '/create_public_token' do
  public_token_response = client.item.public_token.create(access_token)
  content_type :json
  public_token_response.to_json
end

@app.route("/create_public_token", methods=['GET'])
def create_public_token():
    global access_token
    # Create a one-time use public_token for the Item.
    # This public_token can be used to initialize Link
    # in update mode for the user.
    response = client.Item.public_token.create(access_token)
    return jsonify(response)

curl -X POST https://sandbox.plaid.com/item/public_token/create   -H 'Content-Type: application/json'   -d '{
    "client_id": "CLIENT_ID",
    "secret": "SECRET",
    "access_token": "ACCESS_TOKEN"
  }'

import java.net.*;
import java.io.*;
import com.sun.net.httpserver.*;

import com.plaid.client;
import com.plaid.client.request.ItemPublicTokenCreateRequest;
import com.plaid.client.response.ItemPublicTokenCreateResponse;


public class PlaidExample {
  private static final String CLIENT_ID = "PLAID_CLIENT_ID";
  private static final String SECRET = "PLAID_SECRET";

  public static void main(String[] args) {
    HttpServer server = HttpServer.create(
      new InetSocketAddress("localhost", 8000), 0);
    server.createContext("/get_public_token", new GetPublicToken());
    hs.setExecutor(null);
    server.start();
  }

  static class GetPublicToken implements HttpHandler {
    private static PlaidClient plaidClient;
    private String publicToken;
    private String accessToken;

    public void handle(HttpExchange t) throws IOException {
      // Simplified psuedo-code for obtaining access_token
      InputStream is = t.getRequestBody();
      accessToken = is.accessToken();

      // Build your Plaid client
      PlaidClient plaidClient = PlaidClient.newBuilder()
        .clientIdAndSecret(CLIENT_ID, SECRET)
        .sandboxBaseUrl() // sandbox Plaid environment
        .logLevel(HttpLoggingInterceptor.Level.BODY)
        .build();

      // Use the access_token to create a public_token
      Response<ItemPublicTokenCreateResponse> response =
        plaidClient()
        .service()
        .itemPublicTokenCreate(
          new ItemPublicTokenCreateRequest(accessToken)
        ).execute();

      publicToken = response.body().getPublicToken();
    }
  }
}

// Create a one-time use public_token for the Item.
// This public_token can be used to initialize Link
// in update mode for the user
app.get('/create_public_token', function(request, response, next) {
  client.createPublicToken(ACCESS_TOKEN, function(err, res) {
    if(error != null) {
      console.log(msg + "\n" + JSON.stringify(err));
      response.json({error: JSON.stringify(err)}):
    } else {
      // Use the public_token to initialize Link
      var PUBLIC_TOKEN = res.public_token;
      response.json({public_token: PUBLIC_TOKEN});
    }
  });
});

// Create a one-time use public_token for the Item.
// This public_token can be used to initialize Link
// in update mode for the user
app.get('/create_public_token', function(request, response, next) {
  client.createPublicToken(ACCESS_TOKEN, function(err, res) {
    if(error != null) {
      console.log(msg + "\n" + JSON.stringify(err));
      response.json({error: JSON.stringify(err)}):
    } else {
      // Use the public_token to initialize Link
      var PUBLIC_TOKEN = res.public_token;
      response.json({public_token: PUBLIC_TOKEN});
    }
  });
});

// Create a one-time use public_token for the Item.
// This public_token can be used to initialize Link
// in update mode for the user
app.get('/create_public_token', function(request, response, next) {
  client.createPublicToken(ACCESS_TOKEN, function(err, res) {
    if(error != null) {
      console.log(msg + "\n" + JSON.stringify(err));
      response.json({error: JSON.stringify(err)}):
    } else {
      // Use the public_token to initialize Link
      var PUBLIC_TOKEN = res.public_token;
      response.json({public_token: PUBLIC_TOKEN});
    }
  });
});

Then initialize Link client-side with the newly generated public_token:

Initialize Link with Public Token

var handler = Plaid.create({
  clientName: 'Plaid Quickstart',
  env: 'sandbox',
  product: ['transactions'],
  key: 'PUBLIC_KEY',
  token: 'CREATED_PUBLIC_TOKEN',
  onSuccess: function(public_token, metadata) {},
  onExit: function(err, metadata) {},
  onEvent: function(eventName, metadata) {}
});

var handler = Plaid.create({
  clientName: 'Plaid Quickstart',
  env: 'sandbox',
  product: ['transactions'],
  key: 'PUBLIC_KEY',
  token: 'CREATED_PUBLIC_TOKEN',
  onSuccess: function(public_token, metadata) {},
  onExit: function(err, metadata) {},
  onEvent: function(eventName, metadata) {}
});

var handler = Plaid.create({
  clientName: 'Plaid Quickstart',
  env: 'sandbox',
  product: ['transactions'],
  key: 'PUBLIC_KEY',
  token: 'CREATED_PUBLIC_TOKEN',
  onSuccess: function(public_token, metadata) {},
  onExit: function(err, metadata) {},
  onEvent: function(eventName, metadata) {}
});

var handler = Plaid.create({
  clientName: 'Plaid Quickstart',
  env: 'sandbox',
  product: ['transactions'],
  key: 'PUBLIC_KEY',
  token: 'CREATED_PUBLIC_TOKEN',
  onSuccess: function(public_token, metadata) {},
  onExit: function(err, metadata) {},
  onEvent: function(eventName, metadata) {}
});

var handler = Plaid.create({
  clientName: 'Plaid Quickstart',
  env: 'sandbox',
  product: ['transactions'],
  key: 'PUBLIC_KEY',
  token: 'CREATED_PUBLIC_TOKEN',
  onSuccess: function(public_token, metadata) {},
  onExit: function(err, metadata) {},
  onEvent: function(eventName, metadata) {}
});

var handler = Plaid.create({
  clientName: 'Plaid Quickstart',
  env: 'sandbox',
  product: ['transactions'],
  key: 'PUBLIC_KEY',
  token: 'CREATED_PUBLIC_TOKEN',
  onSuccess: function(public_token, metadata) {},
  onExit: function(err, metadata) {},
  onEvent: function(eventName, metadata) {}
});

var handler = Plaid.create({
  clientName: 'Plaid Quickstart',
  env: 'sandbox',
  product: ['transactions'],
  key: 'PUBLIC_KEY',
  token: 'CREATED_PUBLIC_TOKEN',
  onSuccess: function(public_token, metadata) {},
  onExit: function(err, metadata) {},
  onEvent: function(eventName, metadata) {}
});

var handler = Plaid.create({
  clientName: 'Plaid Quickstart',
  env: 'sandbox',
  product: ['transactions'],
  key: 'PUBLIC_KEY',
  token: 'CREATED_PUBLIC_TOKEN',
  onSuccess: function(public_token, metadata) {},
  onExit: function(err, metadata) {},
  onEvent: function(eventName, metadata) {}
});

Link automatically handles the necessary API calls to update the Item. As we’ve noted, the Item's access_token does not change unless you explicitly rotate it. While you’re free to redo the storing and exchange token call, there’s no need to: The end-user has re-authenticated with the institution, and API product access calls should resume operating successfully.

To test Link’s update mode, you may want a to simulate putting an Item into an error state.

Note that Link will automatically configure itself to open with the user’s institution. Attempting to open Link with a specific institution in update mode will not work.

To do so, use the /sandbox/item/reset_login endpoint :

/sandbox/item/reset_login

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
  });
});

# 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)

  curl -X POST https://sandbox.plaid.com/sandbox/item/reset_login   -H 'Content-Type: application/json'   -d '{
    "client_id": "CLIENT_ID",
    "secret": "SECRET",
    "access_token": "ACCESS_TOKEN"
  }'

import java.net.*;
import java.io.*;
import com.sun.net.httpserver.*;

import com.plaid.client;
import com.plaid.client.request.SandboxItemResetLoginRequest;
import com.plaid.client.response.SandboxItemResetLoginResponse;


public class PlaidExample {
  private static final String CLIENT_ID = "PLAID_CLIENT_ID";
  private static final String SECRET = "PLAID_SECRET";

  public static void main(String[] args) {
    HttpServer server = HttpServer.create(
      new InetSocketAddress("localhost", 8000), 0);
    server.createContext("/reset_login", new ResetLogin());
    hs.setExecutor(null);
    server.start();
  }

  static class ResetLogin implements HttpHandler {
    private static PlaidClient plaidClient;
    private String accessToken;

    public void handle(HttpExchange t) throws IOException {
      // Simplified psuedo-code for obtaining access_token
      InputStream is = t.getRequestBody();
      accessToken = is.accessToken();

      // Build your Plaid client
      PlaidClient plaidClient = PlaidClient.newBuilder()
        .clientIdAndSecret(CLIENT_ID, SECRET)
        .sandboxBaseUrl() // sandbox Plaid environment
        .logLevel(HttpLoggingInterceptor.Level.BODY)
        .build();

      // Reset the item associated with the access_token
      Response<SandboxItemResetLoginResponse> response =
        plaidClient()
        .service()
        .sandboxItemResetLogin(
          new SandboxItemResetLoginRequest(accessToken)
        ).execute();
    }
  }
}

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
  });
});

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
  });
});

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
  });
});

OAuth Integration (EU Only)

Note: The following section is only relevant if you are initializing Link with one or more European country codes.

Some European institutions use an OAuth authentication flow, in which Plaid Link redirects the end user to their bank’s website or mobile app to authenticate. If you are initializing Link with one or more European country codes, your integration may require changes in order to support OAuth authentication flows.

Integration typeChanges required?
Desktop web browserNo
Mobile web browserYes
WebViewYes
Android SDKNo
iOS SDKYes
React Native for AndroidNo
React Native for iOSYes

If your integration requires changes, you will need to launch Link twice, once before and once after the OAuth redirect. The first time, you will need to provide two additional configuration parameters, oauthNonce and oauthRedirectUri. After the user completes the OAuth flow, Plaid will redirect back to your application via the oauthRedirectUri with a query parameter called oauth_state_id. To complete the Link flow, dismiss the first Link instance and re-initialize Link with two configuration parameters, the oauthNonce from the original Link initialization, as well as the oauthStateId from the oauth_state_id query parameter.

For security, the oauthNonce must be uniquely generated for each login and must be at least 16 characters long. We recommend using a UUID.

Before re-initializing Link, you should re-authenticate the end user to prevent a confused deputy problem. This can be accomplished by including one or more query parameters in your oauthRedirectUri. For example, you could include a parameter called user_id. Before re-initializing Link, you would check that the user_id in the redirect URI matches the user_id in your application state (e.g. a cookie).

Note that in mobile web browsers, if the end user has their bank’s mobile app installed, they will be redirected to the bank’s mobile app to authenticate, after which they will be redirected back to your web application in a new tab.

Allowed redirect URIs

To prevent open redirect attacks, your oauthRedirectUri must be configured through the developer dashboard. For security, the oauthRedirectUri cannot contain the oauthNonce.

App links

For mobile app integrations, the oauthRedirectUri must be registered as an app link to enable app-to-app authentication flows. You will need to configure an Android App Link or an Apple App Association File.


Payment Initiation (Europe)

The UK Payment Initiation API enables payment transfers within your app. Plaid supports both domestic payments denominated in pound sterling (typically via the Faster Payments network, although this is up to the institution) and international payments denominated in euro (typically via SEPA Credit Transfer). Each time a client wants to receive a payment, the end user must authorize the payment in Link before the payment can be initiated.

Note: The revised EU Directive on Payment Services ("PSD2") regulations require strong customer authentication ("SCA") for each payment order.

Initializing Link

To initialize Link for Payment Initiation, set payment_initiation as the only product and include the payment token. If an item has previously been created for the end user making the payment, a public_token can be included to initialize Link directly to the institution associated with the existing Item.

Refer to the Payment Initiation section of the main docs for more context on how to create a payment initiation recipient and payment resource.

Create payment token request

POST /payment_initiation/payment/token/create

The payment_token will allow for at most one payment initiation. If this attempt fails, the end user aborts the flow, or the token expires, the developer will need to create a new payment token. Creating a new payment token does not require end user input.

FieldRequired?Description
client_id
String
yesYour client_id.
secret
String
yesYour secret.
payment_id
String
yesThe payment_id returned from /payment_initiation/payment/create.
Create payment token request

client.createPaymentToken(paymentID, (err, response) => {
// Handle err
var paymentToken = response.payment_token;
var paymentTokenExpirationTime = response.payment_token_expiration_time;
});

curl -X POST https://sandbox.plaid.com/payment_initiation/payment/token/create \
-H 'Content-Type: application/json' \
-d '{
"client_id": String,
"secret": String,
"payment_id": String
}'

response = @client.payment_initiation.create_payment_token(@payment_id)
payment_token = response.payment_token
payment_token_expiration_time = response.payment_token_expiration_time

Response<PaymentTokenCreateResponse> createPaymentTokenResponse =
      client()
      .service()
      .paymentTokenCreate(
        new PaymentTokenCreateRequest(paymentId)
      ).execute();

response = client.PaymentInitiation.create_payment_token(
    payment_id,
)
payment_token = response['payment_token']
payment_token_expiration_time = response['payment_token_expiration_time']

client.createPaymentToken(paymentID, (err, response) => {
// Handle err
var paymentToken = response.payment_token;
var paymentTokenExpirationTime = response.payment_token_expiration_time;
});

client.createPaymentToken(paymentID, (err, response) => {
// Handle err
var paymentToken = response.payment_token;
var paymentTokenExpirationTime = response.payment_token_expiration_time;
});

client.createPaymentToken(paymentID, (err, response) => {
// Handle err
var paymentToken = response.payment_token;
var paymentTokenExpirationTime = response.payment_token_expiration_time;
});
Create payment token response

http code 200
{
"payment_token": "payment-token-sandbox-feca8a7a-5591-4aef-9297-f3062bb735d3",
"payment_token_expiration_time": "2020-01-01T00:00:00Z",
"request_id": "4ciYVmesrySiUAB"
}