> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.upwardli.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.upwardli.com/_mcp/server.

# Plaid Integration API Documentation

## Overview

This document covers two endpoints for integrating Plaid into your application:

1. **Get Plaid Link Token** — Generates a short-lived token used to initialize Plaid Link on the client side.
2. **Verify Account** — Verifies a connected account after the user completes the Plaid Link flow.

---

## Base URL

```yaml
Sandbox: https://api-sandbox.upwardli.com/
Prod: https://api.upwardli.com/
```

---

## Authentication

All requests require a Bearer token passed in the `Authorization` header.

```json
Authorization: Bearer <your_token>
```

### Required Scopes

| Scope             | Description                              |
| ----------------- | ---------------------------------------- |
| `api:write`       | General write access to the API          |
| `api:plaid:write` | Write access for to get Plaid link token |

---

## Endpoints

### 1. Get Plaid Link Token

Generates a Plaid Link token for a specific consumer. This token is required to initialize the Plaid Link UI on the client side.

#### Method & URL

```bash
POST v2/consumers/{consumer_id}/accounts/plaid-link-token
```

#### Path Parameters

| Parameter     | Type   | Required | Description              |
| ------------- | ------ | -------- | ------------------------ |
| `consumer_id` | string | ✅ Yes    | The UUID of the consumer |

#### Headers

| Header          | Value                 |
| --------------- | --------------------- |
| `Authorization` | `Bearer <your_token>` |
| `Content-Type`  | `application/json`    |

Request Body\*\*

```json
{
  "is_mobile_app": false
}
```

| Field           | Type    | Required | Description                                         |
| --------------- | ------- | -------- | --------------------------------------------------- |
| `is_mobile_app` | boolean | ✅ Yes    | Set to `true` for mobile apps, `false` for web apps |

#### Example Request

```bash
curl --location 'https://api-sandbox.upwardli.com/v2/consumers/1234567/accounts/plaid-link-token' \
--header 'Authorization: Bearer QF1rMIM808v18dNTcsCN7oWkttgktt' \
--header 'Content-Type: application/json' \
--data '{
    "is_mobile_app": false
}'
```

#### Response

```json
{
    "link_token": "link-sandbox-f1133b83-510a-46de-87d7-2add5fa593d3",
    "expiration": 1772778931000,
    "hosted_link_url": "https://secure.plaid.com/hl/lss6688o38065n91qr32q27nqq0sn048q8"
}
```

| Field             | Type    | Description                                                    |
| ----------------- | ------- | -------------------------------------------------------------- |
| `link_token`      | string  | Token used to initialize the Plaid Link SDK on the client side |
| `expiration`      | integer | Unix timestamp (ms) indicating when the link token expires     |
| `hosted_link_url` | string  | Plaid-hosted URL to open the Link flow without the SDK         |

---

### 2. Verify Account

Verifies a specific account after the user has completed the Plaid Link flow. This should be called once Plaid Link has successfully returned a public token and the account has been created on your backend.

#### Method & URL

```bash
POST v2/accounts/{account_id}/verify
```

#### Path Parameters

| Parameter    | Type   | Required | Description                       |
| ------------ | ------ | -------- | --------------------------------- |
| `account_id` | string | ✅ Yes    | The UUID of the account to verify |

#### Headers

| Header          | Value                 |
| --------------- | --------------------- |
| `Authorization` | `Bearer <your_token>` |

#### Example Request

```bash
curl --location --request POST 'https://api-sandbox.upwardli.com/v2/accounts/7f65d732-da69-4fe0-b77c-ebbed53677e9/verify' \
--header 'Authorization: Bearer QF1rMIM808v18dNTcsCN7oWkttgktt'
```

#### Response

```json
{
    "hosted_link_url": "https://secure.plaid.com/hl/lssr9pp15nr73197q93ron8n9pp00r8s10"
}
```

| Field             | Type   | Description                                                |
| ----------------- | ------ | ---------------------------------------------------------- |
| `hosted_link_url` | string | Plaid-hosted URL to complete the account verification flow |

---

## Supported Plaid Verification Flows

We support the following Plaid account verification flows:

### 1. Consumer Logs into Financial Institution

The consumer authenticates directly with their financial institution through Plaid Link. This is the fastest path — the account is verified instantly upon successful login.

### 2. Manual Entry

Used when the consumer's financial institution does not support instant authentication. Two sub-flows are available depending on institution support:

#### 2a. Instant Micro-Deposits

If the financial institution supports it, Plaid will send instant micro-deposits to the account. The consumer verifies the deposit amounts to confirm ownership.

#### 2b. Same Day ACH

If instant micro-deposits are not supported, Same Day ACH is used as a fallback.

> ⚠️ **Account Verification Required** — With Same Day ACH, the consumer must explicitly verify their account after the deposit is received. Use the [Verify Account](#2-verify-account) endpoint to complete this step.

---

## Account Ownership Verification

Once an account is verified with the financial institution, Upward runs a Plaid identity match to confirm the account actually belongs to the consumer. If the account holder's name does not match the consumer on file, the account is set to `verification_failed` and deactivated, the consumer is emailed that the account could not be added, and the [`Consumer.BankAccount.VerificationFailed`](/concepts/webhooks/event-catalog#bank-account-management-webhooks) webhook is sent to any endpoint registered for it.

In sandbox this check passes automatically, so linked accounts stay active by default.

### Testing a Failed Verification

To exercise the failure path in sandbox, link an account for a consumer named **Alexander Upward**:

| Field        | Value       |
| ------------ | ----------- |
| `first_name` | `Alexander` |
| `last_name`  | `Upward`    |

Link the bank account for that consumer as you normally would. The identity match will fail, and you can use it to verify your handling of the deactivated account and the `Consumer.BankAccount.VerificationFailed` webhook.

Any other consumer name passes the sandbox identity match. The name comparison is not case-sensitive, so `alexander upward` behaves the same way.

---

## Opening and Closing the Plaid Browser

### Step 1 — Open the Plaid Browser

Launch a `secure.plaid.com` browser session where the consumer can complete Plaid authentication. Use the `hosted_link_url` returned from the [Get Plaid Link Token](#1-get-plaid-link-token) endpoint to open the session.

### Step 2 — Handle Completion with Custom URL Schema

Once Plaid completes, Upwardli will send a deep link using the following schema:

```bash
upwardli://plaid-link
```

### Step 3 — Close the Plaid Browser on Redirect

Your app must listen for the `plaid completion_redirect_uri` in order to close the Plaid browser session when the deep link is received.

#### Example — Plaid Completion / Close Browser

```javascript
// Handle deep links
useEffect(() => {
  const handleUrl = ({ url }: { url: string }) => {
    if (url.includes("plaid-link")) {
      WebBrowser.maybeCompleteAuthSession();
    }
  };

  const subscription = Linking.addEventListener("url", handleUrl);

  return () => {
    subscription.remove();
  };
}, []);
```

---

## Typical Integration Flow

```BASH
1. Call POST v2/consumers/{consumer_id}/accounts/plaid-link-token
        ↓
2. Use the returned token to open Plaid Link on the client
        ↓
3. User connects their bank account via Plaid Link
        ↓
4. Call POST v2/accounts/{account_id}/verify
        ↓
5. Account is verified and ready to use
```

---

## Notes

* All UUIDs (consumer IDs, account IDs) are in standard UUID v4 format.
* The Plaid Link token is short-lived — initialize the Plaid Link UI promptly after receiving it.
* The sandbox base URL (`api-sandbox.upwardli.com`) should be replaced with the production URL before going live.