> ## Documentation Index
> Fetch the complete documentation index at: https://developers.dwolla.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Plaid: Instant Account Verification

> Step-by-step guide to integrating Dwolla's Open Banking solution with Plaid. Learn how to enable instant account verification, streamline account-to-account (A2A) payments, and enhance security for enterprise payment workflows.

## Overview

This guide dives into leveraging Dwolla's Open Banking Services in collaboration with **Plaid** to streamline bank account verification within your Dwolla-powered application. Open banking empowers your users to more securely share their financial data with Dwolla and your application, eliminating the need for manual data entry and improving the overall user experience.

We'll walk you through the steps to set up and integrate **Plaid Instant Account Verification** (Plaid IAV) using **Dwolla's Exchange Sessions API**. Dwolla's powerful Exchange Sessions API acts as the bridge between your application and Plaid's Open Banking API. This established connection facilitates real-time verification of your user's bank account details.

To gain hands-on experience, we recommend following along with the provided [integration-examples](https://github.com/Dwolla/integration-examples/tree/main/packages/open-banking/plaid) sample app, which provides a practical understanding of the integration process for your own application.

## Instant Account Verification (IAV)

Instant Account Verification (IAV) is a one-time process that verifies the bank account being added by an end user is open and active. At the end of this guide, you'll obtain a **Funding Source URL**, which is a unique identifier that represents a bank account being used for account-to-account (A2A) payments.

## Prerequisites

Before starting the integration, make sure you have completed the following prerequisites:

1. **Dwolla Account**: Set up a Dwolla **production** or **sandbox** account.
2. **Create a Customer**: Create a customer in your Dwolla account if you haven't already done so. Check out the Dwolla [Create a Customer](/docs/api-reference/customers/create-a-customer) API documentation for guidance.

Note: You do not need a Plaid account or contract with Plaid to leverage Plaid via Dwolla's Open Banking Services. Dwolla handles the integration with Plaid for you, simplifying the process.

## Sandbox Testing

Testing in the **sandbox environment** is essential before deploying Plaid Open Banking in production. The sandbox allows you to validate functionality with test data, ensuring a smooth experience for live users.

### Test Credentials for Plaid Link Flow

Use the following credentials to simulate successful authentication with test banks:

* **Username**: `user_good`
* **Password**: `pass_good`

### Returning User Testing in Sandbox

Plaid's Sandbox includes pre-seeded test users for validating different returning user scenarios. Use the phone numbers and OTP (always `123456`) below to simulate these cases:

| Scenario                                     | Phone Number |
| -------------------------------------------- | ------------ |
| New User                                     | 415-555-0010 |
| Verified Returning User                      | 415-555-0011 |
| Verified Returning User: Linked New Account  | 415-555-0012 |
| Verified Returning User: Linked OAuth Bank   | 415-555-0013 |
| Verified Returning User + New Device         | 415-555-0014 |
| Verified Returning User: Auto Account Select | 415-555-0015 |

### Key Notes About Plaid Test Banks

Plaid offers two test banks: one for **checking** accounts and one for **savings** accounts. Both have predefined account and routing numbers. This means:

* You can add up to two banks per <Tooltip tip="A Customer is an individual or business entity in Dwolla's system.">Customer</Tooltip> (one checking, one savings).
* To test additional banks, remove an existing funding source and repeat the Plaid Link flow.

### Plaid SDKs for Account Authentication

Plaid Link serves as the front-end widget for Plaid IAV, enabling users to securely authenticate and link their bank accounts. This widget can be seamlessly embedded into your application using one of [Plaid's Link client SDKs](https://plaid.com/docs/api/libraries/#link-client-sdks).

In this guide, we'll be using the `react-plaid-link` package, which is specifically designed for React web applications. It simplifies the integration of Plaid Link by providing a React hook to handle initialization and user interactions with the widget.

If you're using a different framework or platform, Plaid offers [SDKs](https://plaid.com/docs/api/libraries/#link-client-sdks) tailored to various environments from which you can select the appropriate package for your application infrastructure.

## Demo

<Card title="Plaid Open Banking Demo" href="https://dwolla.coastdemo.com/share/67ca29bcc030cd6114d7d837?&step=3&skip_to_end=yes&mode=link&layoutType=web" img="https://mintcdn.com/dwolla/onJrgnlea1hrJeOy/assets/gifs/coast-demo-plaid.gif?s=397d39270988f0c9576a8b12d58c4e9c" cta="Demo" width="1202" height="730" data-path="assets/gifs/coast-demo-plaid.gif">
  Coast Demo: Plaid Open Banking Flow
</Card>

## Integration Steps

### Step 1 - Initiate Exchange Session with Plaid

To begin, you will [create an exchange session](/docs/api-reference/exchange-sessions/create-customer-exchange-session) for your Customer in Dwolla using the **Exchange Sessions API**. This session will specify Plaid as the **exchange partner**. The Exchange Partner ID for Plaid can be found by calling the [List Exchange Partners](/docs/api-reference/exchanges/list-exchange-partners) API endpoint.

**About the `redirect-url` Field:**

If have an **Android** and/or **iOS** app, you must include a platform-specific `redirect-url` in the request body when creating an exchange session. This URL determines where the user is redirected after completing the Plaid Link flow. The `redirect-url` is a **required** field only for Android and iOS apps. It is not needed for web-based implementations.

* For **Android**, use the Android package name as the redirect-url value (e.g., `com.example.app123`).
* For **iOS**, use a valid HTTP or HTTPS URL (e.g., `https://example.com/app123`) that can handle redirects in the app.

Dwolla will validate the provided `redirect-url` based on these conventions and send the appropriate value to Plaid. If the redirect-url does not start with a valid protocol (https\:// or http\://), it will be assumed to be an Android package name.

<Info>
  Exchange Sessions are single-use. Once a user starts the IAV flow initiated by creation of a session, it becomes invalid and cannot be reused.
</Info>

##### Example: Initiating an Exchange Session via Dwolla API

```javascript theme={"dark"}
import { Client } from "dwolla-v2";

const dwolla = new Client({
  key: "YOUR_KEY",
  secret: "YOUR_SECRET",
  environment: "sandbox", // or 'production'
});

// Retrieve Plaid's exchange partner href
export async function getExchangePartnerHref(): Promise<string> {
  const response = await dwolla.get("/exchange-partners");

  const partnersList = response.body._embedded["exchange-partners"];

  return partnersList.find(
    (partner: { name: string }) => partner.name.toLowerCase() === "plaid"
  )._links.self.href;
}

// Create an exchange session for a Customer
export async function createExchangeSession(
  customerId: string
): Promise<string> {
  const exchangePartnerHref = await getExchangePartnerHref();

  const requestBody = {
    _links: {
      "exchange-partner": { href: exchangePartnerHref },
    },
  };

  const response = await dwolla.post(
    `customers/${customerId}/exchange-sessions`,
    requestBody
  );

  return response.headers.get("location"); // URL of the exchange session
}

// Example usage
const exchangeSessionUrl = await createExchangeSession("your-customer-id");
console.log("Exchange session URL:", exchangeSessionUrl); // => Exchange session URL: https://api.dwolla.com/exchange-sessions/fcd15e5f-8d13-4570-a9b7-7fb49e55941d
```

```bash theme={"dark"}
POST https://api.dwolla.com/customers/74a207b2-b7b7-4efa-8bf8-582148e7b980/exchange-sessions
Accept: application/vnd.dwolla.v1.hal+json
Content-Type: application/vnd.dwolla.v1.hal+json
Authorization: Bearer pBA9fVDBEyYZCEsLf/wKehyh1RTpzjUj5KzIRfDi0wKTii7DqY

{
  "_links": {
    "exchange-partner": {
      "href": "https://api.dwolla.com/exchange-partners/f53ffb32-c84f-496a-9d9d-acd100d396ef"
    }
  }
}

HTTP/1.1 201 Created
Location: https://api.dwolla.com/exchange-sessions/fcd15e5f-8d13-4570-a9b7-7fb49e55941d
```

##### Example Request: Android

```bash theme={"dark"}
POST https://api.dwolla.com/customers/74a207b2-b7b7-4efa-8bf8-582148e7b980/exchange-sessions
Accept: application/vnd.dwolla.v1.hal+json
Content-Type: application/vnd.dwolla.v1.hal+json
Authorization: Bearer pBA9fVDBEyYZCEsLf/wKehyh1RTpzjUj5KzIRfDi0wKTii7DqY


{
  "_links": {
    "exchange-partner": {
      "href": "https://api.dwolla.com/exchange-partners/f53ffb32-c84f-496a-9d9d-acd100d396ef"
    },
    "redirect-url": {
      "href": "com.example.app123"
    }
  }
}
```

##### Example Request: iOS

```bash theme={"dark"}
POST https://api.dwolla.com/customers/74a207b2-b7b7-4efa-8bf8-582148e7b980/exchange-sessions
Accept: application/vnd.dwolla.v1.hal+json
Content-Type: application/vnd.dwolla.v1.hal+json
Authorization: Bearer pBA9fVDBEyYZCEsLf/wKehyh1RTpzjUj5KzIRfDi0wKTii7DqY


{
  "_links": {
    "exchange-partner": {
      "href": "https://api.dwolla.com/exchange-partners/f53ffb32-c84f-496a-9d9d-acd100d396ef"
    },
    "redirect-url": {
      "href": "https://example.com/app123"
    }
  }
}
```

### Step 2 - Retrieve Exchange Session and Complete Plaid Link Flow

After creating the exchange session, retrieve the session details from Dwolla to obtain the **Plaid Link Token**. This token initializes the Plaid Link flow on the front end, where the Customer authenticates their bank account through Plaid's secure interface. Once the flow is successfully completed, the `onSuccess` handler captures the `publicToken` returned by Plaid, which can be used for subsequent operations like creating an exchange.

#### Code Example

##### Backend - Backend: Retrieve Plaid Link Token

```javascript theme={"dark"}
// Retrieve exchange session by ID

export async function getPlaidExchangeSession(
  exchangeSessionId: string
): Promise<string> {
  const response = await dwolla.get(`/exchange-sessions/${exchangeSessionId}`);

  return response.body.externalProviderSessionToken; // Plaid Link Token
}

// Example usage:

const plaidLinkToken = await getPlaidExchangeSession(
  "your-exchange-session-id"
);

console.log("Plaid Link Token:", plaidLinkToken); // => Plaid Link Token: link-production-b41e8ed3-0874-4c64-b07d-a77088979d5f
```

```bash theme={"dark"}
GET https://api.dwolla.com/exchange-sessions/fcd15e5f-8d13-4570-a9b7-7fb49e55941d
Accept: application/vnd.dwolla.v1.hal+json
Authorization: Bearer pBA9fVDBEyYZCEsLf/wKehyh1RTpzjUj5KzIRfDi0wKTii7DqY

...
{
    "created": "2024-11-18T18:48:11.357Z",
    "_links": {
        "self": {
            "href": "https://api.dwolla.com/exchange-sessions/ca80ecc6-9204-4e1c-9a2d-a78fa3c08933",
            "type": "application/vnd.dwolla.v1.hal+json",
            "resource-type": "exchange-sessions"
        },
        "exchange-partner": {
            "href": "https://api.dwolla.com/exchange-partners/f53ffb32-c84f-496a-9d9d-acd100d396ef",
            "type": "application/vnd.dwolla.v1.hal+json",
            "resource-type": "exchange-partner"
        }
    },
    "externalProviderSessionToken": "link-production-b41e8ed3-0874-4c64-b07d-a77088979d5f"
}
```

##### Frontend - Initialize and Handle Plaid Link Flow (using React)

```javascript theme={"dark"}
import { usePlaidLink } from "react-plaid-link";

const plaidLinkToken = "your-session-link-token"; // Replace with the actual link token from the exchange session

const { open, ready } = usePlaidLink({
  token: plaidLinkToken,

  onSuccess: (publicToken) => {
    // Public token is retrieved here. This will be used when creating an exchange

    console.log("Plaid Public Token:", publicToken);
  },

  onExit: () => {
    console.log("User exited the Plaid Link flow.");
  },
});
```

### Step 3 - Create Exchange with Plaid Public Token

After successfully completing the Plaid Link flow and retrieving the `public token`, create an <Tooltip tip="An Exchange represents a secure connection between a user's bank and Dwolla.">Exchange</Tooltip> resource in the Dwolla API by passing the `public token` returned by Plaid. This creates an "exchange" representing the link between the Dwolla [Customer](/docs/api-reference/customers/create-a-customer) and their external bank account.

##### Example: Create Exchange Resource in Dwolla

```javascript theme={"dark"}
// Create an exchange for a Dwolla customer using Plaid's public token

export async function createExchange(
  customerId: string,
  plaidPublicToken: string
): Promise<string> {
  const exchangePartnerHref = await getExchangePartnerHref(); // Retrieve Plaid's exchange partner href

  const requestBody = {
    _links: {
      "exchange-partner": { href: exchangePartnerHref },
    },

    plaid: {
      publicToken: plaidPublicToken,
    },
  };

  const response = await dwolla.post(
    `customers/${customerId}/exchanges`,
    requestBody
  );

  return response.headers.get("location"); // URL of the created exchange
}

// Example usage

const exchangeUrl = await createExchange(
  "your-customer-id",
  "your-plaid-public-token"
);

console.log("Exchange URL:", exchangeUrl); // => Exchange URL: https://api.dwolla.com/exchanges/73463f82-3f9f-499f-a0ae-630c0808e09f
```

```bash theme={"dark"}
POST https://api.dwolla.com/customers/74a207b2-b7b7-4efa-8bf8-582148e7b980/exchanges
Accept: application/vnd.dwolla.v1.hal+json
Content-Type: application/vnd.dwolla.v1.hal+json
Authorization: Bearer pBA9fVDBEyYZCEsLf/wKehyh1RTpzjUj5KzIRfDi0wKTii7DqY

{
    "_links": {
        "exchange-partner": {
            "href": "https://api.dwolla.com/exchange-partners/f53ffb32-c84f-496a-9d9d-acd100d396ef"
        }
    },
    "plaid": {
      "publicToken": "public-production-d5456acb-01d5-4932-9783-e4c883cf1c0c"
    }
}

HTTP/1.1 201 Created
Location: https://api.dwolla.com/exchanges/fcd15e5f-8d13-4570-a9b7-7fb49e55941d
```

### Step 4 - Create Funding Source

After successfully creating the exchange, create a **funding source** for the Customer. This involves calling Dwolla's [Create a Funding Source](/docs/api-reference/funding-sources/create-customer-funding-source) endpoint, where you'll provide the **exchange** resource obtained from the previous step.

In the following function, once a response is received, it will extract the `Location` header value, which is the fully-qualified URL specifying the resource location of the Customers's funding source.

##### Example: Create Funding Source in Dwolla

```javascript theme={"dark"}
// Creates a funding source for a customer.

export async function createFundingSource(
  customerId: string,
  exchangeId: string,
  name: string,
  type: string
): Promise<string> {
  const exchangeUrl = `https://api.dwolla.com/exchanges/${exchangeId}`;

  const requestBody = {
    _links: {
      exchange: {
        href: exchangeUrl,
      },
    },

    bankAccountType: type,

    name: name,
  };

  const response = await dwolla.post(
    `customers/${customerId}/funding-sources`,
    requestBody
  );

  const location = response.headers.get("location");

  return location; // URL of the created funding source
}

// Example usage:

const fundingSourceUrl = await createFundingSource(
  "your-customer-id",
  "your-exchange-id",
  "Your Funding Source Name",
  "checking"
);

console.log("Funding Source URL:", fundingSourceUrl); // => Funding Source URL: https://api.dwolla.com/funding-sources/f41ab99c-7748-4f84-a3ed-3f669c002f4f
```

```bash theme={"dark"}
POST https://api.dwolla.com/customers/99bfb139-eadd-4cdf-b346-7504f0c16c60/funding-sources
Content-Type: application/vnd.dwolla.v1.hal+json
Accept: application/vnd.dwolla.v1.hal+json
Authorization: Bearer pBA9fVDBEyYZCEsLf/wKehyh1RTpzjUj5KzIRfDi0wKTii7DqY
{
  "_links": {
    "exchange": {
      "href": "https://api.dwolla.com/exchanges/6bc9109a-04fd-49b6-ace6-ca06fd282d65"
    }
  },
  "bankAccountType": "checking",
  "name": "Jane Doe - Checking"
}

HTTP/1.1 201 Created
Location: https://api.dwolla.com/funding-sources/AB443D36-3757-44C1-A1B4-29727FB3111C

```

## Handling Re-authentication

When Customers initially connect their bank account via Instant Account Verification, they authenticate their bank account with Plaid and grant permission to access their account information. This allows Dwolla to perform actions like [checking bank balances](https://developers.dwolla.com/docs/balance/api-reference/open-banking/retrieve-bank-balance). However, this access can be interrupted by changes made by the Customer, such as if the Customer updates their bank password, multi-factor authentication method or revokes consent to access their account information.

To maintain a smooth user experience, your application needs to handle these scenarios gracefully. Dwolla's API provides an `UpdateCredentials` error response to signal when a Customer's bank connection needs to be refreshed. Additionally, Dwolla will also send a `customer_exchange_reauth_required` webhook denoting an exchange has been deactivated (or is pending deactivation) and requires re-authentication.

<Info>
  Re-authentication is only required for actions that need real-time access to the Customer's bank account through Plaid, like Balance Check. Once a bank account is successfully added to Dwolla as a funding source, transfers can continue to function normally without re-authentication.
</Info>

##### `UpdateCredentials` error response

```
{
    "code": "UpdateCredentials",
    "message": "Re-authentication is required in order to access account data. Please initiate the exchange session flow to regain access.",
    "_links": {
        "about": {
            "href": "https://api.dwolla.com/exchanges/036c8a60-fa45-45d4-8f5d-181d348c6ec8/exchange-sessions",
            "type": "application/vnd.dwolla.v1.hal+json",
            "resource-type": "exchange-session"
        }
    }
}
```

#### Steps to manage re-authentication

1. **Detect the `UpdateCredentials` error:** When making calls to Dwolla's API (e.g., checking a bank balance), implement error handling to catch the UpdateCredentials response, which is an HTTP 400 error.

2. **Communicate with your Customer:** It's crucial to inform the Customer why they need to re-authenticate and how to do so. Use clear and concise language in in-app messages, emails or text messages to guide them back to your application to complete the process.

3. **Initiate the re-authentication flow:** Upon receiving this error, redirect the Customer to re-authenticate their bank account. This is done by creating a new [re-authentication exchange session](/docs/api-reference/exchange-sessions/create-re-authentication-exchange-session). This will guide the Customer through the necessary steps to re-establish their bank connection.

By following these steps, you can ensure that your application can handle interruptions to bank connections effectively, providing a smooth and user-friendly experience.

### Initiate re-authentication exchange-session

Use Dwolla's API endpoint to [create a re-authentication exchange session](/docs/api-reference/exchange-sessions/create-re-authentication-exchange-session), which initiates an Exchange Session for a Customer. While an optional redirect URL can be specified in the request body, it's not required.

#### Example using Dwolla Node SDK

##### Example: Re-Authenticate an Exchange in Dwolla

```node theme={"dark"}
import { Client } from "dwolla-v2";
const dwolla = new Client({
  key: "YOUR_KEY",
  secret: "YOUR_SECRET",
  environment: "production", // or 'sandbox'
});

/**
 * Creates a re-auth exchange session for a customer
 * @param exchangeId - The ID of the deactivated exchange to complete the re-authentication process.
 */

export async function initiateReauthentication(exchangeId: string) {
  const requestBody = {};
  try {
    const response = await dwolla.post(
      `exchanges/${exchangeId}/exchange-sessions`,
      requestBody
    );
    const location = response.headers.get("location");
    return location;
  } catch (error) {
    // Return an error message or handle the error appropriately
  }
}

// Example usage:

const reauthExchangeSessionUrl = initiateReauthentication(exchangeId); // => https://api.dwolla.com/exchange-sessions/fcd15e5f-8d13-4570-a9b7-7fb49e55941d
```

```bash theme={"dark"}
POST https://api.dwolla.com/exchanges/74a207b2-b7b7-4efa-8bf8-582148e7b980/exchange-sessions
Accept: application/vnd.dwolla.v1.hal+json
Content-Type: application/vnd.dwolla.v1.hal+json
Authorization: Bearer pBA9fVDBEyYZCEsLf/wKehyh1RTpzjUj5KzIRfDi0wKTii7DqY

...

HTTP/1.1 201 Created
Location: https://api.dwolla.com/exchange-sessions/fcd15e5f-8d13-4570-a9b7-7fb49e55941d
```

##### Example Request: Android

```bash theme={"dark"}
POST https://api.dwolla.com/exchanges/74a207b2-b7b7-4efa-8bf8-582148e7b980/exchange-sessions
Accept: application/vnd.dwolla.v1.hal+json
Content-Type: application/vnd.dwolla.v1.hal+json
Authorization: Bearer pBA9fVDBEyYZCEsLf/wKehyh1RTpzjUj5KzIRfDi0wKTii7DqY


{
  "_links": {
    "redirect-url": {
      "href": "com.example.app123"
    }
  }
}
```

##### Example Request: iOS

```bash theme={"dark"}
POST https://api.dwolla.com/exchanges/74a207b2-b7b7-4efa-8bf8-582148e7b980/exchange-sessions
Accept: application/vnd.dwolla.v1.hal+json
Content-Type: application/vnd.dwolla.v1.hal+json
Authorization: Bearer pBA9fVDBEyYZCEsLf/wKehyh1RTpzjUj5KzIRfDi0wKTii7DqY


{
  "_links": {
    "redirect-url": {
      "href": "https://example.com/app123"
    }
  }
}
```

## Resources

* [Integration Example App](https://github.com/Dwolla/integration-examples/tree/main/packages/open-banking/plaid)
* [Plaid Link SDKs](https://plaid.com/docs/api/libraries/#link-client-sdks)
