Inyo

Linking Bank Accounts with Plaid

Plaid lets a customer connect their US bank account by logging in with their bank credentials, instead of typing a routing and account number by hand. The gateway wraps the Plaid Link flow with:

MethodEndpointDescription
POST/providers/plaidCreate a Plaid Link token to initialize Plaid Link on the client
POST/check-accountVerify the selected account and exchange the Plaid public token for a reusable accountTokenId

The result of a completed Plaid link is a tokenized bank account that you pass into a payment as paymentMethod.accountTokenId — the same PULL flow as ACH, but without handling raw bank numbers.

When to use Plaid vs. raw ACH: Use Plaid when you want instant account verification and a better conversion experience, and to avoid collecting/storing raw routing and account numbers. Use direct ACH when you already hold validated bank details.

Flow Overview

1. POST /providers/plaid          2. Open Plaid Link            3. POST /check-account
   (server-side)                     (client-side)                 (server-side)
        │                                 │                              │
        ▼                                 ▼                              ▼
   Gateway returns a            Customer logs in, selects      Exchange the Plaid public
   Plaid Link token        →    an account; Plaid returns  →   token for a verified,
   (token)                      a public token + account id    tokenized accountTokenId

4. POST /v2/payment
   Use the accountTokenId in paymentMethod to pull funds via ACH
POST https://{FQDN}/providers/plaid

Headers:

HeaderValue
AuthorizationBearer {accessToken}
Content-Typeapplication/json

Request Body

FieldTypeRequiredDescription
phoneNumberstringCustomer phone number (E.164). Used by Plaid to pre-fill and accelerate the Link flow via Plaid Layer when available.
androidPackageNamestringYour Android app's package name. Required only when launching Plaid Link from an Android app, so Plaid can hand control back to the correct app.
curl -X POST https://{FQDN}/providers/plaid \
  -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIs...' \
  -H 'Content-Type: application/json' \
  -d '{
    "phoneNumber": "+15555550123",
    "androidPackageName": "com.example.app"
  }'

Response (200)

A successful call returns the Plaid Link token used to initialize Plaid Link on the client.

{
  "token": "link-sandbox-7f8e9d0c-1a2b-3c4d-...",
  "expiration": "2026-02-12T20:27:26Z",
  "requestId": "JWk6bG8b0zsLXWZ"
}
FieldTypeDescription
tokenstringThe Plaid Link token. Pass it to Plaid Link on the client (Step 2) to start the bank-selection flow.
expirationstringISO 8601 timestamp after which the token is no longer valid — create a new one if it expires before the customer completes Link.
requestIdstringCorrelation ID for this request — include it when contacting support for tracing.

Initialize Plaid Link with the token returned above. The customer authenticates with their bank and picks an account. See Plaid Link documentation for the web, iOS, Android, and React Native SDKs.

const handler = Plaid.create({
  token: token, // the `token` from POST /providers/plaid
  onSuccess: (publicToken, metadata) => {
    // Link complete — Plaid returns a public token + the selected account id.
    // Send both to your backend to verify and tokenize the account.
    verifyAccount(publicToken, metadata.account_id);
  },
  onExit: (err, metadata) => { /* handle abandonment */ }
});
handler.open();

Plaid's onSuccess callback gives you a public token and the selected account id — these become accountCheckToken and accountCheckId in the next step.

Step 3 — Verify and Tokenize the Account

Exchange the Plaid public token for a reusable accountTokenId via Check Account. This verifies the account and returns the token you use in payments.

POST https://{FQDN}/check-account
curl -X POST https://{FQDN}/check-account \
  -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIs...' \
  -H 'Content-Type: application/json' \
  -d '{
    "externalPaymentId": "CHECK_ACCOUNT_0a022f78-14b6-4f6b-8ddd-d1c9be7c4dcc",
    "sender": {
      "paymentMethod": {
        "type": "BANK_DEPOSIT",
        "countryCode": "US",
        "accountCheckToken": "public-sandbox-57f6f60a-e637-4582-8858-b871e59f5f4e",
        "accountCheckId": "X4943dk1W1CbvoJ6r3vPTQrLgWlmyet1vm1on"
      }
    }
  }'

The response returns status: "VERIFIED" and the accountTokenId you'll use to pull funds:

{
  "paymentId": "cf8600be-ec46-4ed9-a00b-ece348004ca7",
  "externalPaymentId": "CHECK_ACCOUNT_0a022f78-14b6-4f6b-8ddd-d1c9be7c4dcc",
  "accountTokenId": "62d37fd8-89d0-43ca-900f-a75a6e871fe5",
  "approved": true,
  "status": "VERIFIED",
  "bankAccountName": "Chase",
  "accountNumberMasked": "************0000",
  "routingNumberMasked": "*****1533"
}

See Check Account for the full request and response field reference.

Step 4 — Pull Funds Using the Linked Account

Use the accountTokenId from Step 3 in a standard PULL payment. No routing/account numbers are sent — the token references the verified account.

curl -X POST https://{FQDN}/v2/payment \
  -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIs...' \
  -H 'Content-Type: application/json' \
  -d '{
    "externalPaymentId": "plaid-order-001",
    "ipAddress": "203.0.113.42",
    "paymentType": "PULL",
    "capture": true,
    "amount": {
      "total": 19.99,
      "currency": "USD"
    },
    "sender": {
      "firstName": "John",
      "lastName": "Smith",
      "paymentMethod": {
        "type": "BANK_DEPOSIT",
        "accountTokenId": "62d37fd8-89d0-43ca-900f-a75a6e871fe5"
      }
    }
  }'

The payment response is identical to a direct ACH pull — ACH payments are auto-captured, so a successful result returns status CAPTURED.

What's Next

  • ACH (Bank Account) — Pull funds with raw routing/account numbers (no Plaid)
  • Payment — Core payment operations and payload structure
  • Webhooks — Receive payment status updates asynchronously