Fintech apps rarely start from scratch anymore. When a user links a checking account to your app, odds are Plaid sits in the middle, translating bank logins into clean JSON your backend can use. The Plaid API powers account linking, balance checks, transaction history, and identity verification for thousands of apps including Venmo, Robinhood, and Chime.
This guide walks you through the Plaid API from a developer perspective: how to get keys, how the Link token flow works end to end, which products you should know, and what the common errors mean when things break in production. You will also see how to test every step with Apidog so you stop guessing at request payloads. If you want the raw source of truth, keep the official Plaid documentation open in a second tab as you read.
Open banking is a crowded space, and Plaid is one option among several. If you are still comparing vendors, our rundown of the best open banking APIs is a useful companion. For this post, assume you have picked Plaid and are ready to ship.
TL;DR
- Plaid is a financial data aggregator that connects your app to more than 12,000 banks across the US, Canada, and Europe.
- You get three environments out of the box: sandbox (free, fake data), development (100 free live Items), and production (pay per call).
- The linking flow is a four-step handshake: create
link_tokenserver-side, open Plaid Link client-side, exchangepublic_tokenforaccess_token, then call product endpoints. - Core products are Auth, Balance, Transactions, Identity, Investments, Liabilities, and Income. You enable them per Item.
- The most common production errors are
ITEM_LOGIN_REQUIREDandINVALID_CREDENTIALS. Webhooks tell you when an Item needs attention. - Rate limits are per-Item and per-client. Batch your reads and listen to webhooks instead of polling.
What is Plaid?
Plaid is a US-based fintech infrastructure company that sits between your app and a user’s bank. When a user types their bank credentials into Plaid Link, Plaid connects to the bank (through official open banking APIs where available, or reverse-engineered bank websites where not), pulls the requested data, normalizes it, and hands you a consistent JSON response regardless of which bank it came from.
You never see or store the user’s bank credentials. Plaid holds the connection, which it calls an Item, and gives you an access_token that represents permission to query that Item. One Item equals one set of credentials at one financial institution, and may include multiple accounts (checking, savings, credit card).
Plaid covers consumer checking and savings accounts, credit cards, loans, investment accounts, and payroll data. It does not move money on its own; for ACH transfers you typically pair Plaid Auth with a separate payments processor. Our writeup on the best ACH payments APIs explains how that pairing usually looks.
Authentication and setup
Step 1: Create a Plaid developer account
Sign up at plaid.com and verify your email. You land in the Plaid Dashboard with three environments already provisioned:
- Sandbox: fake institutions, fake users, no cost. Use
user_good/pass_goodto log in. - Development: real bank connections, capped at 100 live Items, free.
- Production: real connections, unlimited, metered billing.
Step 2: Grab your keys
From the Dashboard, go to Team Settings > Keys. You need two values:
client_id: the same across all environmentssecret: different per environment (sandbox, development, production)
Store these in environment variables. Never commit them to git.
Step 3: Install the SDK
The official Node.js SDK lives at github.com/plaid/plaid-node.
npm install plaid
Step 4: Initialize the client
import { Configuration, PlaidApi, PlaidEnvironments } from 'plaid';
const config = new Configuration({
basePath: PlaidEnvironments.sandbox,
baseOptions: {
headers: {
'PLAID-CLIENT-ID': process.env.PLAID_CLIENT_ID,
'PLAID-SECRET': process.env.PLAID_SECRET,
},
},
});
const client = new PlaidApi(config);
Swap PlaidEnvironments.sandbox for .development or .production when you promote.
Core endpoints
The Link token flow
Every Plaid integration follows the same four-step dance. You do steps 1 and 3 server-side; Plaid Link handles step 2 in the user’s browser or mobile app.
Step 1: Create a link_token
const response = await client.linkTokenCreate({
user: { client_user_id: 'user_123' },
client_name: 'Your App',
products: ['auth', 'transactions'],
country_codes: ['US'],
language: 'en',
});
const linkToken = response.data.link_token;
The curl version:
curl -X POST https://sandbox.plaid.com/link/token/create \
-H 'Content-Type: application/json' \
-d '{
"client_id": "YOUR_CLIENT_ID",
"secret": "YOUR_SANDBOX_SECRET",
"user": { "client_user_id": "user_123" },
"client_name": "Your App",
"products": ["auth", "transactions"],
"country_codes": ["US"],
"language": "en"
}'
Step 2: Open Plaid Link in the client
Send the link_token to your frontend and pass it into the Plaid Link SDK. The user picks their bank, logs in, and Plaid returns a public_token to your onSuccess callback.
Step 3: Exchange the public_token
const exchange = await client.itemPublicTokenExchange({
public_token: publicToken,
});
const accessToken = exchange.data.access_token;
const itemId = exchange.data.item_id;
Store accessToken server-side, tied to your user. This token is long-lived and is what you use for every future call.
Step 4: Call product endpoints
const accounts = await client.accountsGet({ access_token: accessToken });
const balance = await client.accountsBalanceGet({ access_token: accessToken });
Product endpoints you should know
- Auth returns account and routing numbers for ACH (
/auth/get). - Balance returns real-time balances, bypassing cache (
/accounts/balance/get). - Transactions returns up to 24 months of cleaned transaction data (
/transactions/sync). - Identity returns account holder name, email, phone, address (
/identity/get). If your use case is pure KYC, compare it against dedicated providers in our best KYC API roundup. - Investments returns holdings and investment transactions (
/investments/holdings/get). - Liabilities returns student loan, credit card, and mortgage details (
/liabilities/get). - Income returns payroll data through Plaid Income (
/credit/payroll_income/get).
Testing the Plaid API with Apidog
Testing Plaid end to end is awkward because the Link step happens in a browser. You still need a reliable way to hit the server-side endpoints with valid payloads, see how errors surface, and share working requests with teammates. Apidog handles that better than most tools.
Import Plaid’s OpenAPI spec into Apidog and you get every endpoint pre-configured with types, example bodies, and the right auth headers. You can create a sandbox environment variable set (client_id, secret, access_token) and switch to production with one click. Chained requests let you run linkTokenCreate → sandboxPublicTokenCreate → itemPublicTokenExchange → accountsGet in a single flow, so you can verify the full handshake without a browser.
Apidog’s mock server is useful when your frontend team needs /accounts/get responses before your backend integration is done. If you are moving off another tool, our guide on API testing without Postman in 2026 covers the migration in detail. Download Apidog and point it at Plaid’s spec to get started.
Common errors and rate limits
Plaid errors come back with an error_type, error_code, and human-readable error_message. Handle these four in production:
INVALID_CREDENTIALS: the user typed the wrong password at the bank. Prompt them to try again via Link update mode.ITEM_LOGIN_REQUIRED: the bank invalidated the session (password change, MFA rotation). Trigger Link in update mode to re-authenticate. You learn about this through a webhook, not a failed call.RATE_LIMIT_EXCEEDED: you hit a per-Item or per-endpoint limit. Back off, then retry with jitter.PRODUCT_NOT_READY: Transactions data is still being pulled. Retry after theINITIAL_UPDATEwebhook fires.
Webhooks
Pass a webhook URL when you create the link_token and Plaid will POST updates to it. The three you cannot ignore are SYNC_UPDATES_AVAILABLE (new transactions), ITEM: LOGIN_REQUIRED (re-auth needed), and ITEM: ERROR (permanent failure). Verify the JWT signature on every webhook before acting on it.
Rate limits
Plaid enforces rate limits per-Item per-endpoint. For example, /accounts/balance/get is capped around 5 calls per minute per Item in production. Aggregate client-level limits also apply on heavy endpoints. The practical rule: poll webhooks, cache balances for a few minutes, and never hit Plaid from a user-facing request path.
Plaid pricing
Plaid uses tiered pay-per-API-call pricing in production. The ballpark:
- Sandbox: free, unlimited.
- Development: free up to 100 Items.
- Production:
- Auth: roughly $1.50 per linked account, one-time.
- Balance: per-call pricing.
- Transactions: monthly per-Item fee (around $0.30).
- Identity: per-call.
- Investments / Liabilities / Income: separate per-Item fees.
Plaid negotiates custom pricing above certain volumes, so the public rate card is a starting point. Check the Plaid products page for the current numbers.
FAQ
How long does an access_token last?Indefinitely, until the user revokes access or the bank invalidates the session. Store it encrypted and do not expire it on your side.
Can I use Plaid for identity verification alone?You can use Plaid Identity, but if your primary need is KYC you may be better served by a dedicated verification product. We cover the tradeoffs in our guide on how to use the Stripe Identity API.
Does Plaid support countries outside the US?Yes. Plaid covers the US, Canada, UK, and most of the EU. Country support varies per product; check the country codes parameter in the /link/token/create call.
What happens if a user changes their bank password?The Item moves into ITEM_LOGIN_REQUIRED state and you get a webhook. Trigger Plaid Link in update mode and the user re-authenticates without losing their access_token.
Can I test the Link flow without a real browser?Yes. The /sandbox/public_token/create endpoint skips Link entirely and returns a public_token you can exchange. Use it for automated integration tests.
How do I handle Plaid in local development?Keep a sandbox secret in your .env file and wire your dev environment to PlaidEnvironments.sandbox. Use tunneling (ngrok, Cloudflare Tunnel) to receive webhooks locally.



