Help us improve
Share bugs, ideas, or general feedback.
From bopen-tools
Integrates Plaid API for bank account linking, transaction syncing, and financial data access in TypeScript/Bun applications. Covers client setup, link tokens, token exchange, pagination, errors, and SQLite schema.
npx claudepluginhub b-open-io/claude-plugins --plugin bopen-toolsHow this skill is triggered — by the user, by Claude, or both
Slash command
/bopen-tools:plaid-integrationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Integrate Plaid for connecting bank accounts and syncing transactions in TypeScript applications using Bun.
Provides patterns for Plaid API integration: link token creation/exchange, transaction sync, identity verification, ACH auth, balance checks, webhook handling, and compliance.
Connects bank accounts via Plaid for automatic daily transaction imports into Wilson. Performs initial 30-day sync, deduplication using transaction_search, and auto-categorization. Requires Pro license.
Guides banking API integrations: Open Banking (PSD2, UK OB, FDX), Plaid (Link, transactions, balance, identity), BaaS (Unit, Synapse, Column), PISP/AISP payments, and security (mTLS, OAuth2, FAPI).
Share bugs, ideas, or general feedback.
Integrate Plaid for connecting bank accounts and syncing transactions in TypeScript applications using Bun.
bun add plaid
import { Configuration, PlaidApi, PlaidEnvironments } from 'plaid';
const plaidClient = new PlaidApi(new Configuration({
basePath: PlaidEnvironments[process.env.PLAID_ENV || 'sandbox'],
baseOptions: {
headers: {
'PLAID-CLIENT-ID': process.env.PLAID_CLIENT_ID,
'PLAID-SECRET': process.env.PLAID_SECRET,
}
}
}));
Omit redirect_uri to use popup mode — required for local HTTP development:
const response = await plaidClient.linkTokenCreate({
user: { client_user_id: `user-${Date.now()}` },
client_name: 'My App',
products: ['transactions'],
country_codes: ['US'],
language: 'en',
// No redirect_uri = popup mode, works with HTTP localhost
});
const linkToken = response.data.link_token;
After the user completes Link, exchange the temporary public_token for a permanent access_token:
const response = await plaidClient.itemPublicTokenExchange({ public_token });
const { access_token, item_id } = response.data;
// Store access_token securely — never expose to clients
Plaid returns a maximum of 500 transactions per request. Always paginate:
let offset = 0;
const count = 500;
while (true) {
const response = await plaidClient.transactionsGet({
access_token,
start_date: '2023-01-01',
end_date: '2024-12-31',
options: { count, offset },
});
// Process response.data.transactions
offset += response.data.transactions.length;
if (offset >= response.data.total_transactions) break;
}
For ongoing incremental updates, prefer transactionsSync with a cursor — see references/api-reference.md.
Catch Plaid errors from error.response?.data:
try {
await plaidClient.transactionsGet({ ... });
} catch (error: any) {
const plaidError = error.response?.data;
if (!plaidError) throw error;
switch (plaidError.error_code) {
case 'ITEM_LOGIN_REQUIRED':
// Re-initialize Link in update mode
break;
case 'INVALID_ACCESS_TOKEN':
// Token revoked — delete item, prompt re-link
break;
case 'PRODUCT_NOT_READY':
// Data still processing — retry after delay
break;
default:
throw new Error(`Plaid error: ${plaidError.error_code} — ${plaidError.error_message}`);
}
}
Use Bun SQLite with items → accounts → transactions hierarchy. For the complete schema with indexes, prepared statements, and TypeScript types, see references/code-examples.md.
references/code-examples.md — Full working implementations: bank connection flow with Elysia server, transaction sync with pagination, complete Bun SQLite database module, CLI integrationreferences/api-reference.md — All API endpoints with request/response shapes, sandbox test credentials, webhook events, rate limits