Plaid Quickstart

repository·master·Indexed 20 days ago

https://github.com/plaid/quickstart

A comprehensive reference implementation demonstrating Plaid's products and client libraries. It features a React frontend and supports multiple backend languages, including Node, Python, Ruby, Go, and Java. The project includes tools for managing application state via QuickstartProvider and utility functions to transform raw Plaid API responses into UI-ready data formats.

Tokens
11.8K
Snippets
54
Records
59
Agent score
73%

What's inside Plaid Quickstart

  1. Test OAuth with a redirect URI and HTTPS

    master

    To test the OAuth flow in Sandbox with a redirect URI, set PLAID_REDIRECT_URI=http://localhost:3000/ in your .env and register this URI in the Plaid Dashboard.

    To test OAuth in Production, you must use HTTPS. You can use mkcert to generate local certificates:

    1. Install mkcert and generate certificates in the frontend folder:
      cd frontend
      brew install mkcert
      mkcert -install
      mkcert localhost
    2. Update frontend/vite.config.ts to use the generated localhost.pem and localhost-key.pem files.
    import fs from "fs";
    
    // inside the server config in vite.config.ts:
    server: {
      port: 3000,
      https: {
        cert: fs.readFileSync("localhost.pem"),
        key: fs.readFileSync("localhost-key.pem"),
      },
      // ... existing proxy config
    }
  2. Clone the Plaid Quickstart repository

    master

    Clone the repository using HTTPS or SSH.

    Windows Users: This repository uses symbolic links. Ensure you enabled symbolic links during Git installation. If you cannot clone normally, use the following command in a Git Bash terminal opened as an administrator:

    git clone -c core.symlinks=true https://github.com/plaid/quickstart
    git clone https://github.com/plaid/quickstart
    cd quickstart
  3. Run the Plaid Quickstart backend

    master

    The Quickstart supports multiple backend languages. Each backend runs on http://localhost:8000. Choose the directory corresponding to your preferred language and follow the specific commands.

    ##### Node
    ```bash
    $ cd ./node
    $ npm install
    $ ./start.sh
    Python
    cd ./python
    # If using virtualenv:
    # virtualenv venv
    # source venv/bin/activate
    
    pip3 install -r requirements.txt
    ./start.sh
    Ruby
    cd ./ruby
    bundle
    ./start.sh
    Go
    cd ./go
    go build
    ./start.sh
    Java
    cd ./java
    mvn clean package
    ./start.sh
  4. Use DataItem for standardized product data

    master
    The DataItem type is a union type that represents the common structure for various Plaid product data points. When using the transformation functions, the returned objects will conform to one of the specific interfaces contained within DataItem (e.g., AuthDataItem, TransactionsDataItem, IdentityDataItem). This allows for a unified way to handle different types of financial data in the UI.
  5. Sync Transactions using a Cursor

    master

    The TransactionsSync endpoint is the recommended way to retrieve transaction updates. It uses a cursor to track the state of the transaction data.

    To get all historical updates, start with an empty cursor. After each request, the response provides a next_cursor. You should pass this next_cursor into your subsequent request to fetch the next page of updates. Continue this loop until has_more is false.

    var cursor *string
    for hasMore {
        request := plaid.NewTransactionsSyncRequest(accessToken)
        if cursor != nil {
            request.SetCursor(*cursor)
        }
        resp, _, err := client.PlaidApi.TransactionsSync(ctx).TransactionsSyncRequest(*request).Execute()
        
        // Update cursor for the next iteration
        nextCursor := resp.GetNextCursor()
        cursor = &nextCursor
        hasMore = resp.GetHasMore()
    }
  6. Poll for asynchronous API results

    master

    When calling APIs that are not immediately ready (e.g., Asset Reports or CRA reports), you may encounter a PRODUCT_NOT_READY error. Use a retry loop to poll the endpoint. The provided poll_with_retries pattern checks if the error is retryable (either PRODUCT_NOT_READY or a 5xx server error) before attempting again after a delay.

    def poll_with_retries(request_callback, ms=1000, retries_left=20):
        while retries_left > 0:
            try:
                return request_callback()
            except plaid.ApiException as e:
                # Check if error_code is 'PRODUCT_NOT_READY' or status >= 500
                # ... retry logic
  7. Polling Pattern for Asynchronous Reports

    master

    Since many Plaid reports (like Asset Reports or CRA reports) are generated asynchronously, you should implement a polling mechanism. A common pattern is to retry the request if the error code is PRODUCT_NOT_READY or if a 5xx server error occurs.

    const pollWithRetries = (requestCallback, ms = 1000, retriesLeft = 20) =>
      new Promise((resolve, reject) => {
        requestCallback()
          .then(resolve)
          .catch((error) => {
            const errorCode = error?.response?.data?.error_code;
            const statusCode = error?.response?.status;
            const isRetryable = errorCode === 'PRODUCT_NOT_READY' || (statusCode >= 500 && statusCode < 600);
            
            if (!isRetryable || retriesLeft === 1) {
              return reject(error);
            }
            
            setTimeout(() => {
              pollWithRetries(requestCallback, ms, retriesLeft - 1).then(resolve).catch(reject);
            }, ms);
          });
      });
  8. Start the Ruby backend server

    master

    To start the Ruby backend server, execute the start.sh shell script. This script uses bundle exec to run the app.rb entrypoint, ensuring the application runs within the context of its configured Ruby gems.

    ./ruby/start.sh
  9. Initialize the Plaid Client

    master

    To use the Plaid Node.js SDK, create a Configuration object specifying the basePath (using PlaidEnvironments) and provide your PLAID-CLIENT-ID and PLAID-SECRET in the baseOptions.headers. Then, instantiate PlaidApi with this configuration.

    const { Configuration, PlaidApi, PlaidEnvironments } = require('plaid');
    
    const configuration = new Configuration({
      basePath: PlaidEnvironments[PLAID_ENV],
      baseOptions: {
        headers: {
          'PLAID-CLIENT-ID': PLAID_CLIENT_ID,
          'PLAID-SECRET': PLAID_SECRET,
          'Plaid-Version': '2020-09-14',
        },
      },
    });
    
    const client = new PlaidApi(configuration);