← Blog

How to Build a Claude-Powered Personal Finance Assistant

2026-11-06 · 5 min read · SubToAPI Team

What you're actually building

A Claude-powered personal finance assistant is a chat or voice interface that lets a user ask questions like "how much did I spend on subscriptions last month?" or "can I afford a €1,200 trip in June?" and get an answer grounded in their real transaction data — not a generic budgeting tip. The hard part isn't the LLM call. It's wiring Claude to live financial data through tool use, keeping that data secure, and formatting numeric answers so they're trustworthy rather than hallucinated.

This guide covers the architecture end to end: data sources, system prompt design, tool calling for transaction lookups, and how to ship the API layer without building your own billing and key management infrastructure from scratch.

Core architecture

A working assistant has four layers:

  1. Data layer — a read-only connection to transaction data, typically via an aggregator (Plaid, TrueLayer, GoCardless, or your own bank-sync pipeline) that normalizes transactions into categories, merchants, dates, and amounts.
  2. Tool layer — functions Claude can call to query that data: get_transactions, get_balance, get_category_spend, get_recurring_charges.
  3. Reasoning layer — Claude itself, given a system prompt that constrains it to answer only from tool results, never to invent numbers.
  4. API layer — the endpoint your app actually talks to, handling auth, streaming, and usage tracking.

The key architectural decision: Claude should never see raw bank credentials or do arithmetic from memory. It should call a tool, get structured JSON back, and reason over that. This keeps numbers accurate and keeps sensitive credentials out of the model context entirely.

Designing the tools

Keep tool schemas narrow and typed. A finance assistant needs fewer, more precise tools rather than one giant "query database" function — this reduces the chance Claude picks the wrong tool or misinterprets a date range.

{
  "name": "get_category_spend",
  "description": "Returns total spend per category for a given date range.",
  "input_schema": {
    "type": "object",
    "properties": {
      "start_date": { "type": "string", "format": "date" },
      "end_date": { "type": "string", "format": "date" },
      "category": { "type": "string", "description": "Optional category filter" }
    },
    "required": ["start_date", "end_date"]
  }
}

On the backend, this function hits your transactions database (already synced from the aggregator) and returns clean totals. Claude never touches the database directly — it only sees the function's output.

For a full walkthrough of defining and handling tools, see the tool use tutorial.

System prompt: constrain, don't just instruct

Finance is one domain where vague system prompts cause real damage — a wrong balance estimate can lead to an overdraft. Be explicit:

You are a personal finance assistant. You only answer using data
returned by tool calls. Never estimate or round numbers without
calling a tool first. If a tool call fails or returns no data,
say so explicitly instead of guessing. Always state the date range
you used. Flag any transaction over €500 as "large" in your summary.

Test this with edge cases: ask about a date range with no transactions, ask about a category that doesn't exist, ask for a prediction. The assistant should decline to fabricate and instead ask a clarifying question or call the right tool.

Handling the conversation flow

A typical turn looks like this:

const response = await fetch("https://api.subtoapi.app/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    model: "claude-sonnet-4",
    max_tokens: 1024,
    system: SYSTEM_PROMPT,
    tools: [getCategorySpendTool, getTransactionsTool, getBalanceTool],
    messages: [
      { role: "user", content: "How much did I spend on dining out in May?" }
    ]
  })
});

Claude responds with a tool_use block requesting get_category_spend with category: "dining" and the May date range. Your backend executes the query, returns the result as a tool_result, and Claude produces the final natural-language answer. The Messages API reference covers the exact request/response shapes if you're implementing this from scratch.

For chat UIs, stream the final response so the answer appears token by token instead of after a multi-second delay — this matters more in finance apps than you'd think, since users are often checking balances on mobile with poor connectivity. The streaming guide covers the SSE event format.

Privacy and security are not optional here

A few non-negotiables when building this:

Where SubToAPI fits

Once the tool-calling logic works, the remaining work is infrastructure: issuing scoped API keys per environment, tracking token usage per customer if you're billing for the assistant as a feature, and giving your team visibility into what's actually being called. SubToAPI wraps Claude access into a standard HTTPS API with sub_live_ keys, streaming, tool use, and usage metadata built in, so you're not maintaining auth and billing plumbing alongside the actual product. Plans start with a free trial at signup, and pricing scales from Solo to Team to Scale seats — see pricing for details. If you're starting from zero, the quickstart gets a working request running in a few minutes.

Testing before you ship

Run a fixed set of transactions through the assistant and verify:

Treat this like testing a calculator, not a chatbot — correctness matters more than personality here.

Questions

Does Claude need direct access to my bank data? No. Claude should only interact with financial data through tool calls that return structured results from your own backend. It should never receive raw credentials or query a database directly.

How do I prevent Claude from hallucinating financial numbers? Force every numeric answer through a tool call in the system prompt, and explicitly instruct the model to decline rather than guess when a tool returns no data or fails.

What's the fastest way to add Claude access without building my own API infrastructure? Use a service like SubToAPI, which exposes Claude through a standard API with keys, streaming, and usage tracking already built, so you focus on the finance logic instead of auth and billing.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →