# Money Forward×Vertex AI財務分析自動化実践ガイド|AIで財務データから洞察を抽出 ## はじめに こんにちは。PlanitAI技術ブログ編集部です。 ビジネスを運営する中で、会計データを分析し、財務インサイトを得ることは非常に重要です。しかし、Money Forwardのダッシュボードを毎日確認し、数字を読み解き、傾向を分析する作業は時間がかかります。 「今月の財務状況はどうか?」というシンプルな質問に対して、AIが自動的にデータを分析し、人間が理解しやすい言葉でインサイトを提供してくれたら、どれだけ便利でしょうか。 本記事では、**Money Forward Business APIとVertex AI(Gemini)を組み合わせて、財務データを自動分析するシステム**を構築する実践ガイドをご紹介します。TypeScriptを使用し、実際に動作するコードとともに、ステップバイステップで解説していきます。 ## 実行結果のイメージ まず、このシステムを実行するとどのような結果が得られるのか、実際の出力例をご覧ください。 **OAuth認証**: ``` $ pnpm run auth Money Forward OAuth 認証 CLI Money Forward OAuth 認証開始 次のURLをブラウザで開いてください: https://api.biz.moneyforward.com/authorize?client_id=... OAuth Callback サーバーが http://localhost:3000 で起動しました 認証が完了しました! トークンが保存されました: .tokens/mf-tokens.json ``` **APIテスト**: ``` $ pnpm run test:api Money Forward API テスト 3 /v2/tenant エンドポイントテスト中... Tenant 情報 (v2): { "tenant_code": "XXXX-XXXX", "tenant_name": "株式会社サンプル" } ``` **Vertex AIによる財務分析**: ``` $ pnpm run analyze > moneyforward-vertexai-analyzer@1.0.0 analyze > tsx src/index.ts Money Forward + Vertex AI 財務分析ツール ============================================================ Step 1: Money Forward データ収集 Tenant 情報取得中... [OK] Tenant: 株式会社サンプル (XXXX-XXXX) Step 2: Vertex AI 分析準備 [OK] Vertex AI クライアント初期化完了 (Project: your-project-id, Model: gemini-2.5-flash) Step 3: AI 財務分析実行 Vertex AI に分析リクエスト中... [OK] AI 分析完了 ============================================================ 分析結果 ============================================================ 要約: 株式会社サンプルはAI技術を活用したソフトウェア開発を主力とする 日本企業です。人工知能分野の急速な成長を背景に、革新的な ソリューション提供を目標としており、技術集約型産業の特性上、 高い成長ポテンシャルを有しています。 ============================================================ [OK] 分析が完了しました! ``` ## 目次 1. プロジェクト概要と技術スタック 2. Money Forward Business API の理解 3. 開発環境のセットアップ 4. OAuth 2.0 認証の実装 5. Money Forward API クライアントの実装 6. Vertex AI(Gemini)の統合 7. AI プロンプトエンジニアリング 8. システム統合とエラーハンドリング 9. 実装時のトラブルシューティング 10. まとめと今後の展望 --- ## 1. プロジェクト概要と技術スタック ### プロジェクトの目標 このプロジェクトでは、以下の機能を持つ財務分析ツールを構築します: - **自動認証**: Money Forward Business API への OAuth 2.0 認証 - **データ収集**: 企業の財務情報を自動的に取得 - **AI 分析**: Vertex AI(Gemini 2.5 Flash)を使用した知的な分析 - **レポート生成**: わかりやすい日本語でのインサイト提供 ### 技術スタック ```typescript { "主要技術": { "言語": "TypeScript 5.9", "ランタイム": "Node.js v18+", "パッケージマネージャー": "pnpm 10.x", "API": [ "Money Forward Business API", "Google Cloud Vertex AI" ] }, "主要ライブラリ": { "HTTPクライアント": "axios 1.13.2", "AI SDK": "@google-cloud/vertexai 1.10.0", "環境変数": "dotenv 17.2.3", "CLI表示": "chalk 5.6.2" } } ``` ### プロジェクト構造 ``` project/ ├── src/ │ ├── moneyforward/ │ │ ├── auth.ts # OAuth 2.0 認証ロジック │ │ ├── client.ts # API クライアント │ │ └── oauth-server.ts # Callback サーバー │ ├── vertexai/ │ │ └── client.ts # Vertex AI クライアント │ ├── types/ │ │ └── index.ts # TypeScript 型定義 │ ├── cli-auth.ts # OAuth 認証 CLI │ ├── cli-test-api.ts # API テスト CLI │ └── index.ts # メイン統合スクリプト ├── .env # 環境変数 ├── .tokens/ # OAuth トークン保存 ├── package.json └── tsconfig.json ``` --- ## 2. Money Forward Business API の理解 ### Business API vs ME API の違い Money Forwardには個人向けME APIと法人向けBusiness APIがあります。本プロジェクトでは**Business API**を使用します。 | 項目 | Business API | ME API(個人用) | |------|-------------|----------------| | Base URL | `api.biz.moneyforward.com` | `moneyforward.com` | | Authorization | `/authorize` | `/oauth/authorize` | | Token | `/token` | `/oauth/v2/token` | | Scope形式 | `mfc/admin/tenant.read` | `accounts transactions` | | 認証方式 | CLIENT_SECRET_BASIC | CLIENT_SECRET_POST | | State パラメータ | **必須** | オプション | ### OAuth 2.0 フロー ``` 1. [ユーザー] → Authorization URL にアクセス https://api.biz.moneyforward.com/authorize 2. [ユーザー] → Money Forward にログイン・権限承認 3. [Money Forward] → Redirect URI に Authorization Code を送信 http://localhost:3000/callback?code=ABC123&state=xxx 4. [アプリ] → Authorization Code で Access Token をリクエスト POST https://api.biz.moneyforward.com/token 認証方式: CLIENT_SECRET_BASIC(Authorization ヘッダー) 5. [Money Forward] → Access Token を発行 { "access_token": "...", "refresh_token": "...", "expires_in": 3600 } 6. [アプリ] → Access Token で API 呼び出し GET https://api.biz.moneyforward.com/v2/tenant ``` ### API エンドポイント **事業体情報(Tenant)**: ``` GET /v2/tenant ``` レスポンス例: ```json { "tenant_code": "XXXX-XXXX", "tenant_name": "株式会社サンプル" } ``` **Expense API(経費管理)**: ``` Base URL: https://expense.moneyforward.com/api/external/v1 GET /api/external/v1/offices GET /api/external/v1/offices/{office_id}/me/ex_transactions ``` --- ## 3. 開発環境のセットアップ ### 必要な準備 1. **Node.js インストール**(v18以上) 2. **pnpm インストール** 3. **Money Forward Business アカウント** 4. **Google Cloud プロジェクト**(Vertex AI 用) ### プロジェクト初期化 ```bash # プロジェクトディレクトリ作成 mkdir moneyforward-vertexai-analyzer cd moneyforward-vertexai-analyzer # pnpm 初期化 pnpm init # 依存関係インストール pnpm add axios @google-cloud/vertexai dotenv chalk date-fns pnpm add -D typescript @types/node tsx ``` ### TypeScript 設定 `tsconfig.json`: ```json { "compilerOptions": { "target": "ES2022", "module": "commonjs", "lib": ["ES2022"], "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "moduleResolution": "node" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] } ``` ### 環境変数設定 `.env`: ```bash # Money Forward Business API MONEYFORWARD_CLIENT_ID=your_client_id MONEYFORWARD_CLIENT_SECRET=your_client_secret MONEYFORWARD_REDIRECT_URI=http://localhost:3000/callback # Google Cloud Vertex AI GOOGLE_CLOUD_PROJECT=your-project-id GOOGLE_APPLICATION_CREDENTIALS=./service-account-key.json VERTEX_AI_LOCATION=asia-northeast1 VERTEX_AI_MODEL=gemini-2.5-flash ``` --- ## 4. OAuth 2.0 認証の実装 ### MoneyForwardAuth クラス `src/moneyforward/auth.ts`: ```typescript import axios from 'axios'; import fs from 'fs/promises'; import path from 'path'; import { MFTokens } from '../types'; export class MoneyForwardAuth { private clientId: string; private clientSecret: string; private redirectUri: string; private tokenFilePath: string; constructor() { this.clientId = process.env.MONEYFORWARD_CLIENT_ID!; this.clientSecret = process.env.MONEYFORWARD_CLIENT_SECRET!; this.redirectUri = process.env.MONEYFORWARD_REDIRECT_URI!; this.tokenFilePath = path.join(process.cwd(), '.tokens', 'mf-tokens.json'); if (!this.clientId || !this.clientSecret || !this.redirectUri) { throw new Error('Money Forward OAuth 環境変数が設定されていません'); } } /** * Step 1: Authorization URL 生成 */ getAuthorizationUrl(): string { // Business API URL const baseUrl = 'https://api.biz.moneyforward.com/authorize'; // CSRF 防止用 state 生成(必須!) const state = Math.random().toString(36).substring(2, 15); const params = new URLSearchParams({ client_id: this.clientId, redirect_uri: this.redirectUri, response_type: 'code', scope: 'mfc/admin/tenant.read', // Business API scope 形式 state: state, }); return `${baseUrl}?${params.toString()}`; } /** * Step 2: Authorization Code で Access Token 発行 */ async getAccessToken(code: string): Promise { try { // CLIENT_SECRET_BASIC: Authorization ヘッダーに Base64 エンコーディング const credentials = Buffer.from( `${this.clientId}:${this.clientSecret}` ).toString('base64'); // URLSearchParams で form-urlencoded 形式を生成 const params = new URLSearchParams(); params.append('redirect_uri', this.redirectUri); params.append('code', code); params.append('grant_type', 'authorization_code'); const response = await axios.post( 'https://api.biz.moneyforward.com/token', params, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': `Basic ${credentials}`, }, } ); const tokens: MFTokens = { access_token: response.data.access_token, refresh_token: response.data.refresh_token, token_type: response.data.token_type, expires_in: response.data.expires_in, expires_at: Date.now() + response.data.expires_in * 1000, }; await this.saveTokens(tokens); return tokens; } catch (error) { if (axios.isAxiosError(error)) { throw new Error( `Access Token 発行失敗: ${error.response?.data?.error || error.message}` ); } throw error; } } /** * Refresh Token で Access Token を更新 */ async refreshAccessToken(refreshToken: string): Promise { const credentials = Buffer.from( `${this.clientId}:${this.clientSecret}` ).toString('base64'); const params = new URLSearchParams(); params.append('refresh_token', refreshToken); params.append('grant_type', 'refresh_token'); const response = await axios.post( 'https://api.biz.moneyforward.com/token', params, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': `Basic ${credentials}`, }, } ); const tokens: MFTokens = { access_token: response.data.access_token, refresh_token: response.data.refresh_token || refreshToken, token_type: response.data.token_type, expires_in: response.data.expires_in, expires_at: Date.now() + response.data.expires_in * 1000, }; await this.saveTokens(tokens); return tokens; } /** * トークンをファイルに保存 */ private async saveTokens(tokens: MFTokens): Promise { const tokenDir = path.dirname(this.tokenFilePath); await fs.mkdir(tokenDir, { recursive: true }); await fs.writeFile(this.tokenFilePath, JSON.stringify(tokens, null, 2)); console.log(' トークンが保存されました:', this.tokenFilePath); } /** * 保存されたトークンを読み込み */ async loadTokens(): Promise { try { const data = await fs.readFile(this.tokenFilePath, 'utf-8'); const tokens: MFTokens = JSON.parse(data); // トークンが期限切れかチェック if (tokens.expires_at < Date.now()) { console.log(' Access Token が期限切れです。更新中...'); return await this.refreshAccessToken(tokens.refresh_token); } return tokens; } catch (error) { return null; } } /** * 有効な Access Token を取得(自動更新含む) */ async getValidAccessToken(): Promise { const tokens = await this.loadTokens(); if (!tokens) { throw new Error( '保存されたトークンがありません。まず OAuth 認証を完了してください。' ); } return tokens.access_token; } } ``` ### OAuth Callback サーバー `src/moneyforward/oauth-server.ts`: ```typescript import http from 'http'; import { URL } from 'url'; import { MoneyForwardAuth } from './auth'; export class OAuthServer { private auth: MoneyForwardAuth; private server: http.Server | null = null; constructor() { this.auth = new MoneyForwardAuth(); } async startAuthFlow(): Promise { const authUrl = this.auth.getAuthorizationUrl(); console.log('\n Money Forward OAuth 認証開始'); console.log('\n次のURLをブラウザで開いてください:'); console.log(`\n${authUrl}\n`); await this.startServer(); } private startServer(): Promise { return new Promise((resolve, reject) => { this.server = http.createServer(async (req, res) => { const url = new URL(req.url!, `http://localhost:3000`); if (url.pathname === '/callback') { const code = url.searchParams.get('code'); const error = url.searchParams.get('error'); if (error) { res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(`

認証失敗

エラー: ${error}

`); this.stopServer(); return reject(new Error(`OAuth エラー: ${error}`)); } if (!code) { res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(`

Authorization Code がありません

`); this.stopServer(); return reject(new Error('Authorization Code がありません')); } try { await this.auth.getAccessToken(code); res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(`

認証成功!

Access Token が発行されました。

このウィンドウを閉じてターミナルに戻ってください。

`); console.log('\n OAuth 認証が完了しました!'); setTimeout(() => { this.stopServer(); resolve(); }, 1000); } catch (error) { res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(`

Token 発行失敗

${error instanceof Error ? error.message : '不明なエラー'}

`); this.stopServer(); reject(error); } } else { res.writeHead(404); res.end('Not Found'); } }); this.server.listen(3000, () => { console.log(' OAuth Callback サーバーが http://localhost:3000 で起動しました'); }); this.server.on('error', (error) => { reject(error); }); }); } private stopServer(): void { if (this.server) { this.server.close(); this.server = null; console.log(' OAuth Callback サーバーが終了しました'); } } } ``` --- ## 5. Money Forward API クライアントの実装 `src/moneyforward/client.ts`: ```typescript import axios, { AxiosInstance } from 'axios'; import { MoneyForwardAuth } from './auth'; export class MoneyForwardClient { private auth: MoneyForwardAuth; private axiosInstance: AxiosInstance; constructor() { this.auth = new MoneyForwardAuth(); this.axiosInstance = axios.create({ baseURL: 'https://api.biz.moneyforward.com', headers: { 'Content-Type': 'application/json', }, }); // リクエストインターセプター: すべてのリクエストに Access Token を追加 this.axiosInstance.interceptors.request.use(async (config) => { const accessToken = await this.auth.getValidAccessToken(); config.headers.Authorization = `Bearer ${accessToken}`; return config; }); } /** * Tenant(事業体)情報取得 */ async getTenants() { try { const response = await this.axiosInstance.get('/v2/tenant'); return response.data; } catch (error) { if (axios.isAxiosError(error)) { throw new Error( `Tenant 情報取得失敗: ${error.response?.status} - ${JSON.stringify(error.response?.data)}` ); } throw error; } } /** * 汎用 GET リクエスト */ async get(endpoint: string) { try { const response = await this.axiosInstance.get(endpoint); return response.data; } catch (error) { if (axios.isAxiosError(error)) { throw new Error( `API リクエスト失敗 (${endpoint}): ${error.response?.status} - ${JSON.stringify(error.response?.data)}` ); } throw error; } } } ``` --- ## 6. Vertex AI(Gemini)の統合 `src/vertexai/client.ts`: ```typescript import { HarmBlockThreshold, HarmCategory, VertexAI } from '@google-cloud/vertexai'; export interface AnalysisRequest { tenantInfo: { tenant_code: string; tenant_name: string; }; additionalContext?: string; } export interface AnalysisResult { summary: string; insights: string[]; recommendations: string[]; rawResponse: string; } export class VertexAIClient { private vertexAI: VertexAI; private model: string; constructor() { const projectId = process.env.GOOGLE_CLOUD_PROJECT; const location = process.env.VERTEX_AI_LOCATION || 'asia-northeast1'; this.model = process.env.VERTEX_AI_MODEL || 'gemini-2.5-flash'; if (!projectId) { throw new Error('GOOGLE_CLOUD_PROJECT 環境変数が設定されていません'); } this.vertexAI = new VertexAI({ project: projectId, location: location, }); console.log(` Vertex AI クライアント初期化完了 (Project: ${projectId}, Model: ${this.model})`); } /** * Tenant 情報を分析してインサイトを生成 */ async analyzeTenant(request: AnalysisRequest): Promise { try { const generativeModel = this.vertexAI.getGenerativeModel({ model: this.model, safetySettings: [ { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, }, ], generationConfig: { maxOutputTokens: 2048, temperature: 0.7, topP: 0.8, }, }); const prompt = this.buildAnalysisPrompt(request); console.log('\n Vertex AI に分析リクエスト中...\n'); const result = await generativeModel.generateContent(prompt); const response = result.response; const text = response.candidates?.[0]?.content?.parts?.[0]?.text || ''; console.log(' AI 分析完了\n'); return this.parseResponse(text); } catch (error) { console.error(' Vertex AI 分析失敗:', error); throw new Error( `AI 分析失敗: ${error instanceof Error ? error.message : '不明なエラー'}` ); } } /** * 分析プロンプト生成 */ private buildAnalysisPrompt(request: AnalysisRequest): string { const { tenantInfo, additionalContext } = request; return ` あなたは日本企業の財務データを分析する専門の財務アナリストです。 次の企業情報を分析してインサイトを提供してください: ## 企業情報 - 事業者コード: ${tenantInfo.tenant_code} - 会社名: ${tenantInfo.tenant_name} ${additionalContext ? `\n## 追加情報\n${additionalContext}\n` : ''} 次の形式で分析結果を提供してください: ## 要約 [企業に関する簡単な要約] ## 主要インサイト 1. [インサイト 1] 2. [インサイト 2] 3. [インサイト 3] ## 提案 1. [提案 1] 2. [提案 2] 3. [提案 3] すべての応答は日本語で作成し、会社名などの固有名詞は原文のまま維持してください。 `.trim(); } /** * AI レスポンスをパース */ private parseResponse(text: string): AnalysisResult { const sections = { summary: '', insights: [] as string[], recommendations: [] as string[], }; const summaryMatch = text.match(/##\s*要約\s*\n([\s\S]*?)(?=##|$)/i); const insightsMatch = text.match(/##\s*主要\s*インサイト\s*\n([\s\S]*?)(?=##|$)/i); const recommendationsMatch = text.match(/##\s*提案\s*\n([\s\S]*?)(?=##|$)/i); if (summaryMatch) { sections.summary = summaryMatch[1].trim(); } if (insightsMatch) { const insightsText = insightsMatch[1]; const insightsList = insightsText.match(/^\d+\.\s*(.+)$/gm) || []; sections.insights = insightsList.map((item) => item.replace(/^\d+\.\s*/, '').trim() ); } if (recommendationsMatch) { const recommendationsText = recommendationsMatch[1]; const recommendationsList = recommendationsText.match(/^\d+\.\s*(.+)$/gm) || []; sections.recommendations = recommendationsList.map((item) => item.replace(/^\d+\.\s*/, '').trim() ); } return { summary: sections.summary, insights: sections.insights, recommendations: sections.recommendations, rawResponse: text, }; } } ``` --- ## 7. システム統合 `src/index.ts`: ```typescript import 'dotenv/config'; import { MoneyForwardClient } from './moneyforward/client'; import { VertexAIClient } from './vertexai/client'; import chalk from 'chalk'; async function main() { console.log(chalk.bold.cyan('\n Money Forward + Vertex AI 財務分析ツール\n')); console.log('='.repeat(60)); console.log(''); try { // 1. Money Forward クライアント初期化 console.log(chalk.yellow(' Step 1: Money Forward データ収集\n')); const mfClient = new MoneyForwardClient(); console.log(' Tenant 情報取得中...'); const tenantData = await mfClient.get('/v2/tenant'); console.log(chalk.green(` Tenant: ${tenantData.tenant_name} (${tenantData.tenant_code})\n`)); // 2. Vertex AI クライアント初期化 console.log(chalk.yellow(' Step 2: Vertex AI 分析準備\n')); const aiClient = new VertexAIClient(); console.log(''); // 3. AI 分析実行 console.log(chalk.yellow(' Step 3: AI 財務分析実行\n')); const analysisResult = await aiClient.analyzeTenant({ tenantInfo: { tenant_code: tenantData.tenant_code, tenant_name: tenantData.tenant_name, }, additionalContext: 'この企業は AI 技術を活用したソフトウェア開発会社です。', }); // 4. 結果出力 console.log('='.repeat(60)); console.log(chalk.bold.green('\n 分析結果\n')); console.log('='.repeat(60)); console.log(''); console.log(chalk.bold.blue(' 要約')); console.log(analysisResult.summary); console.log(''); if (analysisResult.insights.length > 0) { console.log(chalk.bold.blue(' 主要インサイト')); analysisResult.insights.forEach((insight, index) => { console.log(chalk.cyan(` ${index + 1}. ${insight}`)); }); console.log(''); } if (analysisResult.recommendations.length > 0) { console.log(chalk.bold.blue(' 提案')); analysisResult.recommendations.forEach((recommendation, index) => { console.log(chalk.green(` ${index + 1}. ${recommendation}`)); }); console.log(''); } console.log('='.repeat(60)); console.log(''); console.log(chalk.bold.green(' 分析が完了しました!\n')); } catch (error) { console.error(chalk.red('\n エラー発生:'), error); if (error instanceof Error) { console.error(chalk.red('詳細メッセージ:'), error.message); } process.exit(1); } } main(); ``` --- ## 8. 実装時のトラブルシューティング ### 問題 1: "クライアント認証は失敗しました" **症状**: ``` クライアントが不明か、クライアント認証が含まれていないか、 もしくは認証メソッドがサポートされていないため、 クライアント認証は失敗しました。 ``` **原因**: CLIENT_SECRET_POST 方式で送信したが、Business API は CLIENT_SECRET_BASIC が必要 **解決策**: ```typescript // 間違った方法(POST body に含める) await axios.post(url, { client_id: this.clientId, client_secret: this.clientSecret, // ... }); // 正しい方法(Authorization ヘッダー) const credentials = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64'); await axios.post(url, params, { headers: { 'Authorization': `Basic ${credentials}` } }); ``` ### 問題 2: axios が JSON で送信 **症状**: Content-Type を `application/x-www-form-urlencoded` に設定しても JSON で送信される **原因**: axios はオブジェクトを自動的に JSON に変換 **解決策**: URLSearchParams を使用 ```typescript // オブジェクト使用 - JSON で送信される await axios.post(url, { code, grant_type }, { headers }); // URLSearchParams 使用 const params = new URLSearchParams(); params.append('code', code); params.append('grant_type', 'authorization_code'); await axios.post(url, params, { headers }); ``` ### 問題 3: "scopeパラメータが設定されていないか無効です" **症状**: scope パラメータが無効というエラー **原因**: Personal API scope 形式を使用(`accounts transactions`) **解決策**: Business API scope 形式を使用 ```typescript // Personal API scope scope: 'accounts transactions user_info' // Business API scope scope: 'mfc/admin/tenant.read' ``` ### 問題 4: State パラメータ不足 **症状**: 認証画面でエラーまたはセキュリティ警告 **原因**: Business API は state パラメータが必須 **解決策**: ```typescript // CSRF 防止用 random state 生成 const state = Math.random().toString(36).substring(2, 15); params.append('state', state); ``` ### 問題 5: SSH ポートフォワーディングが必要 **症状**: リモートサーバーで実行時に localhost:3000 callback が動作しない **原因**: OAuth callback はローカルブラウザで発生 **解決策**: SSH ポートフォワーディングを使用 ```bash # ローカルで実行 ssh -L 3000:localhost:3000 user@remote-server.com # リモートサーバーで auth サーバーを実行 pnpm run auth # ローカルブラウザで http://localhost:3000 にアクセス ``` --- ## 9. コスト分析 ### Money Forward Business API - **基本料金**: プランによる(要確認) - **API 呼び出し**: レート制限内は無料 ### Google Cloud Vertex AI(Gemini 2.5 Flash) - **入力**: $0.075 / 100万トークン - **出力**: $0.30 / 100万トークン **月間推定コスト**(1日1回分析の場合): ``` 入力: 約 200 トークン × 30日 = 6,000 トークン → $0.0005 出力: 約 500 トークン × 30日 = 15,000 トークン → $0.0045 合計: 約 $0.005/月(約 0.75円) ``` 非常に低コストで運用可能です。 --- ## まとめ 本記事では、Money Forward Business API と Vertex AI を組み合わせた財務分析の自動化システムを実装しました。 **実現できたこと**: - Money Forward Business API の OAuth 2.0 認証 - 企業財務データの自動収集 - Vertex AI(Gemini)による知的な分析 - わかりやすい日本語でのインサイト生成 - 低コストでの運用(月額約0.75円) このシステムにより、財務データの確認と分析作業が自動化され、経営者は重要なインサイトに集中できるようになりました。 **実装時の重要なポイント**: 1. Business API と ME API の違いを理解する 2. CLIENT_SECRET_BASIC 認証方式を正しく実装 3. URLSearchParams で form-urlencoded を確実に送信 4. State パラメータで CSRF 対策 5. SSH ポートフォワーディングでローカルテスト **今後の展開**: - 追加 scope の設定で取引データの取得 - より高度な財務予測分析機能 - Web ダッシュボードの開発 - 定期レポートの自動生成 --- ## 参考リンク - [Money Forward Business API Documentation](https://developers.biz.moneyforward.com/) - [Google Cloud Vertex AI Documentation](https://cloud.google.com/vertex-ai/docs) - [TypeScript Documentation](https://www.typescriptlang.org/docs) - [OAuth 2.0 RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749) --- ## PlanitAIについて PlanitAI株式会社は、AIを活用した業務自動化ソリューションを提供しています。本記事でご紹介したような財務データ分析の自動化はもちろん、会計システム連携、ドキュメント処理の自動化など、お客様の業務効率化を支援いたします。 **提供サービス**: - AI/LLMを活用した業務自動化コンサルティング - API連携システムの設計・開発 - データ分析基盤の構築 - チャットボット・AIエージェントの開発 「こんな業務を自動化したい」「APIを活用した開発を検討している」など、お気軽にご相談ください。 **お問い合わせ**: [https://www.planitai.co.jp/contact](https://www.planitai.co.jp/contact) --- **関連記事**: - [Stripe×ChatGPT売上分析自動化実践ガイド](/blogs/stripe-chatgpt) - [freee API自動化実践ガイド|Vertex AIで会計データ分類を実現](/blogs/freee-api)