petra-plaid-python

Simple Python API client for Plaid -- modified by Petra


Keywords
api, client, plaid
License
MIT
Install
pip install petra-plaid-python==1.4.0

Documentation

plaid-python Build Status

The official python client library for the Plaid API.

This module was recently refactored and released with breaking changes as version 1.0.x.

Table of Contents

Install

Via pip:

pip install plaid-python

Via source:

git clone git@github.com:plaid/plaid-python.git
python setup.py install

Documentation

The module supports all Plaid API endpoints. For complete information about the API, head to the docs.

Getting Started

Configuration

from plaid import Client

Client.config({
    'url': 'https://tartan.plaid.com'
})

By default, all non-200 responses will throw an error.

For more information on Plaid response codes, head to codes.

from plaid import Client
from plaid import errors as plaid_errors


client = Client(client_id='***', secret='***')
try:
    response = client.connect('bofa', {
        'username': '[something_invalid]',
        'password': '***'
    })
except plaid_errors.UnauthorizedError:
     # handle this

If you would prefer to handle non-20x status codes yourself, you can configure the client to suppress these exceptions

import json

from plaid import Client

Client.config({
    'url': 'https://tartan.plaid.com',
    'suppress_http_errors': True,
})

client = Client(client_id='***', secret='***')

response = client.connect('bofa', {
    'username': '[something_invalid]',
    'password': '***'
})

if response.ok:
    user = response.json()
else:
    # handle non-20x status codes

Public Endpoints

Public endpoints (category and institution information) require no authentication and can be accessed as follows:

from plaid import Client
from plaid import errors as plaid_errors
from plaid.utils import json


client = Client(client_id='***', secret='***')
institutions = client.institutions().json()
categories = client.categories().json()

Authenticated Endpoints

Authenticated endpoints require a valid client_id and secret to access. You can use the sandbox client_id and secret for testing (test_id and test_secret) during development mode.

Add Connect user

from plaid import Client
from plaid import errors as plaid_errors
from plaid.utils import json


client = Client(client_id='***', secret='***')
account_type = 'bofa'

try:
    response = client.connect(account_type, {
     'username': '***',
     'password': '***'
    })
except plaid_errors.PlaidError:
     pass
else:
    connect_data = response.json()

MFA add Connect User

from plaid import Client
from plaid import errors as plaid_errors
from plaid.utils import json


client = Client(client_id='***', secret='***')
account_type = 'bofa'

try:
    response = client.connect(account_type, {
     'username': '***',
     'password': '***'
    })
except plaid_errors.PlaidError, e:
     pass
else:
    if response.status_code == 200:
        # User connected
        data = response.json()
    elif response.stat_code == 201:
        # MFA required
        try:
            mfa_response = answer_mfa(response.json())
        except plaid_errors.PlaidError, e:
            pass
        else:
            # check for 200 vs 201 responses
            # 201 indicates that additional MFA steps required


def answer_mfa(data):
    if data['type'] == 'questions':
        # Ask your user for the answer to the question[s].
        # Although questions is a list, there is only ever a
        # single element in this list, at present
        return answer_question([q['question'] for q in data['mfa']])
    elif data['type'] == 'list':
        return answer_list(data['mfa'])
    elif data['type'] == 'selection':
        return answer_selections(data['mfa'])
    else:
        raise Exception('Unknown mfa type from Plaid')


def answer_question(questions):
    # We have magically inferred the answer
    # so we respond immediately
    # In the real world, we would present questions[0]
    # to our user and submit their response
    answer = 'dogs'
    return client.connect_step(account_type, answer)


def answer_list(devices):
    # You should specify the device to which the passcode is sent.
    # The available devices are present in the devices list
    return client.connect_step('bofa', None, options={
        'send_method': {'type': 'phone'}
    })


def answer_selections(selections):
    # We have magically inferred the answers
    # so we respond immediately
    # In the real world, we would present the selection
    # questions and choices to our user and submit their responses
    # in a JSON-encoded array with answers provided
    # in the same order as the given questions
    answer = json.dumps(['Yes', 'No'])
    return client.connect_step(account_type, answer)

Add Auth User

Effectively the same as Connect.

client = Client(client_id='***', secret='***')
response = client.auth('bofa', {
    'username': '***',
    'password': '***'
})

MFA add Auth User

Effectively the same as Connect.

client = Client(client_id='***', secret='***')
response = client.auth('bofa', {
    'username': '***',
    'password': '***'
})

mfa_response = client.auth_step('bofa', 'my_answer')

Upgrade Account

Add a product (auth or connect to the user)

client = Client(client_id='***', secret='***', access_token='usertoken')
response = client.upgrade('connect')

Delete User

client = Client(client_id='***', secret='***', access_token='usertoken')

client.connect_delete()  ## deletes Connect user

# OR

client.auth_delete()  ## deletes Auth user

Exchange

Exchange a public_token from Plaid Link for a Plaid access token and then retrieve account data:

client = Client(client_id='***', secret='***')
response = client.exchange_token('test,chase,connected')
# client.access_token should now be populated with a
# valid access_token;  we can make authenticated requests
client.auth('chase', {
    'username': '***',
    'password': '***'
})

Get Accounts

User previously Auth-ed

client = Client(client_id='***', secret='***', access_token='usertoken')
accounts = client.auth_get().json()

Get Account Balances

User previously added

client = Client(client_id='***', secret='***', access_token='usertoken')
response = client.balance()

Get Transactions

User previously Connect-ed

client = Client(client_id='***', secret='***', access_token='usertoken')
response = client.connect_get()
transactions = response.json()

Get Info

User previously Info-ed

client = Client(client_id='***', secret='***', access_token='usertoken')
response = client.info_get()
info = response.json()

Get Income

User previously Income-ed

client = Client(client_id='***', secret='***', access_token='usertoken')
response = client.income_get()
income = response.json()

Get Risk

User previously Risk-ed

client = Client(client_id='***', secret='***', access_token='usertoken')
response = client.risk_get()
risk = response.json()

Attribution & Maintenance

This repository was originally authored by Chris Forrette. Version 1.0.0 was authored by Ben Plesser.

Support

Open an issue!

Known Issues

  1. SSLError: EOF occurred in violation of protocol (_ssl.c:581)(https://github.com/plaid/plaid-python/issues/62) - Work around is installing pyopenssl ndg-httpsclient pyasn1

Contribute

All pull requests should be linted with flake8 and tested by running:

$ make test

Contributors

License

MIT