title: Connect plaid.io with django
body: <p>I'm just trying to connect <code>plaid.io</code> with <code>Django</code>.
  To do that, I'm using the examples.</p>
  
  <p><a href="https://github.com/plaid/quickstart/tree/master/python" rel="nofollow noreferrer">https://github.com/plaid/quickstart/tree/master/python</a></p>
  
  <p><strong>server.py</strong></p>
  
  <pre><code>import os
  import datetime
  import plaid
  from flask import Flask
  from flask import render_template
  from flask import request
  from flask import jsonify
  
  app = Flask(__name__)
  
  
  # Fill in your Plaid API keys - https://dashboard.plaid.com/account/keys
  PLAID_CLIENT_ID = 'xxxxxxxxxxxxxx'
  PLAID_SECRET = 'xxxxxxxxxxxxxx'
  PLAID_PUBLIC_KEY = 'xxxxxxxxxxxxxx'
  # Use 'sandbox' to test with Plaid's Sandbox environment (username: user_good,
  # password: pass_good)
  # Use `development` to test with live users and credentials and `production`
  # to go live
  PLAID_ENV='sandbox'
  
  
  client = plaid.Client(client_id = PLAID_CLIENT_ID, secret=PLAID_SECRET,
                    public_key=PLAID_PUBLIC_KEY, environment=PLAID_ENV)
  
  @app.route("/")
  def index():
     return render_template('index.ejs', plaid_public_key=PLAID_PUBLIC_KEY, plaid_environment=PLAID_ENV)
  
  
  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']
  
    access_token = exchange_response['access_token']
  
    return jsonify(exchange_response)
  
  @app.route("/set_access_token", methods=['POST'])
  def set_access_token():
    global access_token
    access_token = request.form['access_token']
    # print 'access token: ' + access_token
    return jsonify({'error': False})
  
  @app.route("/accounts", methods=['GET'])
  def accounts():
    global access_token
    accounts = client.Auth.get(access_token)
    return jsonify(accounts)
  
  @app.route("/item", methods=['GET', 'POST'])
  def item():
    global access_token
    item_response = client.Item.get(access_token)
    institution_response = client.Institutions.get_by_id(item_response['item']['institution_id'])
    return jsonify({'item': item_response['item'], 'institution': institution_response['institution']})
  
  @app.route("/transactions", methods=['GET', 'POST'])
  def transactions():
    global access_token
    # Pull transactions for the last 30 days
    start_date = "{:%Y-%m-%d}".format(datetime.datetime.now() + datetime.timedelta(-30))
    end_date = "{:%Y-%m-%d}".format(datetime.datetime.now())
  
    response = client.Transactions.get(access_token, start_date, end_date)
    return jsonify(response)
  
  @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)
  
  if __name__ == "__main__":
      app.run()
  </code></pre>
  
  <p><strong>index.ejs</strong></p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html lang="en"&gt;
  &lt;head&gt;
      &lt;meta charset="UTF-8"&gt;
      &lt;title&gt;Plaid Walkthrough Example&lt;/title&gt;
      &lt;link rel="stylesheet" type="text/css" href="static/style.css"&gt;
      &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
  &lt;/head&gt;
  &lt;body&gt;
      &lt;div id="banner"&gt;
          &lt;h1&gt;Plaid Example Walkthrough&lt;/h1&gt;
          &lt;p id="intro"&gt;
              This is an example application that walks through integrating Plaid Link using the API to retrieve Auth and Transaction data.
          &lt;/p&gt;
          &lt;p id="steps"&gt;
              Great - you just created an Item! The server was successfully able to exchange the public_token for an access_token.
              Below are a few options - you can get account data, retrieve information about the Item itself, or pull transaction data.
          &lt;/p&gt;
      &lt;/div&gt;
  
      &lt;div id="container"&gt;
          &lt;p&gt;
              Click the button below to open a list of Institutions - after you select one,
              you'll be guided through an authentication process. The public_token will be passed
              back to the example server, which will then exchange it for an access_token and log it
              to your console.
          &lt;/p&gt;
  
          &lt;button id="link-btn"&gt;Open Link&lt;/button&gt;
      &lt;/div&gt;
  
      &lt;div id="app"&gt;
          &lt;div class="box"&gt;
              &lt;button id="get-accounts-btn"&gt;Get Accounts&lt;/button&gt;
              &lt;div id="get-accounts-data"&gt;&lt;/div&gt;
          &lt;/div&gt;
  
          &lt;div class="box"&gt;
              &lt;button id="get-item-btn"&gt;Get Item&lt;/button&gt;
              &lt;div id="upgrade-to-connect-data" class="inner"&gt;&lt;/div&gt;
          &lt;/div&gt;
  
          &lt;div class="box" id="txnBox"&gt;
              &lt;button id="get-transaction-data"&gt;Get Transactions&lt;/button&gt;
              &lt;div id="get-transactions-data"&gt;&lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js"&gt;&lt;/script&gt;
      &lt;script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"&gt;&lt;/script&gt;
      &lt;script&gt;
      function getParameterByName(name, url) {
          if (!url) url = window.location.href;
          name = name.replace(/[\[\]]/g, "\\$&amp;");
          var regex = new RegExp("[?&amp;]" + name + "(=([^&amp;#]*)|&amp;|#|$)"),
              results = regex.exec(url);
          if (!results) return null;
          if (!results[2]) return '';
          return decodeURIComponent(results[2].replace(/\+/g, " "));
      }
      ;(function($) {
          var handler = Plaid.create({
              apiVersion: 'v2',
              clientName: 'Plaid Walkthrough Demo',
              env: '{{ plaid_environment }}',
              product: ['transactions'],
              key: '{{ plaid_public_key }}',
              onSuccess: function(public_token) {
                  $.post('/get_access_token', {public_token: public_token}, function() {
                      $('#container').fadeOut('fast', function() {
                          $('#intro').hide();
                          $('#app, #steps').fadeIn('slow');
                      });
                  });
              },
          });
  
          $('#link-btn').on('click', function(e) {
              handler.open();
          });
  
          var accessToken =  getParameterByName('access_token');
          if (accessToken != null) {
              $.post('/set_access_token', {access_token: accessToken}, function() {
                  $('#container').fadeOut('fast', function() {
                      $('#intro').hide();
                      $('#app, #steps').fadeIn('slow');
                  });
              });
          }
  
          $('#get-accounts-btn').on('click', function(e) {
              $.get('/accounts', function(data) {
                  $('#get-accounts-data').slideUp(function() {
                      var html = '';
                      data.accounts.forEach(function(account, idx) {
                          html += '&lt;div class="inner"&gt;';
                          html += '&lt;strong&gt;' + account.name +
                                  ' $' + (account.balances.available != null ? account.balances.available : account.balances.current) + '&lt;/strong&gt;&lt;br&gt;';
                          html += account.subtype + ' ' + account.mask;
                          html += '&lt;/div&gt;';
                      });
  
                      $(this).html(html).slideDown();
                  });
              });
          });
  
          $('#get-item-btn').on('click', function(e) {
              $.post('/item', function(data) {
                  $('#upgrade-to-connect-data').slideUp(function() {
                      if(data.error)
                          $(this).html('&lt;p&gt;' + data.error + '&lt;/p&gt;').slideDown();
                      else {
                          var html = '';
                          html += '&lt;p&gt;Here\'s some basic information about your Item:&lt;/p&gt;';
                          html += '&lt;p&gt;Institution name:' + data.institution.name +'&lt;/p&gt;';
                          html += '&lt;p&gt;Billed products: ' + data.item.billed_products.join(', ') + '&lt;/p&gt;';
                          html += '&lt;p&gt;Available products: ' + data.item.available_products.join(', ') + '&lt;/p&gt;';
  
  
                          $(this).html(html).slideDown();
                          $('#txnBox').slideDown();
                      }
                  });
              });
          });
  
          $('#get-transaction-data').on('click', function(e) {
              $.post('/transactions', function(data) {
                  if (data.error) {
                      $(this).html('&lt;p&gt;' + data.error + '&lt;/p&gt;').slideDown();
                  } else {
                  $('#get-transactions-data').slideUp(function() {
                      var html = '&lt;p&gt;Pulled ' + data.transactions.length + ' transaction(s).&lt;/p&gt;';
                      data.transactions.forEach(function(txn, idx) {
                          html += '&lt;div class="inner"&gt;';
                          html += '&lt;strong&gt;' + txn.name + '&lt;/strong&gt;&lt;br&gt;';
                          html += '$' + txn.amount;
                          html += '&lt;br&gt;&lt;em&gt;' + txn.date + '&lt;/em&gt;';
                          html += '&lt;/div&gt;';
                      });
  
                      $(this).slideUp(function() {
                          $(this).html(html).slideDown();
                      });
                  });
                  }
              });
          });
      })(jQuery);
      &lt;/script&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>This is exactly the same example, with my tokens.</p>
  
  <p>But in the terminal appears the next messages:</p>
  
  <blockquote>
    <p>sandbox.plaid.com/link/client/get Failed to load resource: the server
    responded with a status of 400 (Bad Request) link.js:125 Error: Error
    retrieving info for public key. Make sure that the entered key is
    correct. If the error persists, contact support@plaid.com.
        at link.js:125 (anonymous) @ link.js:125 cdn.plaid.com/authenticate Failed to load resource: the server
    responded with a status of 403 (Forbidden)</p>
  </blockquote>
  
  <p>Why I'm getting the <code>400 Bad Request Message</code> ?</p>