Integrating Pinwheel with your Plaid account
Overview
In order to identify an end user's recurring bills and subscriptions, Pinwheel needs access to transaction data from external user accounts that those bills are paid out of. Pinwheel supports the Plaid banking aggregator for retrieving transaction data from external bank and credit card accounts.
This document details the implementation steps required to allow Pinwheel to access transaction data through your account as a Plaid partner. Plaid partners get access via Plaid Processor tokens, which are tightly scoped to allow a specific partner access to a specific data stream (in this case, transaction data).
In order to facilitate this access, here are the requirements needed for Pinwheel to successfully integrate your Plaid account/connection. This includes analyzing existing connected accounts for the user and connecting new accounts within the user experience.
Step 1: Whitelist redirect URIs
- Log in to your Plaid dashboard and navigate to the Developers -> API section.
- Next, in the Allowed Redirect URIs section, click Configure
- Add the following redirect URI, substituting {customer name} with a value we'll provide before onboarding.
- https://*.subscriptions.widget.getpinwheel.com/scan-accounts/{customer name}
Step 2: Enable processors
- While still in your Plaid dashboard, navigate to Developers -> Integrations.
- Enable the Pinwheel integration.
Step 3: Set up APIs that can be called by Pinwheel
Step 3a: Create an API to create and return a Plaid link token for a given user
If the end user has not yet connected external accounts within your app already, Pinwheel will need a Plaid link token to facilitate connecting a new account. To this end, Pinwheel requires an API endpoint that will provide a Plaid link token for the user.
The API endpoint should be a POST endpoint that accepts a JSON schema as input. See Authorization below for notes on securing the endpoint.
Example path: POST https://<url>/.../plaid/link_tokens
Pinwheel will provide the values for all five of the fields in this request:
{
"end_user_id":"<end_user_id>",
"webhook":"<webhook>",
"redirect_uri":"<redirect_uri>",
"completion_redirect_uri":"<completion_redirect_uri>", // optional
"is_mobile_app":<true|false>
}
The endpoint you build will make a call to Plaid's Link Token Create API using the above data as input. The following configuration is also necessary:
- Enable Product transactions
- Add Account filters:
- Depository; checking & saving
- Credit; credit cards
- Request 730 days of data for proper recurring transaction analysis.
- Include the supplied webhook and redirect_uri in the top level
- Add a hosted_link object including the supplied completion_redirect_uri and set the flag is_mobile_app to the value of
is_mobile_appsent in the request.- If completion_redirect_uri is not present, just use an empty string when configuring the hosted_link
The API's response body should be a JSON object that contains the link token and the hosted link URL:
{
"plaid_link_token": "<link_token>",
"hosted_link_url":"<hosted_link_url>"
}
See Appendix for code sample implementing this endpoint
Step 3b: Create an API to exchange public token for processor tokens
Once the user has connected to their bank or credit card platform, Plaid returns a public_token to Pinwheel. This next API endpoint will receive this public_token from Pinwheel, and return one or more processor_tokens back to Pinwheel. It is these processor tokens that Pinwheel will use to retrieve the transaction data necessary to identify recurring bills.
The API endpoint should be a POST endpoint that accepts a JSON schema as input. See Authorization below for notes on securing the endpoint.
Example path: POST https://<url>/.../plaid/processor_tokens
Pinwheel will provide the value for the public_token in this request as well as the end_user_id:
{
"end_user_id":"<end_user_id>",
"public_token":"<public_token>",
}
This API will take the provided public token and exchange it for an access token using the Plaid public token exchange endpoint.
With the access token, you can now retrieve the list of accounts associated with this access token using the Plaid accounts/get endpoint.
Finally, for each account, you will create a processor token using Plaid's processor token create endpoint.
We recommend storing both the access token and the processor tokens for later use. The third API endpoint (see below) returns existing processor tokens that have already been created; this saves the user from having to connect to their account on subsequent visits.
The API endpoint should return the processor tokens using this JSON schema:
{
"pinwheel": {
"processor_tokens": [...], // array of strings
}
}
See Appendix for code sample implementing this endpoint
Step 3c: Create an API to return all processor tokens for a user
This third endpoint simply returns any processor tokens that are already available for the given user.
The API endpoint should be a GET endpoint that includes a user ID in the path or query string. See Authorization below for notes on securing the endpoint.
Example path: GET https://<url>/.../plaid/processor_tokens?end_user_id=<end_user_id>
Pinwheel will provide the value for the end_user_id.
This API should simply return any processor tokens that have already been created and stored for the given user. Note that if the user has already connected an external account for a different purpose, processor tokens can be generated on the fly for Pinwheel (exactly as in the previous API), so long as you have stored the access token associated with the user's bank or credit card vendor.
The API endpoint should return the processor tokens using this JSON schema:
{
"pinwheel": {
"processor_tokens": [...], // array of strings
}
}
Authorization
To secure these endpoints, we recommend a simple shared-secret approach as described below, optionally augmented with IP whitelisting that rejects requests from any unknown IP address. However, Pinwheel can usually accommodate whatever authorization scheme is in place for any existing public APIs you have already implemented. Please flag this for us during implementation kickoff if the shared secret approach is not viable.
Shared secret
In this scheme, you will provide Pinwheel with a secret during implementation time. Pinwheel offers both sandbox and production environments, so a separate secret is required for each.
Pinwheel will send the secret in the x-api-key header in all API requests:
"x-api-key": "{secret}"
Appendix: API code samples
Sample code for Plaid Link Token endpoint
solution = 'Bill Switch' # or 'Switch Kit' or 'Bill Navigator'
request = LinkTokenCreateRequest(
user=LinkTokenCreateRequestUser(
client_user_id=end_user_id,
),
client_name=solution,
products=[Products('transactions')],
transactions=LinkTokenTransactions(
days_requested=730
),
country_codes=[CountryCode('US')],
language='en',
account_filters=LinkTokenAccountFilters(
depository=DepositoryFilter(
account_subtypes=DepositoryAccountSubtypes([
DepositoryAccountSubtype('checking'),
DepositoryAccountSubtype('savings')
])
),
credit=CreditFilter(
account_subtypes=CreditAccountSubtypes([
CreditAccountSubtype('credit card')
])
),
)
webhook={webhook},
redirect_uri={redirect_uri},
hosted_link=LinkTokenCreateHostedLink(
is_mobile_app={is_mobile_app},
completion_redirect_uri={completion_redirect_uri},
),
)
response = client.link_token_create(request)
link_token = response['link_token']
hosted_link_url = response['hosted_link_url']
return {
plaid_link_token: link_token,
hosted_link_url: hosted_link_url
}
Sample code for Plaid Processor Token Exchange endpoint
# Exchange the public token from Plaid Link for an access token.
exchange_request = ItemPublicTokenExchangeRequest(public_token=public_token)
exchange_token_response = client.item_public_token_exchange(exchange_request)
access_token = exchange_token_response['access_token']
# Fetch all accounts for this access token
accounts_request = AccountsGetRequest(access_token=access_token)
accounts_response = client.accounts_get(accounts_request)
accounts = accounts_response['accounts']
# Create processor tokens for all accounts
pinwheel_processor_tokens = []
for account in accounts:
create_request = ProcessorTokenCreateRequest(
access_token=access_token,
account_id=account['account_id'],
processor='pinwheel'
)
create_response = client.processor_token_create(create_request)
pinwheel_processor_tokens.append(create_response['processor_token'])
Updated about 11 hours ago