Add Customer External Bank Accounts

How do I connect a customer's bank account using Plaid Link?

Overview

Connect customer bank accounts to the Cybrid platform using Plaid Link. This secure front-end SDK allows customers to authenticate with their financial institution and link their accounts for funding and withdrawal operations.

We strongly recommend reviewing the official Plaid Link documentation for the most up-to-date details for your specific platform (Web, iOS, Android, or React Native).

Prerequisites

  • You have an active Cybrid account and API keys.
  • You have created a customer_guid for the user who will be linking their bank account. See our guide on creating a customer.

Step 1: Generate a Plaid Link Token

First, generate a plaid_link_token by creating a workflow. This token is used to initialize the Plaid Link SDK in the next step.

Create a workflow with the type set to plaid and the kind to link_token_create. The Cybrid API will then asynchronously request a plaid_link_token from Plaid. You must poll the workflow endpoint using the returned workflow_guid until the plaid_link_token becomes available.

ℹ️

Workflow Notes

  • Ensure that the customer_guid provided is associated with the external_bank_account_guid
  • All redirect URIs must be registered with Cybrid
POST /api/workflows
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN

{
  "type": "plaid",
  "kind": "link_token_create",
  "language": "en",
  "link_customization_name": "default",
  "customer_guid": "{customer_guid}",
  "redirect_uri": "https://yourapp.com/api/plaid-redirect-uri"
}
{
  "guid": "{workflow_guid}",
  "bank_guid": "{bank_guid}",
  "customer_guid": "{customer_guid}",
  "type": "plaid",
  "state": "storing",
  "failure_code": null,
  "created_at": "2025-01-01T12:00:00.000Z",
  "updated_at": "2025-01-01T12:00:00.000Z"
}

Poll GET /api/workflows/{workflow_guid}, until the state is completed and the plaid_link_token is populated.

{
  "guid": "{workflow_guid}",
  "bank_guid": "{bank_guid}",
  "customer_guid": "{customer_guid}",
  "type": "plaid",
  "state": "completed",
  "failure_code": null,
  "plaid_link_token": "{plaid_link_token}",
  "created_at": "2025-01-01T12:00:00.000Z",
  "updated_at": "2025-01-01T12:00:05.000Z"
}

Workflow States

StateDescription
storingThe Platform is storing the workflow details in the private store
completedThe Platform has created the workflow and generated the link token
failedThe workflow was not completed successfully (check failure_code for details)

OAuth and Redirect URIs

Many financial institutions use an OAuth flow, which redirects the customer to their bank's portal for authentication. You must register your application's redirect URIs with Cybrid for each environment (Sandbox and Production).

Contact Cybrid support to register your URIs.

For more information, see Plaid's documentation on OAuth redirect URIs.

Step 2: Initialize Plaid Link SDK

Use the generated plaid_link_token to initialize the Plaid Link SDK on your client-side application. The handler below includes callbacks for success, exit events, and other events.

const handler = Plaid.create({
  token: 'GENERATED_LINK_TOKEN', // The plaid_link_token from Step 1
  onSuccess: (public_token, metadata) => {
    // A Plaid public_token and account metadata are returned
    // Use these values to create an external bank account in Step 3
    // https://plaid.com/docs/link/web/#onsuccess
  },
  onLoad: () => {},
  onExit: (err, metadata) => {
    // Handle the case where the user exits the flow
    // https://plaid.com/docs/link/web/#onexit
  },
  onEvent: (eventName, metadata) => {
    // Optionally subscribe to events during the Plaid flow
    // https://plaid.com/docs/link/web/#onevent
  },
});
⚠️

Callback Logging

We recommend implementing clear logging for each callback in your application

Handling the onSuccess Callback

The onSuccess callback is triggered when the customer successfully links an account. It returns a public_token and metadata object containing the account id. You will use both of these in the next step.

ℹ️

One Account per Workflow

A customer can only link one external bank account per workflow. To link multiple accounts, you must create a unique workflow for each one.

Step 3: Create an External Bank Account

With the public_token and account id (inside accounts object) from the onSuccess callback, you can now create an external bank account on the Cybrid platform.

Call the POST /api/external_bank_accounts endpoint with the Plaid-specific parameters.

POST /api/external_bank_accounts
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN

{
  "name": "External Bank Account Name",
  "account_kind": "plaid",
  "customer_guid": "{customer_guid}",
  "asset": "USD",
  "plaid_public_token": "{plaid_public_token}",
  "plaid_account_id": "{plaid_account_id}"
}

For a detailed walkthrough, see our recipe for adding a customer's verified external bank account.

ℹ️

Payment Rail Routing

When a bank account is linked via Plaid, the ABA routing number is captured and stored. When initiating a transfer, specify the payment_rail parameter (ach or wire) to process the payment using the appropriate routing. Note that some US banks have different routing numbers for ACH vs wire transactions. If wire transfers fail due to routing issues with a Plaid-linked account, you may need to use the counterparty external bank accounts method to explicitly specify routing details for the intended payment rail.

⚠️

FBO Account Limitations

If a bank account is opened for a customer via Cybrid (such as an FBO account), the customer cannot be provided with online banking credentials to link that account to other platforms via Plaid. Only accounts where the customer has their own online banking access can be linked via Plaid Link.

Handling Plaid Link Updates (Update Mode)

Bank connections can expire, requiring the customer to re-authenticate with their financial institution. When this happens, the external bank account's state will change to refresh_required.

From GET /api/external_bank_accounts/{guid}

{
  "guid": "{external_bank_account_guid}",
  "name": "My Checking Account",
  "asset": "USD",
  "account_kind": "plaid",
  "bank_guid": "{bank_guid}",
  "customer_guid": "{customer_guid}",
  "state": "refresh_required",
  "failure_code": null,
  "created_at": "2024-12-15T10:30:00.000Z",
  "updated_at": "2025-01-01T12:00:00.000Z"
}
❗️

Transactions Disabled

No transactions can be performed with an external bank account in the refresh_required state.

To resolve this, you must guide the customer through Plaid's Update Mode:

  1. Detect the refresh_required state by polling GET /api/external_bank_accounts/{external_bank_account_guid} and checking the state field.
  2. Create a workflow with POST /api/workflows using kind: "link_token_update" and the external_bank_account_guid that needs to be refreshed, and read the plaid_link_token from the response.
  3. Initialize Plaid Link with the plaid_link_token in update mode.
  4. The customer re-authenticates with their financial institution through the Plaid Link flow.
  5. Update the external bank account state by calling PATCH /api/external_bank_accounts/{external_bank_account_guid} with state set to completed.
⚠️

Manual State Update Required

The platform does not automatically update the external bank account state after the customer re-authenticates. Your application must explicitly call PATCH /api/external_bank_accounts/{external_bank_account_guid} with { "state": "completed" } to transition the account out of the refresh_required state.

POST /api/workflows
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN

{
  "type": "plaid",
  "kind": "link_token_update",
  "language": "en",
  "link_customization_name": "default",
  "external_bank_account_guid": "{external_bank_account_guid}",
  "redirect_uri": "https://yourapp.com/api/plaid-redirect-uri"
}

After the customer completes the Plaid Link update flow, call the patch external bank account endpoint to finalize the refresh:

PATCH /api/external_bank_accounts/{external_bank_account_guid}
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN

{
  "state": "completed"
}

Sandbox Environment

In the Cybrid Sandbox, the generated plaid_link_token automatically initializes the Plaid Link SDK in its sandbox mode, so you can test without using real personal information.

To test the full update mode flow, you can force an external bank account into the refresh_required state using the patch external bank account endpoint:

PATCH /api/external_bank_accounts/{external_bank_account_guid}
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN

{
  "state": "refresh_required"
}

This allows you to simulate an expired bank connection and verify your application handles the update mode flow correctly.