Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate Plaid with V0

To integrate Plaid with V0 by Vercel, generate a bank connection UI using Plaid Link, create Next.js API routes for token exchange and data fetching, store your Plaid credentials in Vercel environment variables, and deploy. Your app can securely connect user bank accounts and fetch transactions, balances, and identity data without exposing API secrets to the browser.

What you'll learn

  • How to create a Plaid developer account and get sandbox API credentials
  • How to implement the Plaid Link OAuth flow in a V0-generated Next.js app
  • How to exchange a Plaid public token for an access token via a Next.js API route
  • How to fetch bank account balances and transactions securely from server-side routes
  • How to display financial data in a V0-generated personal finance dashboard
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate15 min read45 minutesOtherApril 2026RapidDev Engineering Team
TL;DR

To integrate Plaid with V0 by Vercel, generate a bank connection UI using Plaid Link, create Next.js API routes for token exchange and data fetching, store your Plaid credentials in Vercel environment variables, and deploy. Your app can securely connect user bank accounts and fetch transactions, balances, and identity data without exposing API secrets to the browser.

Build Personal Finance Dashboards with Plaid and V0 by Vercel

Plaid has become the standard infrastructure for fintech applications — it's the invisible layer that powers bank connections in apps like Venmo, Robinhood, and thousands of smaller fintech products. Building a personal finance tool, expense tracker, or financial reporting app with V0 becomes far more useful when users can connect their real bank accounts rather than entering transactions manually. Plaid's developer sandbox lets you build and test the entire bank connection flow using simulated financial data without needing real bank credentials.

The Plaid integration flow has two distinct phases. First, the bank connection phase: your app creates a Link token via a server-side API route, loads the Plaid Link widget in the browser with that token, and the user authenticates with their bank. Plaid handles all the bank login UI — your app never sees the bank credentials. After successful authentication, Plaid returns a temporary public token to your browser. Your frontend immediately sends this public token to a second API route that exchanges it for a permanent access token using your Plaid secret key. Store that access token (per user, typically in a database) — it is what you use for all subsequent data requests.

Once you have an access token, fetching financial data is straightforward. The Plaid Node.js SDK provides methods for retrieving account balances (plaidClient.accountsBalanceGet), transactions (plaidClient.transactionsGet or the newer transactionsSync), institution identity, and income information. V0 excels at generating the data visualization layer — net worth summaries, spending category charts, transaction history tables, and account balance cards that transform raw financial data into actionable insights. The combination of Plaid's data depth and V0's UI generation speed lets you build sophisticated personal finance tools in hours rather than weeks.

Integration method

Next.js API Route

Plaid integrates with V0-generated Next.js apps through a multi-step server-side flow: Next.js API routes create Link tokens and exchange public tokens for access tokens using Plaid's Node.js SDK, while the Plaid Link widget runs in the browser to handle the bank authentication UI securely. Your Plaid secret key and any stored access tokens never leave the server. V0 generates the financial dashboard and bank connection interfaces; Next.js API routes handle the secure communication with Plaid for account linking and data retrieval.

Prerequisites

  • A Plaid developer account at plaid.com/docs/quickstart — sign up for free sandbox access, no credit card required
  • Your Plaid sandbox credentials: PLAID_CLIENT_ID and PLAID_SECRET — found in the Plaid Dashboard → Team Settings → Keys after creating an account
  • Node.js installed locally and a Next.js project to integrate Plaid into — run npm install plaid to add the Plaid Node.js SDK
  • A V0 account at v0.dev and a Vercel account for deployment
  • For production apps: Plaid API access requires a production key which requires going through Plaid's approval process and agreeing to their API agreement — sandbox and development environments are immediately available

Step-by-step guide

1

Generate the Finance Dashboard UI with V0

Open V0 at v0.dev and describe the personal finance dashboard or bank connection interface you want to build. Plaid integrations have two distinct UI states: the pre-connection state (showing a 'Connect Your Bank' call-to-action) and the post-connection state (showing the actual financial data). Tell V0 about both states so it generates components that handle the transition smoothly. The Plaid Link widget itself is a Plaid-hosted UI component that appears as a modal overlay — your V0 component does not generate the bank login screens, only the surrounding dashboard and the button that triggers Link. Describe what the connected state shows: account balance cards (one card per bank account), a transaction list with merchant, amount, date, and Plaid's automatic category, and any summary charts. Be specific about the API endpoint paths (/api/plaid/link-token for getting the token, /api/plaid/data for fetching account and transaction data after connection). V0 generates the component with React hooks for managing connection state naturally — the Plaid Link SDK is loaded via the react-plaid-link npm package which integrates well with V0-generated React components. After generating, push to GitHub via V0's Git panel.

V0 Prompt

Build a personal finance dashboard with two states. Disconnected state: show a centered card with a bank icon, headline 'Connect your bank to get started', subtext 'Securely connect with Plaid — we never see your credentials', and a large 'Connect Bank Account' button. Connected state: show 3 account balance cards at the top (Account Name, Type badge, Balance), then a transactions table with Merchant, Category, Amount, and Date columns showing last 30 transactions. Include a Disconnect button in the top right. The button calls POST /api/plaid/link-token to get the Link token, then opens Plaid Link. After Plaid onSuccess, POST the public_token to /api/plaid/exchange. Use a clean fintech design with a dark navy and green color scheme.

Paste this in V0 chat

Pro tip: Install react-plaid-link by prompting V0 with 'Use the react-plaid-link package to open the Plaid Link widget when the Connect button is clicked. Install it with npm install react-plaid-link.' This package wraps the Plaid Link script and provides the usePlaidLink hook that integrates naturally with V0-generated React components.

Expected result: A personal finance dashboard renders in V0's preview with Connect Bank Account button in the disconnected state. The component is ready to open Plaid Link and handle the post-connection state with account and transaction data.

2

Create the Plaid API Routes for Token Exchange and Data Fetching

Create the Next.js API routes that handle the Plaid authentication flow and data retrieval. There are three key routes: first, POST /api/plaid/link-token creates a Link token using your server-side Plaid credentials — this token is safe to send to the browser and is used to initialize the Plaid Link widget. Second, POST /api/plaid/exchange receives the public_token from the browser after the user successfully connects their bank, exchanges it for a permanent access_token using the Plaid secret key (this exchange must happen server-side), and stores the access token for future use. In this tutorial the access token is returned to the client and stored in localStorage or React state for simplicity — production apps should store it in a server-side database keyed to the authenticated user. Third, GET /api/plaid/data uses the stored access_token to fetch account balances and recent transactions. Install the Plaid SDK with npm install plaid. The Plaid SDK is initialized with your client ID and secret — use PlaidEnvironments.sandbox during development and PlaidEnvironments.production when ready for real bank connections. The sandbox environment provides pre-built test accounts (use username user_good, password pass_good in Plaid Link when testing) that return realistic simulated financial data.

app/api/plaid/link-token/route.ts
1// app/api/plaid/link-token/route.ts
2import { NextResponse } from 'next/server';
3import { Configuration, PlaidApi, PlaidEnvironments, Products, CountryCode } from 'plaid';
4
5const plaidConfig = new Configuration({
6 basePath: PlaidEnvironments[process.env.PLAID_ENV as keyof typeof PlaidEnvironments || 'sandbox'],
7 baseOptions: {
8 headers: {
9 'PLAID-CLIENT-ID': process.env.PLAID_CLIENT_ID,
10 'PLAID-SECRET': process.env.PLAID_SECRET,
11 },
12 },
13});
14
15const plaidClient = new PlaidApi(plaidConfig);
16
17export async function POST() {
18 if (!process.env.PLAID_CLIENT_ID || !process.env.PLAID_SECRET) {
19 return NextResponse.json(
20 { error: 'Plaid credentials are not configured' },
21 { status: 500 }
22 );
23 }
24
25 try {
26 const response = await plaidClient.linkTokenCreate({
27 user: { client_user_id: 'user-' + Date.now() },
28 client_name: 'My Finance App',
29 products: [Products.Transactions],
30 country_codes: [CountryCode.Us],
31 language: 'en',
32 });
33
34 return NextResponse.json({ link_token: response.data.link_token });
35 } catch (error: any) {
36 console.error('Plaid link token error:', error.response?.data || error.message);
37 return NextResponse.json(
38 { error: 'Failed to create Plaid link token' },
39 { status: 500 }
40 );
41 }
42}

Pro tip: For the token exchange route (app/api/plaid/exchange/route.ts), the Plaid SDK call is plaidClient.itemPublicTokenExchange({ public_token }). The returned access_token should be stored in a database in production — never log it or expose it in API responses beyond the initial exchange.

Expected result: POST /api/plaid/link-token returns a link_token that can be passed to the react-plaid-link usePlaidLink hook. After completing Plaid Link in the browser, the public_token can be exchanged for an access_token via POST /api/plaid/exchange.

3

Create the Data Fetching Routes and Handle Token Exchange

Create the remaining Plaid API routes for token exchange and financial data retrieval. The exchange route is critical — it receives the public_token from the browser and exchanges it server-side for a permanent access_token. The data route uses the access_token to fetch account balances and transactions. Create app/api/plaid/exchange/route.ts for the token exchange and app/api/plaid/data/route.ts for data fetching. For the data route, use plaidClient.accountsBalanceGet({ access_token }) to get real-time account balances and plaidClient.transactionsGet({ access_token, start_date: '2024-01-01', end_date: '2024-12-31' }) for transaction history. Transactions come back with merchant_name, amount (positive for credits, negative for debits in Plaid's convention), date, and personal_finance_category with a primary and detailed category. For local testing, add PLAID_CLIENT_ID, PLAID_SECRET, and PLAID_ENV=sandbox to .env.local. When running Plaid Link in the browser with sandbox credentials, use the test institution 'Plaid Checking' (appears in the search) and enter username user_good, password pass_good to get realistic simulated account data. This gives you a complete working demo without any real bank credentials.

V0 Prompt

Update the dashboard to handle the full Plaid flow: 1) when the Connect Bank button is clicked, POST to /api/plaid/link-token and store the returned link_token. 2) Pass the link_token to usePlaidLink from react-plaid-link. 3) When Plaid onSuccess fires with public_token, POST to /api/plaid/exchange to get the access_token. 4) Store the access_token in component state. 5) Immediately fetch GET /api/plaid/data?access_token={access_token} and show the returned accounts and transactions. Handle loading states at each step with appropriate spinners and messages like 'Connecting your bank...' and 'Loading your transactions...'.

Paste this in V0 chat

app/api/plaid/data/route.ts
1// app/api/plaid/data/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3import { Configuration, PlaidApi, PlaidEnvironments } from 'plaid';
4
5const plaidConfig = new Configuration({
6 basePath: PlaidEnvironments[process.env.PLAID_ENV as keyof typeof PlaidEnvironments || 'sandbox'],
7 baseOptions: {
8 headers: {
9 'PLAID-CLIENT-ID': process.env.PLAID_CLIENT_ID,
10 'PLAID-SECRET': process.env.PLAID_SECRET,
11 },
12 },
13});
14
15const plaidClient = new PlaidApi(plaidConfig);
16
17export async function GET(request: NextRequest) {
18 const { searchParams } = new URL(request.url);
19 const accessToken = searchParams.get('access_token');
20
21 if (!accessToken) {
22 return NextResponse.json({ error: 'access_token is required' }, { status: 400 });
23 }
24
25 try {
26 // Fetch account balances
27 const balancesResponse = await plaidClient.accountsBalanceGet({
28 access_token: accessToken,
29 });
30
31 // Fetch last 30 days of transactions
32 const endDate = new Date().toISOString().split('T')[0];
33 const startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
34 .toISOString()
35 .split('T')[0];
36
37 const transactionsResponse = await plaidClient.transactionsGet({
38 access_token: accessToken,
39 start_date: startDate,
40 end_date: endDate,
41 });
42
43 const accounts = balancesResponse.data.accounts.map((account) => ({
44 id: account.account_id,
45 name: account.name,
46 type: account.type,
47 subtype: account.subtype,
48 balance: account.balances.current,
49 currency: account.balances.iso_currency_code || 'USD',
50 }));
51
52 const transactions = transactionsResponse.data.transactions.map((txn) => ({
53 id: txn.transaction_id,
54 merchant: txn.merchant_name || txn.name,
55 amount: txn.amount,
56 date: txn.date,
57 category: txn.personal_finance_category?.primary || 'Other',
58 }));
59
60 return NextResponse.json({ accounts, transactions });
61 } catch (error: any) {
62 console.error('Plaid data fetch error:', error.response?.data || error.message);
63 return NextResponse.json(
64 { error: 'Failed to fetch account data' },
65 { status: 500 }
66 );
67 }
68}

Pro tip: In a production app, never accept the access_token from the browser as a query parameter — it should be stored server-side (in a database) and retrieved by user ID from an authenticated session. The pattern in this tutorial is simplified for getting started quickly.

Expected result: After completing Plaid Link in the browser, the dashboard successfully fetches and displays account balances and recent transactions from the user's connected bank account.

4

Configure Vercel Environment Variables and Deploy

Add Plaid credentials to Vercel and deploy the integration. Open the Vercel Dashboard, navigate to your project, and go to Settings → Environment Variables. Add PLAID_CLIENT_ID and PLAID_SECRET from the Plaid Dashboard — never use the NEXT_PUBLIC_ prefix for these, as they must remain server-only. Add PLAID_ENV set to 'sandbox' for development and testing, and 'production' when you have Plaid production access. After adding variables for all scopes (Production, Preview, Development), save and trigger a redeployment. Test the deployed integration: click Connect Bank Account in your deployed app, which should open Plaid Link. In sandbox mode, use the test institution 'Plaid Checking' and credentials user_good / pass_good to connect a simulated account. After connecting, the dashboard should load with realistic simulated balance and transaction data. Moving to production requires applying for Plaid production access through the Plaid Dashboard — Plaid reviews applications and requires you to agree to their API usage agreement, privacy policy, and demonstrate how user data will be handled. For apps handling real financial data, ensure you have reviewed Plaid's compliance requirements and implemented proper access token storage in a database rather than the simplified client-side approach used in this tutorial.

Pro tip: Set PLAID_ENV to 'sandbox' for all Vercel environments during development. When ready for production, create a separate Production environment variable with PLAID_ENV=production and your production Plaid secret — this lets you test in sandbox on Preview deployments while serving real bank connections on your production domain.

Expected result: The deployed app opens Plaid Link, accepts sandbox bank connection, and displays simulated account balances and transactions in the V0-generated dashboard. The integration is ready for sandbox testing and eventual production approval.

Common use cases

Personal Finance Dashboard with Bank Connection

A personal finance app where users connect their bank accounts via Plaid Link and immediately see their account balances and recent transactions in a clean dashboard. V0 generates the dashboard layout with account cards and a transaction table; Next.js API routes handle the full Plaid token exchange flow and data fetching.

V0 Prompt

Build a personal finance dashboard. Show a 'Connect Your Bank' button that opens Plaid Link (calling POST /api/plaid/link-token to get the token first). After bank connection success, display account balance cards showing account name, type (Checking, Savings, Credit), and current balance. Below the cards, show a transaction list for the last 30 days with merchant name, amount (negative for debits), and date. Data loads from GET /api/plaid/data after connection. Use a clean fintech design with dark blue accents.

Copy this prompt to try it in V0

Expense Tracker by Category

An expense categorization tool that fetches the last 90 days of transactions from Plaid and groups them by spending category (Food, Travel, Entertainment, Shopping, etc.). V0 generates the pie chart and category breakdown table; the API route fetches transactions and uses Plaid's automatic categorization data.

V0 Prompt

Create an expense tracker showing spending by category. On load, fetch transactions from GET /api/plaid/transactions?days=90. Group transactions by their category and display a donut chart of spending by category (Food, Travel, Entertainment, Shopping, Utilities, Other). Below the chart, show a table of categories with total amount and percentage of total spending. Add a date range picker to change the analysis period. Click a category to see individual transactions for that category. Use a modern analytics design.

Copy this prompt to try it in V0

Income and Cash Flow Report

A cash flow analysis view for freelancers or small business owners who want to understand their income patterns. The dashboard shows monthly income vs expenses over the past 6 months as a bar chart, with Plaid's transaction data as the source of truth for actual cash flows.

V0 Prompt

Design a cash flow report page showing the last 6 months of income versus expenses as a grouped bar chart. Each month has two bars: income (green) and expenses (red). Below the chart, show a summary table with Month, Total Income, Total Expenses, and Net Cash Flow columns. Highlight months with positive cash flow in green and negative in red. Data comes from GET /api/plaid/cashflow?months=6. Add a note at the top 'Based on connected bank account transactions via Plaid'.

Copy this prompt to try it in V0

Troubleshooting

Plaid Link opens but shows 'Something went wrong' or fails to load

Cause: The link_token was created with incorrect credentials, is expired (link tokens expire after 30 minutes), or the browser is blocking Plaid's CDN scripts.

Solution: Verify PLAID_CLIENT_ID and PLAID_SECRET are correct and match the environment (sandbox credentials only work with PlaidEnvironments.sandbox). Generate a fresh link_token — do not cache or reuse tokens. Check browser console for Content Security Policy errors blocking Plaid's cdn.plaid.com script.

Public token exchange fails with 'invalid public token' error

Cause: Public tokens from Plaid expire after 30 minutes and can only be exchanged once. If your frontend delays the exchange call or the user takes too long completing Link, the token expires.

Solution: Exchange the public_token immediately in the Plaid Link onSuccess callback — do not store it or delay the exchange. If the exchange fails, guide the user to re-connect their bank (re-opening Plaid Link creates a new public_token). Log the exact error from Plaid's response body for diagnosis.

transactionsGet returns an PRODUCT_NOT_READY error

Cause: Plaid's transaction data is fetched asynchronously from the bank after the initial connection. For newly connected accounts, transactions are not immediately available — Plaid needs time to process them.

Solution: Wait 30-60 seconds after token exchange before fetching transactions, or implement the Plaid Transactions webhook to receive a notification when transactions are ready. In the sandbox, transactions are available immediately. In production, this initial delay of 30 seconds to a few minutes is expected.

Plaid API returns 400 with 'INVALID_ACCESS_TOKEN'

Cause: The access token is malformed, was generated in a different Plaid environment (sandbox vs production), or the item has been removed and the access token is no longer valid.

Solution: Verify PLAID_ENV matches the environment the access token was created in — sandbox tokens cannot be used with production credentials and vice versa. If the item was removed in Plaid Dashboard or the user revoked access, guide the user to reconnect their bank via Plaid Link.

Best practices

  • Never expose Plaid access tokens to the browser — store them server-side in a database keyed to authenticated user IDs, not in localStorage or client-side state
  • Always exchange public tokens immediately in the onSuccess callback — public tokens expire in 30 minutes and are single-use; any delay risks losing the connection
  • Use PlaidEnvironments.sandbox during development so no real bank credentials are ever used — Plaid's sandbox has pre-built test institutions with realistic data
  • Implement Plaid webhooks to handle token expiry notifications (ITEM_LOGIN_REQUIRED) so users are prompted to re-authenticate when their bank session expires
  • Request only the Plaid products your app actually uses in the linkTokenCreate call — requesting unnecessary products like Identity or Assets adds friction and regulatory requirements
  • For production apps, apply for Plaid production access early — the review process can take days to weeks and approval requires demonstrating proper data handling practices
  • Display clear privacy messaging alongside the bank connection UI explaining that Plaid handles authentication and your app only receives data, not bank credentials

Alternatives

Frequently asked questions

Does Plaid have a free tier for development and testing?

Yes — Plaid's sandbox environment is free and provides unlimited access for development and testing. The sandbox simulates realistic bank accounts, transactions, and error scenarios without connecting to real banks. Development environment access is also free but connects to a limited set of real banks. Production access requires applying through Plaid's Dashboard and agreeing to their usage agreement.

What test credentials should I use with Plaid sandbox?

In Plaid Link running against the sandbox environment, search for 'Plaid Checking' as the institution. Use username user_good and password pass_good to get a fully populated test account with realistic transaction history, multiple account types, and balance data. Plaid provides additional test usernames that simulate different scenarios like multi-factor authentication and OAuth flows.

How do I store Plaid access tokens securely for multiple users?

Store access tokens in a server-side database (PostgreSQL via Neon, Supabase, or MongoDB) with a record structure linking the token to your app's user ID. Never return the access token to the browser after the initial exchange — instead, make all subsequent data requests through authenticated API routes that retrieve the token from the database by user ID from the session.

What happens when a user's bank session expires and the Plaid access token is no longer valid?

Plaid sends an ITEM_LOGIN_REQUIRED webhook event when a bank session expires and the access token can no longer retrieve data. Set up a Plaid webhook endpoint in your app to receive these events, then prompt the affected user to re-authenticate by opening Plaid Link with the update mode parameter — this lets them re-enter their bank credentials without creating a new item.

Can I use Plaid to verify bank accounts for ACH payments?

Yes — Plaid's Auth product provides routing and account numbers for ACH transfers. When creating the Link token, include Products.Auth in the products array. After connecting, call plaidClient.authGet({ access_token }) to retrieve routing and account numbers. Plaid also offers Instant Account Verification (IAV) specifically optimized for ACH payment flows.

Does V0 understand Plaid's integration pattern well enough to generate useful code?

V0 generates accurate React components and can reference the react-plaid-link package if you mention it in your prompt. The UI layer — bank connection buttons, dashboard cards, transaction tables — is well within V0's capabilities. The API routes for token exchange and Plaid SDK calls are best written manually or with specific prompting since the Plaid flow requires precise server-side security handling that V0 may simplify. Use V0 for the frontend and write the API routes carefully following Plaid's documentation.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.