mcpField
P
plaid

plaid

github.com/raintree-technology開発64 回インストール
リポジトリ

plaid について

Plaid Banking API を利用する開発者向けの実装リファレンスです。口座接続、金融データ、決済、本人確認に加え、Link フロー、Webhook、環境設定、安全な取り扱いを説明します。

主な機能

  1. 01Plaid Link による口座接続フロー
  2. 02取引、残高、口座情報の取得
  3. 03Auth、Identity、Investments、Liabilities 製品
  4. 04ACH 送金と Webhook の処理
  5. 05Sandbox、Development、Production 環境
  6. 06トークン保護と再認証のガイダンス

活用シーン

  1. 01フィンテックアプリで銀行口座を接続
  2. 02取引履歴や現在残高の取得
  3. 03ACH 送金向けの口座情報読み取り
  4. 04取引更新や口座接続エラーへの対応

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/raintree-technology/claude-starter --skill plaid

インストール後、Claude Code で/plaidを入力して読み込まれたか確認します。

詳細

Plaid Banking API エキスパート

Plaid は、金融データへのアクセス、決済、本人確認のために、アプリケーションをユーザーの銀行口座に接続します。

使用する場面

  • フィンテックアプリで銀行口座を接続する
  • Plaid Link フローを実装する
  • 取引履歴、残高、口座情報を取得する
  • ACH 送金を設定する
  • 本人確認・収入確認を行う
  • Plaid ウェブフックを処理する

主な製品

製品用途
AuthACH 用の銀行口座番号・ルーティング番号
Transactions取引履歴(最大 24 か月分)
Identity銀行口座の所有権によるユーザー確認
Balanceリアルタイムの口座残高
Investments投資口座の保有資産
Liabilitiesローンおよびクレジットカードのデータ

クイックスタート

1. SDK をインストールする
npm install plaid react-plaid-link
2. Plaid クライアントを作成する
import { Configuration, PlaidApi, PlaidEnvironments } from "plaid";

const client = new PlaidApi(
  new Configuration({
    basePath: PlaidEnvironments.sandbox,
    baseOptions: {
      headers: {
        "PLAID-CLIENT-ID": process.env.PLAID_CLIENT_ID,
        "PLAID-SECRET": process.env.PLAID_SECRET,
      },
    },
  })
);
3. Link トークンを作成する(サーバー)
// POST /api/plaid/create-link-token
export async function POST(req: Request) {
  const response = await client.linkTokenCreate({
    user: { client_user_id: userId },
    client_name: "Your App",
    products: ["auth", "transactions"],
    country_codes: ["US"],
    language: "en",
  });

  return Response.json({ link_token: response.data.link_token });
}
4. Plaid Link(クライアント)
import { usePlaidLink } from "react-plaid-link";

function ConnectBank({ linkToken }) {
  const { open, ready } = usePlaidLink({
    token: linkToken,
    onSuccess: async (public_token, metadata) => {
      // Exchange for access_token on server
      await fetch("/api/plaid/exchange-token", {
        method: "POST",
        body: JSON.stringify({ public_token }),
      });
    },
  });

  return (
    <button onClick={() => open()} disabled={!ready}>
      Connect Bank Account
    </button>
  );
}
5. トークンを交換する(サーバー)
// POST /api/plaid/exchange-token
export async function POST(req: Request) {
  const { public_token } = await req.json();

  const response = await client.itemPublicTokenExchange({
    public_token,
  });

  // Store access_token securely (encrypted in database)
  await db.users.update(userId, {
    plaid_access_token: response.data.access_token,
    plaid_item_id: response.data.item_id,
  });

  return Response.json({ success: true });
}

データの取得

Auth の取得(口座番号・ルーティング番号)
const response = await client.authGet({ access_token });

const ach = response.data.numbers.ach[0];
console.log("Account:", ach.account);
console.log("Routing:", ach.routing);
取引履歴の取得
const response = await client.transactionsGet({
  access_token,
  start_date: "2024-01-01",
  end_date: "2024-12-31",
});

let transactions = response.data.transactions;

// Handle pagination
while (transactions.length < response.data.total_transactions) {
  const more = await client.transactionsGet({
    access_token,
    start_date: "2024-01-01",
    end_date: "2024-12-31",
    offset: transactions.length,
  });
  transactions = transactions.concat(more.data.transactions);
}

取引オブジェクト:

{
  transaction_id: "abc123",
  amount: 12.34,           // Positive = outflow
  date: "2024-11-16",
  name: "Starbucks",
  merchant_name: "Starbucks",
  category: ["Food and Drink", "Coffee Shop"],
  pending: false,
}
残高の取得
const response = await client.accountsBalanceGet({ access_token });

response.data.accounts.forEach((account) => {
  console.log(`${account.name}: $${account.balances.current}`);
});
本人確認情報の取得
const response = await client.identityGet({ access_token });

const owner = response.data.accounts[0].owners[0];
console.log("Name:", owner.names[0]);
console.log("Email:", owner.emails[0].data);
console.log("Phone:", owner.phone_numbers[0].data);

ウェブフック

エンドポイントの設定
// POST /api/plaid/webhook
export async function POST(req: Request) {
  const { webhook_type, webhook_code, item_id } = await req.json();

  switch (webhook_type) {
    case "TRANSACTIONS":
      if (webhook_code === "DEFAULT_UPDATE") {
        // New transactions available - fetch them
        await syncTransactions(item_id);
      }
      break;

    case "ITEM":
      if (webhook_code === "ERROR") {
        // Connection issue - prompt user to re-authenticate
        await notifyUserReauth(item_id);
      }
      break;
  }

  return Response.json({ received: true });
}

主なウェブフックイベント:

イベント意味
TRANSACTIONS: INITIAL_UPDATE最初のバッチの準備完了
TRANSACTIONS: DEFAULT_UPDATE新しい取引
ITEM: ERROR接続の問題
ITEM: PENDING_EXPIRATION認証情報の有効期限が近づいています

環境

環境用途ベースパス
SandboxテストPlaidEnvironments.sandbox
Development制限付きの本番利用(100 接続)PlaidEnvironments.development
Production本番PlaidEnvironments.production
Sandbox テスト用認証情報
  • ユーザー名:user_good
  • パスワード:pass_good
  • MFA:1234

エラー処理

再認証(更新モード)

認証情報の有効期限が切れた場合:

// Create link token for update mode
const response = await client.linkTokenCreate({
  user: { client_user_id: userId },
  client_name: "Your App",
  access_token: existingAccessToken, // Triggers update mode
  country_codes: ["US"],
  language: "en",
});
よくあるエラー
エラー解決方法
ITEM_LOGIN_REQUIREDLink の更新モードで再認証する
RATE_LIMIT_EXCEEDED指数バックオフを実装する
PRODUCT_NOT_READYウェブフックを待つか、再試行する

セキュリティのベストプラクティス

実施すること:

  • データベース内のアクセストークンを暗号化して保存する
  • 認証情報には環境変数を使用する
  • ウェブフックの署名を検証する
  • すべてのエンドポイントで HTTPS を使用する

実施しないこと:

  • シークレットキーをクライアント側に公開する
  • アクセストークンをログに記録する
  • 認証情報をコード内に保存する

Next.js App Router の例

// app/api/plaid/create-link-token/route.ts
import { NextResponse } from "next/server";
import { Configuration, PlaidApi, PlaidEnvironments } from "plaid";

const client = new PlaidApi(
  new Configuration({
    basePath: PlaidEnvironments.sandbox,
    baseOptions: {
      headers: {
        "PLAID-CLIENT-ID": process.env.PLAID_CLIENT_ID!,
        "PLAID-SECRET": process.env.PLAID_SECRET!,
      },
    },
  })
);

export async function POST(req: Request) {
  const session = await getSession();

  const response = await client.linkTokenCreate({
    user: { client_user_id: session.user.id },
    client_name: "Your App",
    products: ["auth", "transactions"],
    country_codes: ["US"],
    language: "en",
    webhook: `${process.env.NEXT_PUBLIC_URL}/api/plaid/webhook`,
  });

  return NextResponse.json({ link_token: response.data.link_token });
}

実装チェックリスト

  • Plaid アカウントに登録する
  • クライアント ID とシークレットを取得する
  • plaid と react-plaid-link をインストールする
  • 環境変数を設定する
  • Link トークンのエンドポイントを作成する
  • トークン交換エンドポイントを実装する
  • フロントエンドに Plaid Link を統合する
  • アクセストークンを安全に保存する
  • ウェブフックのエンドポイントを設定する
  • 再認証エラーを処理する
  • Sandbox の認証情報でテストする

リソース

コメント