Skip to main content
Glama

Look up finances

query
Read-onlyIdempotent

Query the household ledger — spending, transactions, recurring bills, forecasts, runway, money moved between accounts, plan-vs-actuals, tax prep, and data health. One tool, 20 modes, auto-detected from params.

MODE MAP (first match wins, in this order): digest:true→daily flag briefing · health:true→data-quality dashboard · explain:true+transaction_id→why this name/category · plan_status:true→annual plan vs actuals · vested_interest:true→private holdings register · recurring:true→bills & subscriptions · forecast:true|forecast_months|scenario→projected balance runway · paychecks:true→income streams · account_summary:true→per-account rollup · flows:true→money between own accounts · reimbursables:true→money owed back · tag_report:true→per-tag project ledger · tax_ledger:true→taxes paid/refunded · tax_documents:true→expected tax forms · clusters:true→merchant dedup candidates · detail:true→individual transactions · by+granularity→P&L matrix · granularity alone→trend over time · by alone→aggregate with pct · period alone→income/expenses/net summary

COST: two shapes run an order of magnitude (10-25x) slower than everything else on real households — period:"all", worst combined with search (a substring match defeats the date index and scans lifetime history), and clusters (nothing bounds it, even at its default window). Bound a search with a period where you can. WITHIN a mode the reads already run in parallel, so one mode call is the optimized form — never split a mode into several calls (clusters is the exception: a single serial scan). ACROSS calls, independent queries — two periods, or several modes for a briefing — cost the SLOWEST when issued together in one batch but the SUM when chained, so batch them.

SHAPE: filters go top-level, never nested under a filter key (that is annotate's shape). type:"pnl" nets income−expenses (operating); default type:"cashflow" rows exclude transfers, and its net is the change in cash in every mode (see TYPES).

When reporting results to the user, translate to plain English. Don't echo schema field names like monthly_net, pct, vs_prior, param_warnings — say "money in", "share of total", "change from last month", etc. FIELD GLOSSARY (terse response fields → plain English): amt=amount, cat=category, grp=group, acct=account, bal=balance, avail=available balance, dt=date, n=count, pct=percent, dir=direction (money in/out), freq=how often, xfer=transfer, ign=ignored, pend=pending, ptype=party type, ctype=category type, pfc=the bank's original category (from Plaid), docs=how many documents are filed against this transaction, sign=which way the amounts point ("inflow+ outflow-" = money in positive; "spend+ refund-" = spending positive, refunds negative; "inflow+ outflow-; expenses spend+ refund-" = every section money in positive except the expenses section, which is spending positive).

ADJUSTMENT TRIP TAGS: admin adjustment create/update accepts tags:["trip-slug"] (omit preserves, [] clears). query {tag:"trip-slug",view:"adjusted"} includes only matching applied entries; category/group/exclude_tag compose per leg. query {by:["tag"],type:"expense",view:"adjusted"} shows booked spending plus tagged adjustments, with as_booked_amt and adjustment_amt on contributing rows; n still counts bank transactions. Each tag is independent: never sum overlapping tag rows. Default/as_booked totals stay unchanged. Use summary with reconcile:true for a whole-selection bridge, including an imputation's investment funding offset. A YYYY entry uses period overlap, never a fabricated payment date; finer windows are not proof of when that payment occurred. Tag-report mode remains bank-only and warns if adjusted is requested. Tag child splits/nests and tag matrices retain reporting-entry residuals.

REPORTING VIEWS: view:"as_booked" reports recorded activity and is the basis for cash/statement comparisons with the same account, date and financial-kind scope. view:"adjusted" applies reporting entries without changing those transactions and can differ from cash that moved in the range; reconcile:true shows the bridge. Financial breakdowns, current/prior comparisons, elapsed pacing, FI and expense/savings target formulas follow the displayed financial view. Bank balances, planned recurring facts and historical income shape retain their recorded basis. Reconcile-only keeps displayed amounts and comparisons as booked. A bridge includes scoped reporting-entry kinds and their funding offsets alongside the selected ledger kinds, so an expense-only bridge can carry an investment funding component. Period sums use exact selected dates, even when calendar column labels are wider. P&L operating net remains income minus expenses; change_in_cash includes investment, financing and transfer activity.

REPORTING ENTRY BREAKDOWNS: Reporting entries can lack a real party, account, tag or their own child category. A grouped row then carries reporting_entries.split and/or reporting_entries.items, each {amt,reason}, for that specific alternative child breakdown. Each remainder is already included in the parent; add it only to its own child projection when checking a complete single-valued breakdown. Matrix sections or expense groups carry reporting_entries:{amounts,reason}. Residuals preserve signed reversals and create zero transaction rows. Ordinary top limits can omit primary rows; overlapping transaction tags remain independent and cannot be summed into a partition.

MODE DETAIL (priority order is the MODE MAP above):

  • Digest: { digest: true } → daily "what should I flag" briefing for a scheduled/cron agent: a 30-day low-balance forecast + the attention items (unusual charges, price changes, bank fees, missed bills, late income, capital calls past due or due within 14 days, stale vested-interest marks, vests in the next 30 days and option/warrant expiries within 12 months, broken bank connections), in one bounded read-only call. Optional period/start/end widen the anomaly window (default this month).

  • Health: { health: true } → data quality dashboard: unnamed accounts, uncategorized transaction stats including pending rows (pending_n counts them, including 0 when all are posted), suspected misclassified income (large inflows not in income category), orphan parties, empty categories, stale recurring series (bills that stopped charging), stale party rules (a rule that stopped matching a merchant that keeps charging, or that matches no transactions), orphaned edits (a person's edit stranded where it no longer shows: on a row hidden behind its duplicate or posted copy, a rule left with no condition, a document link or plan reference to something deleted — each item says how to fix it)

  • Explain: { explain: true, transaction_id: "" } → shows how a transaction's name and category were decided. Returns: name-cleanup steps, party match method, rule overrides, the bank's original category (Plaid PFC), all matching rules with scores. Use to debug misclassifications or understand rule behavior before editing. Supports search: { explain: true, search: "STARBUCKS", account: "Wells Fargo" }. Search selects the most recent match and returns matched (full count); use transaction_id for an exact selection. When a plan exists for the transaction's year, includes plan: { year, claimed_by, via? } — which plan item claimed this amount and why.

  • Plan status: { plan_status: true, year?: 2026 } → annual plan vs actuals: income items received/pending/past_due, events with claimed spend + computed status (upcoming/underway/done), everyday-base pacing (whether everyday spending is on track for the year) vs the household's own seasonal shape, guardrails (spending limits), exceptions, full-year forecast. Resolve exceptions by revising the plan (admin { entity: "plan", action: "upsert", reason }) — the plan changes so the breach evaporates on recomputation. No plan for the year → { error, hint } naming admin { entity: "plan", action: "propose", year } to draft one from the household's own actuals. Ignores period/filters — scoped by plan year.

  • Vested Interest: { vested_interest: true } → the register of private holdings (angel checks, fund commitments, advisor equity): per position paid-in, unfunded, distributed, DPI and net cash, open and past-due call notices, vesting on grants, and the latest mark with its as-of date. Add mark:"none" to enumerate positions without a settled mark, or mark:"stale" for open positions whose latest mark is older than 180 days — the gaps behind include:["marks"] coverage, with the usual filters and paging. To read a whole book in one call use rollup_by (groups, not rows) rather than paging; resolved positions come back only as the resolved_omitted count unless include_resolved. Paging, filters, rollup_by, compact, changed_since and include:["marks"] are described on their params. Write side: admin { entity: "position" | "position_event" }.

  • Recurring: { recurring: true } → recurring bills and subscriptions, forecast, duplicates

  • Forecast: { forecast: true } → chronological projected events from recurring series with running balance (within a day, money in first). Projects only series on the balance-pool accounts (checking+savings, or accounts tagged bills when narrowed); series elsewhere (e.g. credit-card subscriptions) are excluded from events and named in warnings. For the full bills list regardless of account, use recurring mode. Open capital-call notices from Vested Interest (admin { entity: "position_event", status: "pending" }) project as dated outflows too — a past-due notice lands on today; a notice projects against the position's funding_account_id; with none set, a pool narrowed to bills accounts cannot place it and names it in the forecast_scope warning, ahead of any recurring series.

  • Paychecks: { paychecks: true } → income-side recurring series with cadence + monthly_avg, plus trailing-90d non-recurring income (variable comp). Filters out inflow series misclassified as transfer/investment/financing via majority-vote categoryType.

  • Account summary: { account_summary: true } → one row per active account with inflow/outflow/net/bal/n. Defaults to last_90d. Use for envelope / multi-account skills. Pass include_hidden:true to include hidden accounts.

  • Flows: { flows: true } → money moved between the user's own accounts (from/to/net/gross). Includes rows where isTransfer=true plus investment and financing category types. Rule-demoted transfers (isTransfer=false on a transfer-typed category) are excluded. Resolves counterpart accounts by name matching. Defaults to last_90d.

  • Reimbursables: { reimbursables: true } → money the user is owed back — outflows tagged 'reimbursable' and not yet 'reimbursed'. Returns { outstanding, n, items, reimbursed_total? }. Tag the expense 'reimbursable' when you pay; add 'reimbursed' once it comes back. Optional period scopes by transaction date (default all time).

  • Tag report: { tag_report: true } → per-tag project/tax ledger: { sign, tags: [{ tag, total, n, first, last, top_categories }] }. Totals a trip/project across categories. A transaction can carry several tags or none, so tag totals overlap and exclude untagged transactions. Read each tag independently; never sum across tags or expect their totals to reconcile to an overall total. Honors ledger filters; defaults to all time. Pages by absolute total descending, then tag: limit 1–200 (default 25), cursor, has_more. Finish when has_more is false for the complete inventory of tags in the selected payment-date window; zero-net tags remain. coverage:{basis:"payment_date",range:{start,end}|"all",tagged_only:true} states coverage explicitly. This is payment-date coverage, not travel dates: prepaid trip charges outside the window are excluded. Keep the same range/type/filters/household/viewer while paging; limit may change. Totals are live, so restart after concurrent edits. Tags are normalized (lowercase-hyphen) — pass "Greece Trip" or "greece-trip", both resolve. total follows the response's sign: "inflow+ outflow-" by default (like detail amt); type:"expense" gives "spend+ refund-" (the sign plan_status uses).

  • Tax ledger: { tax_ledger: true } (US households only; elsewhere { not_available, country }) → what moved between you and tax authorities in a period: { payments: [{ cat, amt, n }], paid, refunded?, refunded_n?, net_paid, covers, excludes }. Payments are Federal/State/Local/Property Tax by category; refunds are inflows from tax authorities. net_paid = paid − refunded. excludes names what's out of view (paycheck withholding isn't visible in the bank feed) — surface it so a W2 user isn't told they paid $0. Defaults to this_year. Organizes what you paid to hand to a preparer — never computes tax owed or gives tax advice.

  • Tax documents: { tax_documents: true } (US households only; elsewhere { not_available, country }) → which tax forms to expect, from the money we can see: { year, basis, expected: [{ form, issuer, issuer_hint?, from, amount, confidence, issuer_confidence, threshold?, filed? }], also_filed?: [{ id, title }], cannot_see: [...], needs_review?: [{ dt?, desc, amt, n?, note? }] }. Wages→W-2 (by employer), interest→1099-INT & dividends→1099-DIV (by account, ≥$10), tuition→1098-T, childcare→statement, charitable ≥$250→acknowledgment. confidence is the FORM ("do you get it?"); issuer_confidence is separate ("do we know who issues it?" — low for payroll-masked employers). cannot_see lists what the cash can't reveal (mortgage 1098, brokerage 1099-B, 1099-R, income we can't see) — surface it so the list is never read as exhaustive. needs_review is possible-1099 income to chase, not a clean prediction. filed is Paper Trail documents for that tax year whose title or filename NAMES that form — what the document SAYS it is, never a classifier; absent means we did not find one, NOT that it hasn't arrived. When several rows share a form (interest is per-account, wages per-employer) the issuer must match too, so one filed 1099-INT can't mark three accounts received; a document naming a form that fits no single row goes to also_filed, alongside filed tax forms nothing predicted. Forms named by description rather than number (childcare statement, charitable acknowledgment) never carry filed. k1? (when the household keeps Vested Interest positions): { expected, received, missing, not_due?, rows: [{ from, via: "vehicle"|"issuer", holder, position_ids, status: "missing"|"not_due"|"received", filed?: [{ id, title, how: "linked"|"name"|"text", page? }] }], unattributed?: [{ id, title, could_be }], text_unread?: [{ id, title, text_status }], not_applicable?: [{ position, instrument, why }], undated?: [{ position, id }], exit_undated?: [{ position, id, last_event }], record_exit? } — one K-1 per vehicle (or issuer, for a direct interest) per holder, for every partnership interest HELD during the year by its own event dates (resolved positions included through their last event): fund/LP instruments, the fund and syndicate segments, anything held through a vehicle, a fund issuer, or an issuer named LLC/LP. A direct SAFE, note, option or warrant is not applicable; an IRA's K-1 goes to its custodian; a position held in a currency other than the household's is assumed to be a foreign fund that issues it no K-1 (each says why in not_applicable). "missing" = the year is over and no K-1 is on file; "not_due" = the year is still running. A K-1 is received when a document for the tax year is linked to the position (admin document link_position_ids — the way a consolidated package names the funds it covers) and names a K-1 or is a tax_form naming no other form, or when its title names a K-1 and its issuer/title fits exactly ONE row (several → unattributed, listing only the rows still open, never attached to all), or — for rows still open — when a page of a K-1 document's indexed text is a partnership K-1 page (Schedule K-1 with Part I "Information About the Partnership", not an estimate or draft) naming that row's vehicle/issuer as a whole-word run — or, for an "X, a series of Y" name a narrow box B wraps, X up to "a series of" with Y's words elsewhere on the page — and no other partnership (how: "text", page = that page). Text never matches a name with fewer than two significant words, a vehicle held by two holders, or a name inside a longer one the book holds, and a series core two book names share finds neither; cover letters, delayed lists and S-corp/trust/state K-1s are not read — link those. text_unread lists K-1 documents the text pass could not read in full (queued, partial past the 200-page index cap, or no text layer) while a row could still be marked by text: a missing row may be inside one. K-1s the checklist takes leave also_filed. undated = pass-through positions with no dated event, so the year can't be decided — record the commitment or an opening balance with held_since; exit_undated = resolved, but the last event isn't an exit, so a later K-1 can't be ruled out — record_exit gives the call that records it (a distribution, return of capital or write-off on its date). Pass year for a prior year (catching a K-1 that never arrived). A position's declared k1 (admin position update { k1: "none" | "expected" }) overrides every rule above, both ways — "none" for an LLC taxed as a corporation or a foreign fund the rules miss, "expected" for one they wrongly rule out; null clears it back to inferred. Defaults to the just-completed tax year (last_year Jan–Apr, else this_year); pass year/period to scope. A checklist to hand a preparer or reconcile against email — never computes tax or gives advice.

  • Clusters: { clusters: true } → find groups of transactions likely from the same merchant but not unified under one party. Default lookback 18 months; pass cluster_months:0 for an all-time dedup sweep of historical merchants.

  • Summary: { period: "this_month" } → income/expenses/net totals. Use period:"all" for all time.

  • Grouped: { by: ["group"], top: 10 } → aggregated by dimension; any grouping containing transaction tag has overlapping buckets and omits total/pct

  • Time series: { granularity: "monthly", periods: 6 } → period-over-period trend. Granularity options: daily, weekly, monthly, quarterly, yearly. periods caps at 90 (enough for last-90-days daily). Default periods is 6 for all granularities except daily, which defaults to 30. Daily labels include weekday (e.g. "Fri May 22"). Daily elapsed comparison is suppressed (use vs_prior on the latest bucket instead).

  • Multi-dim: { by: ["group"], granularity: "monthly" } → income vs. expenses by group over time (a month-by-month income statement). top caps every section's rows, folding the rest into "Other" (by:tag just drops them); nest.top caps the items under each group

  • Detail: { detail: true } → individual transactions with pagination. For a scheduled "what's new since last time" check, add { since: "<as_of from previous run>" } to get only transactions synced since that moment; the response echoes a fresh as_of to store for next time — only once the whole set came back, so follow cursor until has_more is absent before storing it. Add { count: true } to also get matched — the total number of transactions matching the filter across ALL pages — so you can size the result before paging.

SIGN CONVENTIONS:

  • Detail: amt is signed (inflow +, outflow −)

  • Summary: income is money in (positive), expenses are spending (positive; refunds reduce them, so a refund-heavy period can read negative), net = income − expenses + investments + financing + transfers

  • Grouped / time series / multi-dim / tag report / plan_status: see the response's sign. Grouped and time series follow type ("inflow+ outflow-"; type:"expense" → "spend+ refund-"); type:"pnl" and the multi-dim matrix (which ignores type) read "inflow+ outflow-; expenses spend+ refund-". Financing inflows positive, repayments negative.

  • A reconcile bridge carries its own sign ("inflow+ outflow-; expenses spend+ refund-"), whatever the mode's.

  • pct = percentage share; its denominator is described by the response shape

RESPONSE SHAPES:

  • Summary: { range, income, expenses, net, transfers, investments, financing?, top_cats: [{ cat, grp, amt, n, pct }], uncategorized?: { n, amt }, anomalies?: { large_unusual?, price_changes? }, vs_prior?, sources_uses?, fi?, warnings?: [{ kind, msg, party? }], accounts? }

  • Grouped: { range, sign, results: [{ grp|cat|party|acct|tag, amt, n, pct?, items?, split? }], total?, transfers?, net?, net_vs_prior?, vs_prior? }. For grouping without transaction tag, total covers all selected buckets before top truncation. pct uses the sum of absolute bucket net amounts before top, rounded to one decimal with nonzero shares at least 0.1%; true zero stays zero, and rounded shares need not sum to 100%. Under cashflow, net = total + transfers (the change in cash — the same number as summary's net). For the change in cash from the prior period read net_vs_prior (= summary's vs_prior.net); vs_prior tracks total. by:["category"] includes both cat and grp. Any by containing transaction tag omits total, net, pct and grand vs_prior because tags overlap; per-tag amounts and comparisons remain, and untagged transactions can appear as Untagged. type:"pnl" → { income: [...], expenses: [...] } instead (sign "inflow+ outflow-; expenses spend+ refund-").

  • Time series: { granularity, type, sign, periods: [{ label, amt, n, partial?, transfers?, net?, net_vs_prior?, vs_prior? }], averages?: { amt, net? }, stats? }. amt sums the rows; under cashflow, net = amt + transfers (the change in cash — the same number as summary's net) and averages.net is its mean over the complete periods. For net's change from the prior period read net_vs_prior (present only when a transfers line makes it differ; absent, vs_prior is the same comparison); vs_prior/stats track amt. Unfinished simple time-series buckets carry partial:true; vs_prior and net_vs_prior are omitted when either compared bucket is unfinished. stats covers only the COMPLETE periods: when the newest period is still in progress it is dropped and excludes_partial:true is set, so stats.min/max may not appear in periods[]. type:"pnl" → periods have { label, income, expenses, net, savings_rate, change_in_cash, n, partial? } (sign "inflow+ outflow-; expenses spend+ refund-"). change_in_cash = income − expenses + investments + financing + transfers (net cash change, in the household's currency — summary's net; it and savings_rate count every kind whatever include shows, and include only adds the transfers/investments/financing fields and their rows to n); savings_rate = change_in_cash ÷ sources in PERCENT (the cash bucket — same definition as the summary sources_uses block; bounded to ±100, defined in decumulation).

  • Multi-dim: { sign, periods: [...labels], income: { total: [...], items }, expenses: { total: [...], groups: [{ name, total, items? }] }, transfers: { total: [...], items }, investments: { total: [...], items }, financing?: { total: [...], items }, net: [...], vs_prior_elapsed? }

  • Detail: { n, matched?, page_total, txns: [{ id, dt, amt, desc, raw, acct, cat?, grp?, party?, channel?, loc?, xfer?, ign?, flag?, pend?, tags?, docs?, anomaly? }], cursor?, has_more?, as_of? }. page_total is the signed sum of this page's returned txns (money in positive, money out negative), not an all-pages total. as_of appears with since, and only on the page that completes the set. matched (number of filter matches across all pages) appears only with { count: true }. docs is how many documents are filed against that row — absent means none; get them with admin { entity:"document", action:"list", link_transaction_ids:[id] }. channel is "online"/"in store"/"other". loc has city/region/lat/lng/addr when available.

  • Recurring: { series: [{ id, name, renamed?, party, ptype, freq, amt, stddev?, monthly, varies?, dir, ctype, active?, acct, last, next?, expected?, stale? }] (renamed = name is the one the user gave it — show it instead of party; varies = amount swings too much to promise a per-paycheck share; its absence means no claim, not verified-stable), totals: { monthly_income, monthly_expenses, monthly_transfers?, monthly_investments?, monthly_financing?, monthly_net, annual_net }, monthly_sources_uses?: { sources: [{ label, amt, pct }], uses: [{ label, amt, pct }], total, change_in_cash, ratios: { operating_coverage?, net_investing_rate, savings_rate } }, duplicates?, forecast?, missed?, missed_income? }. missed = late BILLS only: money going out to someone else (expenses, loan payments, transfers that pay a card or loan) — moves between the household's own accounts and investment contributions never count. missed_income = late income of at least $25 (scaled to the household's currency), omitted when none — interest cents and round-ups never appear. Note: monthly_net includes transfers/investments/financing (full cash picture). monthly_sources_uses reframes the recurring totals as a balanced statement (change_in_cash == monthly_net) — a recurring portfolio withdrawal shows as a source ("From investments"), useful in decumulation. Its ratios match summary's sources_uses (same units) minus consumption (operating_coverage = recurring income ÷ bills as a ×; net_investing_rate & savings_rate in %). For "bills vs income" compute monthly_income - monthly_expenses. totals/missed/forecast always cover ACTIVE series regardless of is_active (which shapes the series list only); active, recently seen rows show the next date on or after today, matching admin recurring_series list; expected carries the original date when next rolls forward. Inactive and stale rows keep their last expected date as next; stale:true flags active bills that stopped charging or were never observed. type:income/expense narrows the list AND the math.

  • Forecast: { days, starting_bal, ending_bal, p10_ending_bal?, p90_ending_bal?, p10_shortfall_dt?, lowest_bal, lowest_dt, monthly_net, var_net?, var_in?, var_out?, bills_narrowing_active?, events: [{ dt, name, amt, bal, dir, freq }], warnings? }. ending_bal/lowest_bal/lowest_dt and each event's bal fold in a projected daily variable-spend drift (non-recurring everyday flow on the balance pool, beyond recurring bills). lowest_bal/lowest_dt and the Shortfall warnings judge END-OF-DAY balances: a same-day paycheck that covers a bill is no shortfall. The drift is conservative on both sides: var_out = typical recent monthly spending (recent-6-month average), var_in = reliable monthly income (median of the last 12 months, so one-off bonuses don't inflate it); var_net = var_in − var_out per month (negative = net everyday spend; omitted when flat or under ~30 days of history). p10_ending_bal/p90_ending_bal bracket a likely range for the ending balance given how much the user's everyday in/out swings month to month (roughly an 80% range — about a 1-in-10 chance of ending below p10 or above p90); p10_shortfall_dt is when the balance would dip below zero in that pessimistic (p10) case, omitted if it stays positive or history is too short to estimate the swing. monthly_net is recurring-only and spans all matching series (parity with recurring totals); events cover only the balance pool.

  • Paychecks: { paychecks: [{ name, party, ptype, acct, cadence, per_paycheck, monthly_avg, stddev?, last, next }], totals: { monthly_avg, n_streams }, irregular_income_90d }. cadence is one of weekly/biweekly/semimonthly/monthly/quarterly/semiannual/annual. irregular_income_90d sums non-recurring inflows that classify as income — non-zero suggests variable comp or side income outside the regular paycheck.

  • Account summary: { range, accounts: [{ acct, type, inflow, outflow, net, bal, avail?, limit?, n, stale?, stale_since? }], warnings?: [{ kind, msg }] }. One row per active account. Zero-activity accounts still appear so you see the full picture. stale: true means bal is frozen as of stale_since rather than current: the bank connection behind that account is broken or gone (stale_since = the last successful sync, or for an account no connection feeds any more, its last activity), or it still works but the bank has stopped sending updates (stale_since = when it last did; nothing to fix yet, reconnecting is the thing to try if it lasts) — say so rather than quoting the balance as live. Healthy rows omit both keys.

  • Flows: { range, n, flows: [{ from, to, net, n, from_acct_id?, to_acct_id?, gross_out?, gross_in? }] }

  • Clusters: { n, scanned, clusters: [{ name, variants: [{ name, n }], n, sample }], truncated? }. Default top 25; pass top param to adjust. n is total cluster count; truncated shows how many were omitted.

  • Explain: { txn: { id, dt, amt, dir, raw, name_in?, acct }, name: { display, src, stages?, party?, rule? }, class: { cat, grp, type, src, pfc?, rule? }, rules?: [{ name, score, winner?, actions }], plaid?: { merchant, counterparties?, pfc? }, src }. txn.raw is the bank's original text (what a rule's description_pattern matches) and txn.acct the account name — both as detail prints them. name_in is the source's own shorter description (Plaid's cleaned name), which description_pattern also tests and name cleanup starts from; absent means it is the same as raw.

  • Health: { unnamed_accounts?: [{ id, name, mask }], uncategorized?: { n, amt, pending_n, top_parties: [{ name, n, amt }] }, suspected_misclassified_income?: [{ id, dt, amt, desc, cat? }], orphan_parties?: { n }, stale_recurring?: [{ name, last?, freq }], orphaned_edits?: { n, inert_rules?, hidden_edits?, hidden_metadata?, document_links?, plan_refs?: { n, items: [{ …, fix }] } } }. unnamed_accounts lists unrenamed blank, number-like, known-mask or generic bank-product names; readable bank-provided names need no rename. Unused global categories are not health issues. All fields omitted when clean.

  • Digest: { as_of, range, forecast: { days, ending_bal, lowest_bal, lowest_dt, var_net?, warnings?, shortfall_kind?, assumes? }, attention: { unusual, price_changes, bank_fees, missed_bills, missed_income, broken_connections, plan_exceptions?, capital_calls?: [{ position, id, amt, ccy, due, past_due? }], stale_marks?: [{ position, as_of, age_days, source }], newer_recorded_marks?, vests_soon?: [{ position, dt, qty }], expiries?: [{ position, expiry, days, expired?, exercise_cost? }], uncategorized? } }. A checked section with nothing in it is [] (checked, none); plan_exceptions appears only with a plan for the year, and the Vested Interest lists only with an open position. With a shortfall, forecast.assumes says what the projection counted: { through, start_bal, in: [{ dt, name, amt, freq }], out: [...], more_in?/more_out?: { n, amt }, drift?, late_excl?: { n, amt } } — the largest projected events each side up to the dip (amt signed in+ out-), start_bal + every event's amt + drift = lowest_bal when the conservative line dips (drift is absent when only the P10 band dips, through = p10_shortfall_dt). Late bills are never projected; late_excl counts them.

  • Vested Interest: { n, positions: [{ id, name, issuer, issuer_kind, holder, holder_kind, beneficial_owner?, instrument, segment?, ticker?, k1?, terms?: [{ term, value?, basis, doc?, page?, note? }], ccy, status, funding_account_id?, committed, paid_in, unfunded, distributed, cost_basis, dpi?, net_cash, held_days?, vested?, unvested?, vested_through?, schedule_through?, exercised?, next_vest?: { dt, qty }, exercise_cost?, pending?: [{ id, amt, due, past_due? }], converted?: { dt, from?, to?, qty? }, instrument_stale?, mark?: { amt, as_of, source, basis?, age_days, stale?, recorded?, newer_recorded?: { amt, as_of, recorded, source } } }], totals?: { : { n, committed, paid_in, unfunded, distributed, cost_basis, net_cash, pending_calls } }, past_due?: [{ position, id, amt, ccy, due }], stale_marks?: [{ position, as_of, age_days, source }], newer_recorded_marks?: [{ position, amt, as_of, recorded, source }], vests_soon?: [{ position, dt, qty }], expiries?: [{ position, expiry, days, expired?, exercise_cost? }], caveat }. All amounts in each position's own currency. unfunded = committed − contributions: fees and exercises are paid-in but never draw a commitment. vests_soon = open positions whose NEXT tranche vests within 30 days (a later tranche is still on the row's next_vest); expiries = within 365 days, or past. converted = the latest conversion (qty = shares received); instrument_stale = the position still declares the instrument it converted from — update its instrument. unvested is OMITTED rather than 0 when no future tranche is recorded — absent means unknown, not fully vested; vested_through = last tranche on or before today; schedule_through (only when a future tranche is recorded) = last tranche on record, not a promise the schedule is complete. stale = a mark older than 180 days (never on a resolved position); newer_recorded names a mark recorded LATER whose as-of sits behind this one.

  • Plan status: { plan: { year, rev, created, revised_at? }, sign, income?: [{ name, expected, actual?, due_by?, status?, unmatched? }], events?: [{ name, tag?, est, actual, n?, last?, status, window?, over_pct? }], base: { annual, ytd_actual, ytd_expected, pace_pct?, shape_source, shape_note? }, guardrails?: [{ scope, label?, min?, max?, actual, state, no_match? (nothing matched yet this year — normal early on or off-season; a scope matching nothing at all raises a guardrail_empty exception) }], exceptions?: [{ key, kind, msg }], forecast: { projected, actuals_ytd, events_remaining, base_remaining, by_month } }. All amounts in the household's currency. sign is "spend+ refund-; income in+": event, base and guardrail amounts (and the exceptions quoting them) are spend-positive — outflows add, refunds subtract — so an event's actual reads opposite to its tag's default tag_report total. No plan for the year → { error, hint }.

ZERO-RESULT LOOKUPS: Initial search/amount lookups in detail, grouped and simple time series can return excluded_transfers:{n,hint}, a positive transaction row count of matching transfers outside the primary results. Retry the same filters as the hint directs: default cashflow uses is_transfer:true; P&L and income/expense/financing require type:"all" plus is_transfer:true. Grouped P&L requires that retry even with include:["transfers"]. An explicit exclusion stays honored: replace is_transfer:false with true to inspect those rows. This diagnostic does not change counts, totals or paging and is absent on continuation pages and when no matching omitted transfers are found.

PAGINATION: Pass the returned cursor value as cursor in the next call to page forward. Cursors are bound to the sort that issued them — keep the same sort across pages (changing sort mid-pagination is a validation error; start over without the cursor instead).

TYPES:

  • income: income only (excludes investments + financing)

  • expense: expenses only (excludes investments + financing)

  • financing: cash advances + EWA-repaid-from-bank only (DTC borrowing flows: Cleo, Brigit, Dave, etc.)

  • pnl: income+expenses side-by-side (excludes transfers/investments/financing). Its net is the OPERATING net (income − expenses). Grouped/time-series split into income[] and expenses[] — expenses spend-positive, the rest money-in positive (see sign). Cash-basis income statement — actuals only; for plan-vs-actuals use plan_status mode.

  • cashflow (default): includes investments + financing, excludes transfers from rows and row totals (unless is_transfer:true). Its net is ONE number in summary, grouped, time series and the matrix: the change in cash = income − expenses + investments + financing + the transfers line, which is non-zero when a transfer's other leg isn't in view (an unconnected or hidden account, or across the period boundary). Grouped total / time-series amt are the row sums without that line.

ADJUSTED REPORTS: view:"as_booked" (default) reports original bank activity. view:"adjusted" includes reporting entries managed by admin { entity:"adjustment" }, including imputation for real expenses paid outside connected bank feeds. reconcile:true adds original versus adjusted totals and entry effects to summary/time-series output. Use imputation only when investment-withdrawal funding matches the payment. Adjusted reports support summary, time series, and grouped reports with exactly one group/category/tag dimension and type other than pnl. Category/group filters select each leg separately; tag/exclude_tag select the entry's tags on both its expense and funding legs. Party, account and other unsupported transaction filters disable the overlay: check view and param_warnings for as_booked fallback. Tags overlap: never sum tag rows. tag_report and detail remain bank-only; tag child breakdowns and matrices keep a reporting-entry remainder. Adjustments create no bank transactions. Coarse YYYY or YYYY-MM periods count in full on any overlap, without proration, and land in the first overlapping trend bucket; use an exact YYYY-MM-DD payment date when known. Retire the imputation if the real payment is later imported to avoid counting it twice.

FILTERS: category, group, party, account, tag, exclude_tag, country, city, search, amount_min/max, direction, is_recurring, is_uncategorized, is_transfer, is_ignored, is_pending, is_flagged, has_url, include_hidden. Scope note: "hidden" applies to ACCOUNTS (include_hidden brings hidden accounts back in); "ignored" applies to individual TRANSACTIONS (is_ignored finds them). exclude_tag drops rows carrying any of the named tags (none-of-any); ordinary labels and untagged rows remain, and [] excludes nothing. Transaction tags are normalized (lowercased, spaces→hyphens — "Greece Trip" → "greece-trip"), so filter input is normalized to match. Tagging a txn 'one-time' also excludes it from recurring detection / forecast. FILTER COMBINATIONS: filters AND together. Useful combos: { account, is_recurring: false, period, by: ["category"] } isolates non-recurring drafts on one account (good for reconciling against per-account net flow). { account, period } gives that account's income/expenses/net. { account, tag, period } scopes a tag to one account. SORT (detail mode): sort="amount"|"-amount" (default "-date"). Amounts are signed — for largest expenses use sort="amount" (most negative first); for largest inflows use sort="-amount" (most positive first). Detail limit is 1–200 (default 25); grouped top is 1–50 (default 50), and limit does not cap grouped results. HIDDEN ACCOUNTS: Transactions from hidden accounts are excluded by default. Pass include_hidden:true to include them. Manage visibility via admin { entity: "account", action: "hide"|"unhide", id: "" }. SEARCH DEFAULT: When search is provided with no period/start/end, defaults to all time. COMPARE: prior_period, prior_year — works in summary and grouped modes with a bounded period (not 'all'). The change in net from the prior period is summary's vs_prior.net and grouped's net_vs_prior (the same number). prior_period_elapsed (defined on the compare param) also works in multi-dim time series (not at daily granularity), where it surfaces as vs_prior_elapsed. Check param_warnings. INCLUDE: stats, warnings, accounts, transfers, investments, financing, fi (extra output sections). transfers/investments/financing add those fields to pnl time series periods. fi adds FIRE primitives (annual_spend, fi_number_25x, fi_lean_20x, fi_chubby_30x, fi_fat_50x, years_to_fi, extrapolation_basis, extrapolation_reliability, decumulation?) to summary mode. targets adds the 80/20 framework defaults: income_shape, buffer { months, target, callable?, current_months, shortfall?|funded } — target = months × expenses + callable, where callable is Vested Interest's unfunded USD commitments not yet noticed (committed − contributions; money owed on demand, so a reserve rather than a forecast event) — and savings_rate { current_pct, default_pct?, gap_pct? }. ANOMALIES (default-on in summary mode): { large_unusual: [{ desc, amt, dt, party?, vs_avg, reason }], price_changes: [{ name, expected, actual, pct_change, reason }], bank_fees: [{ desc, amt, dt, pfc, kind, reason }], by_account?: [{ acct, total, n }] }. Pre-computed at import time. large_unusual flags per-party transactions exceeding historical median (MAD-based, log-space). price_changes flags recurring series whose recent median deviates from expected amount. bank_fees surfaces NSF / overdraft / late fees (from Plaid PFC). by_account rolls up large_unusual by account so a spending skill can quote "Bill Pay had $X of irregular drafts" without re-summing. ANOMALY TAGS: each fast-detector anomaly also writes a transaction_metadata tag for cheap filtering — nsf, overdraft, late-fee, price-increase / price-decrease (sign-aware). Use query { detail: true, tag: "nsf" } to drill into bank fees without filtering on anomalyType directly. SOURCES_USES (summary mode, always-on when there's activity): a Sources & Uses of cash statement that works in BOTH FIRE accumulation and retirement/decumulation — each flow lands on a side by DIRECTION, so investments are a use when contributing, a source when withdrawing. Shape: sources[] and uses[] (each { label, sub?, amt, pct } where pct is % of the equal side total), total, change_in_cash (signed; + added to cash, − drawn down; == net exactly), and ratios: operating_coverage (income÷expenses as a MULTIPLE/×, e.g. 7.4× or 0.24× — not a percent; >1 accumulation, <1 retirement; omitted when no spend), net_investing_rate (−investments÷sources, in PERCENT; its SIGN is the regime flag — + accumulating, − decumulating), savings_rate (change_in_cash÷sources, in PERCENT — the CASH bucket: cash set aside (+) / drawn down (−) after consuming and investing; Sethi's "Savings" bucket, distinct from and non-overlapping with net_investing_rate, so FIRE's total savings rate = savings_rate + net_investing_rate; always present), consumption { essential, discretionary, untagged, reporting_entries? } (each { amt, pct } as % of total sources; reporting_entries also explains why its signed expense amount lacks an attributable category). The three classified buckets plus that reporting-entry remainder equal displayed consumption. The whole block is one sources-denominated frame: consumption + investing + savings partition total cash inflow. LOCATION: country / city are the MERCHANT's location as the bank reports it, so an online merchant abroad counts as abroad. A trip: { detail: true, start, end, country: "GR" } finds every charge made there in the window, whatever its category. GROUPING: Category/group buckets partition the same selected transactions (including Uncategorized) and add up before top truncation, unless combined with transaction tag. Transaction tags overlap: one purchase can appear under several labels, so never add the tag rows together. Grouped tag results can include Untagged; tag_report excludes untagged transactions. Matrix headline totals are computed independently of overlapping tag rows. Canonical category tags are different: essential/discretionary/untagged are mutually exclusive. by:["category_tag"] aggregates by canonical category tag (essential / discretionary / untagged). Works in by:, nest.by:, and split_by:. Most useful with type=expense — non-expense categories carry no canon tag and roll into 'untagged' (a param_warning fires on type=income or type=financing). Response key is c_tag. For "P&L split essential / discretionary": by:["category_tag"], type:"expense". For "each spending group split by spending-class": by:["group"], split_by:"category_tag", type:"expense". For per-account or per-owner rollups, use the existing by:["account"] with an account:[...] filter (account_tag grouping is intentionally not exposed — accounts are low-cardinality enough that the model handles them directly). WARNINGS: { kind, msg, party? } objects. unusual_txn includes the resolved party when known, independently of the transaction display label in msg. Summary mode: always-on sync_incomplete + connection_error + flagged + anomaly warnings (bank_fee, price_increase, missed_bill, missed_income); with include:["warnings"] also low_balance, unusual_txn, uncategorized. missed_bill, missed_income and low_balance describe today, so they appear only when the range includes today — their absence on a past range says nothing about bills or balances. Account-summary mode: the connection warnings only (sync_incomplete, connection_error, connection_warning), matching summary word for word. PRECEDENCE: start/end beats period, and params that belong to a lower-priority mode than the one detected are ignored. Both are reported in param_warnings. NEST: { by: "party", top: 5 } — sub-group within each grouped result SPLIT_BY: any by: dimension — cross-tab each grouped result by a second dimension RECURRING OPTIONS: forecast_days (0-365, recurring default 30, forecast default 90), is_active (default true). Also accepted by paychecks: is_active, include_hidden.

DISCOVERY: To list available categories, groups, parties, or tags, use admin { entity: "category"|"party"|..., action: "list" }. DASHBOARD: https://cashflow.tech has two views agents can link to:

  • /spending?start=YYYY-MM-DD&end=YYYY-MM-DD (income statement). Also accepts view=month|quarter|year|all_time for named periods.

  • /transactions?start=YYYY-MM-DD&end=YYYY-MM-DD&search=X&group=X&account=X (transaction list). Also accepts view param. All filter params optional.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
byNoAggregate by dimension(s). Triggers grouped mode. category/group put each selected transaction in one bucket, including Uncategorized; their full buckets add up before top truncation. Any grouping containing transaction tag has overlapping buckets: a transaction can carry several tags or none. Read each tag independently; never sum across tags. Grouped tag results omit total/pct and can include Untagged; tag_report gives standalone per-tag figures without Untagged. category_tag is different: its canonical essential / discretionary / untagged buckets do partition the selected transactions; most useful with type=expense. country groups by merchant country (ISO alpha-2), city by merchant city; rows with none land in "Unknown".
endNoCustom range end (YYYY-MM-DD)
tagNoTransaction tag name(s) — exact match
topNoLimit grouped results to top N by amount (1–50, default 50); grouped comparisons rank by absolute change and include rows with only prior activity. In the time-series matrix (by + granularity) it caps every section's rows: expense groups past N fold into "Other" so groups still sum to the total (over by:tag, whose buckets overlap, the extra tags are dropped, not folded); nest.top caps the items under each group.
cityNoMerchant city — exact match, case-insensitive. Only where the bank reports one (mostly linked accounts).
markNovested_interest: only positions with no settled mark (none) or whose latest settled mark is stale (stale: older than 180 days, open positions only). A settled zero-dollar mark is marked; pending and superseded marks do not count. Uses the same status as include:["marks"] coverage and stale_marks. Composes with other book filters; totals, matched, alerts, resolved_omitted and rollups cover this filtered set before paging.
nestNoNested sub-grouping within each group
sortNoSort field (detail mode): date, -date, amount, -amount. Default -date. Signed amounts: amount puts the most negative outflows first; -amount puts the most positive inflows first. A typo is a hard error, not a silent fall back to date.
typeNoincome, expense, financing (cash advances + EWA repaid from bank), pnl (income+expenses side-by-side, excludes transfers/investments/financing; its net is the OPERATING net = income − expenses, while a pnl trend's change_in_cash and savings_rate still count every kind), cashflow (default; rows and row totals exclude transfers, and `net` — one number in summary, grouped, time series and the matrix — is the change in cash = income − expenses + investments + financing + the transfers line, which is non-zero when a transfer's other leg isn't in view), all (full ledger, no kind filter — includes transfers)cashflow
viewNoReporting view (summary, grouped, time-series). 'as_booked' (default; alias 'actual') = recorded activity for cash/statement comparisons with the same account, dates and financial-kind scope. 'adjusted' applies reporting entries without changing those transactions, so it can differ from cash that moved in that range. Period sums use the exact selected dates even when calendar labels are wider. Under `compare`, adjusted compares to adjusted. category/group/tag filters (and their exclude_*) scope the overlay; other narrowing filters return as_booked. Adjusted single by:['tag'] rows include as_booked_amt and adjustment_amt; tags overlap, so never sum rows. A year-only adjustment keeps its year period (overlap, not a payment date). Manage entries via admin { entity: 'adjustment' }.as_booked
yearNoYear for plan_status (plan year) and tax_documents (tax year). Default: current year.
countNoDetail mode only: also return `matched` — the total number of transactions matching the filter across ALL pages — so you can size the result before paging. Opt-in because it runs a second count scan (vested_interest always returns matched).
flowsNoNet inter-account transfer matrix (from/to/net/gross). Includes transfers, investment flows, credit card payments.
groupNoCategory group name(s) — exact match, case-insensitive
limitNoPage size 1–200: detail and tag_report default 25, vested_interest defaults 50. Ignored in grouped mode — use top (1–50, default 50) there.
partyNoParty name(s) — exact match, case-insensitive
sinceNoDetail mode only: transactions recorded on or after this ISO timestamp — the `as_of` from a previous run. The first page pins an upper recorded-time bound carried by its cursors, so later arrivals wait for the next run. Keep the original since and sort while paging; store as_of only after has_more is absent. Timestamp equality may replay boundary rows: deduplicate by transaction id.
startNoCustom range start (YYYY-MM-DD)
cursorNoPagination cursor from previous response. Pass the exact cursor to fetch the next page. tag_report cursors require unchanged payment-date range, type, filters, household and viewer; limit may change. Its live totals can move during concurrent edits: restart for a fresh inventory.
detailNoReturn individual transactions instead of aggregates
digestNoDaily 'what should I flag' digest: a 30-day low-balance forecast, missed bills (late payments out, never moves between your own accounts), late income (paychecks and other deposits of $25 or more that haven't arrived), unusual charges (large/price-change/fees), plan exceptions when a plan exists (breached spending limits, missed income, over-budget events, off-pace spending), and broken bank connections, in one bounded read-only call. Built for a scheduled/cron agent — safe to run every morning.
filterNoDo NOT use — filters go at the top level (e.g. { tag: 'wechat' }). A nested wrapper is flattened, with a param_warnings nudge.
healthNoData quality dashboard: accounts needing readable names, uncategorized transactions, suspected misclassified income, orphan parties, stale recurring
holderNovested_interest: only positions whose legal holder (the person, trust, LLC, IRA or nominee) contains this text, case-insensitive.
issuerNovested_interest: only positions whose issuer (the company or fund) contains this text, case-insensitive.
periodNoNamed time period. 'all' = no date filtering.
searchNoText search across display name, party name, description, and check number
accountNoAccount name or display name — exact match, case-insensitive
compactNovested_interest: omit position notes, term notes and mark basis explanations from the rows. Keeps exact term values and their basis/document/page provenance, plus mark amounts, dates and sources. Opt-in, including with changed_since; use smaller limit pages for large books. Full prose remains available through compact:false or admin position get.
compareNoAdd comparison to prior period or prior year. prior_period_elapsed compares only the same number of elapsed days of the prior period (apples-to-apples for an in-progress period like this_month); prior_year_elapsed does the same against the SAME span one year earlier (right for a partial year — H1-2026 vs H1-2025, not vs the preceding H2-2025). Both work in summary, grouped, and multi-dim time series.
countryNoMerchant country — ISO alpha-2 ("GR"), alpha-3 ("GRC") or English name ("Greece"), any case. The merchant's country as the bank or card network reports it; rows with no known country never match.
explainNoProvenance trace for a single transaction's naming and classification. Search selects the most recent match and returns matched (the full match count); use transaction_id for an exact selection.
has_urlNoFilter by receipt URL presence (true=has, false=missing)
includeNoExtra sections to include in output. transfers/investments/financing: include in pnl time series output. fi: FIRE primitives (annual_spend, fi_number_25x, lean/chubby/fat targets, years_to_fi) on summary. targets: 80/20 framework defaults on summary — emergency-buffer target sized by income shape (with months-short) and a savings-rate anchor vs the household's actual rate. marks: mark COVERAGE on vested_interest — marked_n, unmarked_n, stale_n and the as_of span of the marks that exist, per currency. Counts and dates only: marks are recorded opinions of different ages and are never summed into a total, so it answers how much of the book carries a current opinion, not what the book is worth.
periodsNoNumber of rolling periods (requires granularity). Cap is 90 so 'last 90 days daily' fits; for longer ranges use a coarser granularity.
segmentNovested_interest: only this book — employment, direct, fund, syndicate, other. The employment book in one call. "undeclared" returns the positions that declare NO segment — nothing else reaches those, since the column is nullable with no default and they match no other value.
vehicleNovested_interest: only positions held through a vehicle whose name contains this text, case-insensitive. "undeclared" returns the positions held through NO vehicle (a direct deal, an employment grant).
categoryNoCategory name(s) — exact match, case-insensitive
clustersNoFind groups of transactions that likely represent the same merchant but aren't unified under one party
currencyNovested_interest: only positions in this currency (USD, NZD, …).
end_dateNoAnchor date for the time window — shifts named periods and rolling buckets to end on/around this date instead of today. Applies in every mode.
forecastNoChronological projected events from recurring series with running balance
scenarioNoForecast decision-support: re-run the projection with these what-if changes to regular bills/income, and compare to the unchanged baseline. Answers 'can I afford X?' / 'what if income drops?'. Works with forecast or forecast_months; nothing is saved.
split_byNoCross-tab: add a split map by this dimension to each grouped result
directionNoFilter by transaction direction
is_activeNoFilter active/inactive series (recurring mode, null=all, default true)
paychecksNoIncome-side recurring series only (paychecks, regular deposits) with cadence labels, plus trailing-90d non-recurring income for variable comp
reconcileNoAttach a reconciliation bridge to summary or time-series OUTPUT: recorded as_booked activity vs adjusted reporting totals plus each entry's net effect within the exact selected dates. A modifier, not a mode of its own — it adds to whatever the other params select, and is scoped by period/start/end like any other query (never by `year`). Works with either view; vs_prior follows `view`, not the bridge.
recurringNoList recurring bills/subscriptions from recurring_series table
rollup_byNovested_interest: return GROUPS instead of rows — per group its included position count, resolved_omitted count when resolved positions were left out, and its per-currency totals, and no positions at all. A resolved-only group has n:0 and empty totals; include_resolved counts those positions and omits resolved_omitted. The whole register in one call: 86 positions is ~78KB of rows and past most tool-result limits, where the same book by segment is a handful of lines. Each group names its DIMENSION as the key ({ segment: "syndicate", n, totals }), so the value can be sent straight back as that filter; a position with no value for the dimension buckets under "undeclared". Groups cover the whole filtered set, so limit and cursor do not apply — there are no rows to page.
amount_maxNoMaximum absolute amount (household's currency)
amount_minNoMinimum absolute amount (household's currency)
instrumentNovested_interest: only positions of this instrument (option, safe, private_equity_fund, …).
is_flaggedNoFilter flagged transactions
is_ignoredNoReturn ONLY ignored (hidden) transactions — they're excluded from every query by default. To see ignored rows ALONGSIDE normal ones (e.g. a search that greys them out), use include_ignored instead.
is_pendingNoFilter by pending status — true = only pending, false = only posted. Omitted: transaction detail shows both; summaries and reports show posted only
tag_reportNoPer-tag project/tax ledger: each tag's total, count, date span (first/last), and top categories. A trip/project total across categories. Transactions can carry several tags or none: these totals overlap and exclude untagged transactions. Read each tag on its own; never sum across tags or expect them to reconcile to an overall total. Honors ledger filters; defaults to all time. Pages by absolute total descending, then tag: limit 1–200 (default 25), cursor and has_more. Finish when has_more is false for complete tag inventory in the selected payment-date window. coverage states payment_date and range (or all); it excludes untagged rows and prepaid trip charges outside that window, so this is not travel-date coverage. Per-tag totals include each transaction once. Live pagination: restart after concurrent edits.
tax_ledgerNoWhat you paid the government this year: tax payments by category (Federal/State/Local/Property Tax), refunds from tax authorities, and net_paid. Returns an `excludes` note (e.g. paycheck withholding isn't visible in the bank feed) so a W2 user is never told they paid $0. Defaults to this_year. Organizes what happened to hand to a preparer — not tax advice. US households only.
account_tagNoAccount tag name(s) — restricts to transactions in accounts carrying any of the tags. Canon: operating, bills, emergency-fund, savings-goal, brokerage, retirement.
exclude_tagNoExclude transaction tag name(s) — drops rows carrying any of these normalized tags (none-of-any, exact match). Other labels and untagged rows remain; [] excludes nothing.
granularityNoGroup results by day, week, month, quarter, or year. Triggers time series mode.
is_transferNoFilter transfers
plan_statusNoAnnual plan vs actuals: income items, events (claimed spend + computed upcoming/underway/done), everyday-base pacing vs the household's seasonal shape, guardrails, exceptions, and the full-year forecast. Scoped by plan year (ignores period/filters).
terms_basisNovested_interest: only positions carrying at least one term on any of these bases. One value or a list, so terms_basis:["assumed","missing"] is the whole what-only-you-can-confirm list in ONE call.
category_tagNoCategory tag name(s) — restricts to transactions whose category carries any of the tags. Canon: essential, discretionary.
is_recurringNoFilter recurring transactions
private_bookNoDeprecated: renamed vested_interest. Still accepted, with a param_warning — send vested_interest.
changed_sinceNovested_interest: latest currently matching positions with something RECORDED on or after this (inclusive): an event or position creation/update, with changes. Date and naive ISO mean UTC; offset timestamps keep their exact instant; at most 3 fractional digits and normalized UTC year 0000–9999. Page to completion before saving as_of, the FIRST request clock carried in a scoped versioned cursor. Keep changed_since and book filters unchanged; legacy changed-feed cursors require restarting without cursor from the original cutoff. Next review from as_of intentionally overlaps concurrent records: replace/upsert by position id, never add totals across pages/runs. Membership, folds, totals and alerts stay live; rollups have no feed cursor/as_of. Future row cutoff completes empty at the current clock. Timestamp order is not commit order: earlier-stamped late commits/backward clocks, event edits/deletes, position deletions and filter exits have no guaranteed notifications; position edits coalesce to updated:true without a diff.
exclude_groupNoExclude category group name(s)
exclude_partyNoExclude party name(s)
forecast_daysNoDays to forecast (recurring mode default 30, forecast mode default 90, 0 to skip)
reimbursablesNoOutstanding receivables — outflows tagged 'reimbursable' and not yet 'reimbursed'. Returns the total you're owed plus the open items.
tax_documentsNoWhich tax forms to expect, derived from the money Cashflow can see: wages→W-2, interest→1099-INT, dividends→1099-DIV (kept per issuer), plus categorized tuition/childcare/charitable → 1098-T/statement/acknowledgment. Each form carries its issuer, amount, and confidence (form vs issuer). Returns a `cannot_see` list (mortgage 1098, 1099-B, 1099-R, income we can't see…) so it's never read as exhaustive, and `needs_review` for possible-1099 income to chase. Defaults to the just-completed tax year (last_year Jan–Apr, else this_year); pass `year`/`period` to scope. A checklist to hand a preparer or reconcile against email — not a return, not tax advice. US households only.
cluster_monthsNoClusters mode: lookback window in months (default 18). Pass 0 for all-time — use for a full dedup sweep of historical merchants, since merchants whose last activity predates the window are otherwise invisible.
include_hiddenNoInclude hidden account transactions (excluded by default)
transaction_idNoTarget transaction ID (for explain mode)
account_summaryNoPer-account inflow/outflow/net/balance/n over a period — one row per active account
forecast_monthsNoForecast mode: return a month-by-month projection over N months (1-12) with a calibrated low/high (P10/P90) balance band, instead of the daily event list. Headline is first_negative_month — the first month the low-end (P10) balance goes negative (the runway-relevant stress point).
include_ignoredNoInclude ignored (hidden) transactions ALONGSIDE normal ones instead of excluding them; each ignored row is flagged with `ign:true` so a caller can de-emphasize (grey out) rather than drop it. Unlike is_ignored:true (only ignored), this returns both. Ignored still stays out of all aggregate totals.
vested_interestNoThe register of private holdings (angel checks, fund commitments, advisor equity): per position committed / paid-in / unfunded / distributed / DPI / net cash, open and past-due capital-call notices, and the latest mark with its as-of date and a staleness flag. Pages (limit, default 50, + cursor); resolved positions are left out unless include_resolved, and their count is echoed as resolved_omitted. Filters: instrument, issuer, vehicle, currency, mark, search (name / issuer / vehicle). totals, matched and the alerts cover the WHOLE filtered set, not the page. Totals per currency, never combined; marks never summed. cost_basis (per position and in the totals) is what is still AT RISK — paid_in minus return_of_capital minus written_off — not what went in; return_of_capital / fees / written_off print beside it whenever they are non-zero, so a write-off is never a silent gap between the two. On a resolved position net_cash is the realized result and dpi the realized multiple. Ignores period and the ledger filters.
exclude_categoryNoExclude category name(s)
include_resolvedNovested_interest: also list resolved (exited / written-off) positions — left out by default, as in admin position list.
is_uncategorizedNoFilter uncategorized transactions
recurring_series_idNoOnly transactions linked to this recurring series ID, from query { recurring: true }. Matches membership, not merchant or series name. Use period:'all' for its full history.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / view / description
      Previous value: -"Reporting view (summary, grouped, time-series). 'as_booked' (default; alias 'actual') = recorded activity for cash/statement comparisons with the same account, dates and financial-kind scope. 'adjusted' applies reporting entries without changing those transactions, so it can differ from cash that moved in that range. Period sums use the exact selected dates even when calendar labels are wider. Under `compare`, adjusted compares to adjusted. category/group filters (and their exclude_*) scope the overlay; any other filter returns as_booked. Manage entries via admin { entity: 'adjustment' }."New value: +"Reporting view (summary, grouped, time-series). 'as_booked' (default; alias 'actual') = recorded activity for cash/statement comparisons with the same account, dates and financial-kind scope. 'adjusted' applies reporting entries without changing those transactions, so it can differ from cash that moved in that range. Period sums use the exact selected dates even when calendar labels are wider. Under `compare`, adjusted compares to adjusted. category/group/tag filters (and their exclude_*) scope the overlay; other narrowing filters return as_booked. Adjusted single by:['tag'] rows include as_booked_amt and adjustment_amt; tags overlap, so never sum rows. A year-only adjustment keeps its year period (overlap, not a payment date). Manage entries via admin { entity: 'adjustment' }."
  2. Changed6 schema fields changed
    • changedInput schema / properties / cursor / description
      Previous value: -"Pagination cursor from previous response. Pass the cursor value returned in the prior call to fetch the next page."New value: +"Pagination cursor from previous response. Pass the exact cursor to fetch the next page. tag_report cursors require unchanged payment-date range, type, filters, household and viewer; limit may change. Its live totals can move during concurrent edits: restart for a fresh inventory."
    • changedInput schema / properties / exclude_tag / description
      Previous value: -"Exclude transaction tag name(s) — drops rows carrying any of these tags (exact match)"New value: +"Exclude transaction tag name(s) — drops rows carrying any of these normalized tags (none-of-any, exact match). Other labels and untagged rows remain; [] excludes nothing."
    • changedInput schema / properties / limit / description
      Previous value: -"Page size in detail mode (default 25) and vested_interest mode (default 50). Ignored in grouped mode — use top there."New value: +"Page size 1–200: detail and tag_report default 25, vested_interest defaults 50. Ignored in grouped mode — use top (1–50, default 50) there."
    • changedInput schema / properties / sort / description
      Previous value: -"Sort field (detail mode): date, -date, amount, -amount. Default -date. A typo is a hard error, not a silent fall back to date."New value: +"Sort field (detail mode): date, -date, amount, -amount. Default -date. Signed amounts: amount puts the most negative outflows first; -amount puts the most positive inflows first. A typo is a hard error, not a silent fall back to date."
    • changedInput schema / properties / tag_report / description
      Previous value: -"Per-tag project/tax ledger: each tag's total, count, date span (first/last), and top categories. A trip/project total across categories. Transactions can carry several tags or none: these totals overlap and exclude untagged transactions. Read each tag on its own; never sum across tags or expect them to reconcile to an overall total. Honors all filters; defaults to all time."New value: +"Per-tag project/tax ledger: each tag's total, count, date span (first/last), and top categories. A trip/project total across categories. Transactions can carry several tags or none: these totals overlap and exclude untagged transactions. Read each tag on its own; never sum across tags or expect them to reconcile to an overall total. Honors ledger filters; defaults to all time. Pages by absolute total descending, then tag: limit 1–200 (default 25), cursor and has_more. Finish when has_more is false for complete tag inventory in the selected payment-date window. coverage states payment_date and range (or all); it excludes untagged rows and prepaid trip charges outside that window, so this is not travel-date coverage. Per-tag totals include each transaction once. Live pagination: restart after concurrent edits."
    • changedInput schema / properties / top / description
      Previous value: -"Limit grouped results to top N by amount; grouped comparisons rank by absolute change and include rows with only prior activity. In the time-series matrix (by + granularity) it caps every section's rows: expense groups past N fold into \"Other\" so groups still sum to the total (over by:tag, whose buckets overlap, the extra tags are dropped, not folded); nest.top caps the items under each group."New value: +"Limit grouped results to top N by amount (1–50, default 50); grouped comparisons rank by absolute change and include rows with only prior activity. In the time-series matrix (by + granularity) it caps every section's rows: expense groups past N fold into \"Other\" so groups still sum to the total (over by:tag, whose buckets overlap, the extra tags are dropped, not folded); nest.top caps the items under each group."
  3. Changed1 schema field changed
    • addedInput schema / properties / recurring_series_id
      Added value: +{
      +  "description": "Only transactions linked to this recurring series ID, from query { recurring: true }. Matches membership, not merchant or series name. Use period:'all' for its full history.",
      +  "format": "uuid",
      +  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      +  "type": "string"
      +}
  4. Changed4 schema fields changed
    • changedInput schema / properties / changed_since / description
      Previous value: -"vested_interest: only positions with something RECORDED on or after this — an event recorded, or the position created or updated — each row carrying `changes` (the events with when they were recorded, and created / updated flags). A YYYY-MM-DD date (or a time with no offset) is read as UTC; the response echoes as_of (ISO) to pass back next time for an exact cutoff — but only when the whole matched set came back, so page to the end (has_more absent) before storing it. Limits: pages read live position state and return a completion-time watermark, so concurrent records or updates can be missed during pagination. A position field change shows as updated:true without a diff, and an event edited or deleted after the cutoff is invisible (events carry only a recorded time)."New value: +"vested_interest: latest currently matching positions with something RECORDED on or after this (inclusive): an event or position creation/update, with changes. Date and naive ISO mean UTC; offset timestamps keep their exact instant; at most 3 fractional digits and normalized UTC year 0000–9999. Page to completion before saving as_of, the FIRST request clock carried in a scoped versioned cursor. Keep changed_since and book filters unchanged; legacy changed-feed cursors require restarting without cursor from the original cutoff. Next review from as_of intentionally overlaps concurrent records: replace/upsert by position id, never add totals across pages/runs. Membership, folds, totals and alerts stay live; rollups have no feed cursor/as_of. Future row cutoff completes empty at the current clock. Timestamp order is not commit order: earlier-stamped late commits/backward clocks, event edits/deletes, position deletions and filter exits have no guaranteed notifications; position edits coalesce to updated:true without a diff."
    • changedInput schema / properties / health / description
      Previous value: -"Data quality dashboard: unnamed accounts, uncategorized transactions, suspected misclassified income, orphan parties, empty categories, stale recurring"New value: +"Data quality dashboard: accounts needing readable names, uncategorized transactions, suspected misclassified income, orphan parties, stale recurring"
    • changedInput schema / properties / reconcile / description
      Previous value: -"Attach a reconciliation bridge to summary or time-series OUTPUT: as_booked vs adjusted totals plus the per-entry net deltas. A modifier, not a mode of its own — it adds to whatever the other params select, and is scoped by period/start/end like any other query (never by `year`). Works with either view; vs_prior follows `view`, not the bridge."New value: +"Attach a reconciliation bridge to summary or time-series OUTPUT: recorded as_booked activity vs adjusted reporting totals plus each entry's net effect within the exact selected dates. A modifier, not a mode of its own — it adds to whatever the other params select, and is scoped by period/start/end like any other query (never by `year`). Works with either view; vs_prior follows `view`, not the bridge."
    • changedInput schema / properties / view / description
      Previous value: -"Reporting view (summary, grouped, time-series). 'as_booked' (default; alias 'actual') = raw actuals; 'adjusted' = with the adjustment overlay folded into the headline totals, and into the prior period under `compare`, so vs_prior compares adjusted to adjusted. category/group filters (and their exclude_*) scope the overlay; any other filter returns as_booked. Manage entries via admin { entity: 'adjustment' }."New value: +"Reporting view (summary, grouped, time-series). 'as_booked' (default; alias 'actual') = recorded activity for cash/statement comparisons with the same account, dates and financial-kind scope. 'adjusted' applies reporting entries without changing those transactions, so it can differ from cash that moved in that range. Period sums use the exact selected dates even when calendar labels are wider. Under `compare`, adjusted compares to adjusted. category/group filters (and their exclude_*) scope the overlay; any other filter returns as_booked. Manage entries via admin { entity: 'adjustment' }."
  5. Changed2 schema fields changed
    • changedInput schema / properties / by / description
      Previous value: -"Aggregate by dimension(s). Triggers grouped mode. category_tag groups by canonical category tag (essential / discretionary / untagged); most useful with type=expense. country groups by merchant country (ISO alpha-2), city by merchant city; rows with none land in \"Unknown\"."New value: +"Aggregate by dimension(s). Triggers grouped mode. category/group put each selected transaction in one bucket, including Uncategorized; their full buckets add up before top truncation. Any grouping containing transaction tag has overlapping buckets: a transaction can carry several tags or none. Read each tag independently; never sum across tags. Grouped tag results omit total/pct and can include Untagged; tag_report gives standalone per-tag figures without Untagged. category_tag is different: its canonical essential / discretionary / untagged buckets do partition the selected transactions; most useful with type=expense. country groups by merchant country (ISO alpha-2), city by merchant city; rows with none land in \"Unknown\"."
    • changedInput schema / properties / tag_report / description
      Previous value: -"Per-tag project/tax ledger: each tag's total, count, date span (first/last), and top categories. A trip/project total across categories. Honors all filters; defaults to all time."New value: +"Per-tag project/tax ledger: each tag's total, count, date span (first/last), and top categories. A trip/project total across categories. Transactions can carry several tags or none: these totals overlap and exclude untagged transactions. Read each tag on its own; never sum across tags or expect them to reconcile to an overall total. Honors all filters; defaults to all time."
  6. Changed1 schema field changed
    • changedInput schema / properties / compact / description
      Previous value: -"vested_interest: omit each position's note from the rows — the review shape, when ten rows would otherwise each carry up to 2,000 characters of note."New value: +"vested_interest: omit position notes, term notes and mark basis explanations from the rows. Keeps exact term values and their basis/document/page provenance, plus mark amounts, dates and sources. Opt-in, including with changed_since; use smaller limit pages for large books. Full prose remains available through compact:false or admin position get."
  7. Changed17 schema fields changed
    • changedInput schema / properties / changed_since / description
      Previous value: -"private_book: only positions with something RECORDED on or after this — an event recorded, or the position created or updated — each row carrying `changes` (the events with when they were recorded, and created / updated flags). A YYYY-MM-DD date (or a time with no offset) is read as UTC; the response echoes as_of (ISO) to pass back next time for an exact cutoff — but only when the whole matched set came back, so page to the end (has_more absent) before storing it. Limits: pages read live position state and return a completion-time watermark, so concurrent records or updates can be missed during pagination. A position field change shows as updated:true without a diff, and an event edited or deleted after the cutoff is invisible (events carry only a recorded time)."New value: +"vested_interest: only positions with something RECORDED on or after this — an event recorded, or the position created or updated — each row carrying `changes` (the events with when they were recorded, and created / updated flags). A YYYY-MM-DD date (or a time with no offset) is read as UTC; the response echoes as_of (ISO) to pass back next time for an exact cutoff — but only when the whole matched set came back, so page to the end (has_more absent) before storing it. Limits: pages read live position state and return a completion-time watermark, so concurrent records or updates can be missed during pagination. A position field change shows as updated:true without a diff, and an event edited or deleted after the cutoff is invisible (events carry only a recorded time)."
    • changedInput schema / properties / compact / description
      Previous value: -"private_book: omit each position's note from the rows — the review shape, when ten rows would otherwise each carry up to 2,000 characters of note."New value: +"vested_interest: omit each position's note from the rows — the review shape, when ten rows would otherwise each carry up to 2,000 characters of note."
    • changedInput schema / properties / count / description
      Previous value: -"Detail mode only: also return `matched` — the total number of transactions matching the filter across ALL pages — so you can size the result before paging. Opt-in because it runs a second count scan (private_book always returns matched)."New value: +"Detail mode only: also return `matched` — the total number of transactions matching the filter across ALL pages — so you can size the result before paging. Opt-in because it runs a second count scan (vested_interest always returns matched)."
    • changedInput schema / properties / currency / description
      Previous value: -"private_book: only positions in this currency (USD, NZD, …)."New value: +"vested_interest: only positions in this currency (USD, NZD, …)."
    • changedInput schema / properties / holder / description
      Previous value: -"private_book: only positions whose legal holder (the person, trust, LLC, IRA or nominee) contains this text, case-insensitive."New value: +"vested_interest: only positions whose legal holder (the person, trust, LLC, IRA or nominee) contains this text, case-insensitive."
    • changedInput schema / properties / include / description
      Previous value: -"Extra sections to include in output. transfers/investments/financing: include in pnl time series output. fi: FIRE primitives (annual_spend, fi_number_25x, lean/chubby/fat targets, years_to_fi) on summary. targets: 80/20 framework defaults on summary — emergency-buffer target sized by income shape (with months-short) and a savings-rate anchor vs the household's actual rate. marks: mark COVERAGE on private_book — marked_n, unmarked_n, stale_n and the as_of span of the marks that exist, per currency. Counts and dates only: marks are recorded opinions of different ages and are never summed into a total, so it answers how much of the book carries a current opinion, not what the book is worth."New value: +"Extra sections to include in output. transfers/investments/financing: include in pnl time series output. fi: FIRE primitives (annual_spend, fi_number_25x, lean/chubby/fat targets, years_to_fi) on summary. targets: 80/20 framework defaults on summary — emergency-buffer target sized by income shape (with months-short) and a savings-rate anchor vs the household's actual rate. marks: mark COVERAGE on vested_interest — marked_n, unmarked_n, stale_n and the as_of span of the marks that exist, per currency. Counts and dates only: marks are recorded opinions of different ages and are never summed into a total, so it answers how much of the book carries a current opinion, not what the book is worth."
    • changedInput schema / properties / include_resolved / description
      Previous value: -"private_book: also list resolved (exited / written-off) positions — left out by default, as in admin position list."New value: +"vested_interest: also list resolved (exited / written-off) positions — left out by default, as in admin position list."
    • changedInput schema / properties / instrument / description
      Previous value: -"private_book: only positions of this instrument (option, safe, private_equity_fund, …)."New value: +"vested_interest: only positions of this instrument (option, safe, private_equity_fund, …)."
    • changedInput schema / properties / issuer / description
      Previous value: -"private_book: only positions whose issuer (the company or fund) contains this text, case-insensitive."New value: +"vested_interest: only positions whose issuer (the company or fund) contains this text, case-insensitive."
    • changedInput schema / properties / limit / description
      Previous value: -"Page size in detail mode (default 25) and private_book mode (default 50). Ignored in grouped mode — use top there."New value: +"Page size in detail mode (default 25) and vested_interest mode (default 50). Ignored in grouped mode — use top there."
    • changedInput schema / properties / mark / description
      Previous value: -"private_book: only positions with no settled mark (none) or whose latest settled mark is stale (stale: older than 180 days, open positions only). A settled zero-dollar mark is marked; pending and superseded marks do not count. Uses the same status as include:[\"marks\"] coverage and stale_marks. Composes with other book filters; totals, matched, alerts, resolved_omitted and rollups cover this filtered set before paging."New value: +"vested_interest: only positions with no settled mark (none) or whose latest settled mark is stale (stale: older than 180 days, open positions only). A settled zero-dollar mark is marked; pending and superseded marks do not count. Uses the same status as include:[\"marks\"] coverage and stale_marks. Composes with other book filters; totals, matched, alerts, resolved_omitted and rollups cover this filtered set before paging."
    • changedInput schema / properties / private_book / description
      Previous value: -"The register of private holdings (angel checks, fund commitments, advisor equity): per position committed / paid-in / unfunded / distributed / DPI / net cash, open and past-due capital-call notices, and the latest mark with its as-of date and a staleness flag. Pages (limit, default 50, + cursor); resolved positions are left out unless include_resolved, and their count is echoed as resolved_omitted. Filters: instrument, issuer, vehicle, currency, mark, search (name / issuer / vehicle). totals, matched and the alerts cover the WHOLE filtered set, not the page. Totals per currency, never combined; marks never summed. cost_basis (per position and in the totals) is what is still AT RISK — paid_in minus return_of_capital minus written_off — not what went in; return_of_capital / fees / written_off print beside it whenever they are non-zero, so a write-off is never a silent gap between the two. On a resolved position net_cash is the realized result and dpi the realized multiple. Ignores period and the ledger filters."New value: +"Deprecated: renamed vested_interest. Still accepted, with a param_warning — send vested_interest."
    • changedInput schema / properties / rollup_by / description
      Previous value: -"private_book: return GROUPS instead of rows — per group its included position count, resolved_omitted count when resolved positions were left out, and its per-currency totals, and no positions at all. A resolved-only group has n:0 and empty totals; include_resolved counts those positions and omits resolved_omitted. The whole register in one call: 86 positions is ~78KB of rows and past most tool-result limits, where the same book by segment is a handful of lines. Each group names its DIMENSION as the key ({ segment: \"syndicate\", n, totals }), so the value can be sent straight back as that filter; a position with no value for the dimension buckets under \"undeclared\". Groups cover the whole filtered set, so limit and cursor do not apply — there are no rows to page."New value: +"vested_interest: return GROUPS instead of rows — per group its included position count, resolved_omitted count when resolved positions were left out, and its per-currency totals, and no positions at all. A resolved-only group has n:0 and empty totals; include_resolved counts those positions and omits resolved_omitted. The whole register in one call: 86 positions is ~78KB of rows and past most tool-result limits, where the same book by segment is a handful of lines. Each group names its DIMENSION as the key ({ segment: \"syndicate\", n, totals }), so the value can be sent straight back as that filter; a position with no value for the dimension buckets under \"undeclared\". Groups cover the whole filtered set, so limit and cursor do not apply — there are no rows to page."
    • changedInput schema / properties / segment / description
      Previous value: -"private_book: only this book — employment, direct, fund, syndicate, other. The employment book in one call. \"undeclared\" returns the positions that declare NO segment — nothing else reaches those, since the column is nullable with no default and they match no other value."New value: +"vested_interest: only this book — employment, direct, fund, syndicate, other. The employment book in one call. \"undeclared\" returns the positions that declare NO segment — nothing else reaches those, since the column is nullable with no default and they match no other value."
    • changedInput schema / properties / terms_basis / description
      Previous value: -"private_book: only positions carrying at least one term on any of these bases. One value or a list, so terms_basis:[\"assumed\",\"missing\"] is the whole what-only-you-can-confirm list in ONE call."New value: +"vested_interest: only positions carrying at least one term on any of these bases. One value or a list, so terms_basis:[\"assumed\",\"missing\"] is the whole what-only-you-can-confirm list in ONE call."
    • changedInput schema / properties / vehicle / description
      Previous value: -"private_book: only positions held through a vehicle whose name contains this text, case-insensitive. \"undeclared\" returns the positions held through NO vehicle (a direct deal, an employment grant)."New value: +"vested_interest: only positions held through a vehicle whose name contains this text, case-insensitive. \"undeclared\" returns the positions held through NO vehicle (a direct deal, an employment grant)."
    • addedInput schema / properties / vested_interest
      Added value: +{
      +  "description": "The register of private holdings (angel checks, fund commitments, advisor equity): per position committed / paid-in / unfunded / distributed / DPI / net cash, open and past-due capital-call notices, and the latest mark with its as-of date and a staleness flag. Pages (limit, default 50, + cursor); resolved positions are left out unless include_resolved, and their count is echoed as resolved_omitted. Filters: instrument, issuer, vehicle, currency, mark, search (name / issuer / vehicle). totals, matched and the alerts cover the WHOLE filtered set, not the page. Totals per currency, never combined; marks never summed. cost_basis (per position and in the totals) is what is still AT RISK — paid_in minus return_of_capital minus written_off — not what went in; return_of_capital / fees / written_off print beside it whenever they are non-zero, so a write-off is never a silent gap between the two. On a resolved position net_cash is the realized result and dpi the realized multiple. Ignores period and the ledger filters.",
      +  "type": "boolean"
      +}
  8. Changed2 schema fields changed
    • addedInput schema / properties / mark
      Added value: +{
      +  "description": "private_book: only positions with no settled mark (none) or whose latest settled mark is stale (stale: older than 180 days, open positions only). A settled zero-dollar mark is marked; pending and superseded marks do not count. Uses the same status as include:[\"marks\"] coverage and stale_marks. Composes with other book filters; totals, matched, alerts, resolved_omitted and rollups cover this filtered set before paging.",
      +  "enum": [
      +    "none",
      +    "stale"
      +  ],
      +  "type": "string"
      +}
    • changedInput schema / properties / private_book / description
      Previous value: -"The register of private holdings (angel checks, fund commitments, advisor equity): per position committed / paid-in / unfunded / distributed / DPI / net cash, open and past-due capital-call notices, and the latest mark with its as-of date and a staleness flag. Pages (limit, default 50, + cursor); resolved positions are left out unless include_resolved, and their count is echoed as resolved_omitted. Filters: instrument, issuer, vehicle, currency, search (name / issuer / vehicle). totals, matched and the alerts cover the WHOLE filtered set, not the page. Totals per currency, never combined; marks never summed. cost_basis (per position and in the totals) is what is still AT RISK — paid_in minus return_of_capital minus written_off — not what went in; return_of_capital / fees / written_off print beside it whenever they are non-zero, so a write-off is never a silent gap between the two. On a resolved position net_cash is the realized result and dpi the realized multiple. Ignores period and the ledger filters."New value: +"The register of private holdings (angel checks, fund commitments, advisor equity): per position committed / paid-in / unfunded / distributed / DPI / net cash, open and past-due capital-call notices, and the latest mark with its as-of date and a staleness flag. Pages (limit, default 50, + cursor); resolved positions are left out unless include_resolved, and their count is echoed as resolved_omitted. Filters: instrument, issuer, vehicle, currency, mark, search (name / issuer / vehicle). totals, matched and the alerts cover the WHOLE filtered set, not the page. Totals per currency, never combined; marks never summed. cost_basis (per position and in the totals) is what is still AT RISK — paid_in minus return_of_capital minus written_off — not what went in; return_of_capital / fees / written_off print beside it whenever they are non-zero, so a write-off is never a silent gap between the two. On a resolved position net_cash is the realized result and dpi the realized multiple. Ignores period and the ledger filters."
  9. Changed1 schema field changed
    • changedInput schema / properties / explain / description
      Previous value: -"Provenance trace for a single transaction's naming and classification"New value: +"Provenance trace for a single transaction's naming and classification. Search selects the most recent match and returns matched (the full match count); use transaction_id for an exact selection."
  10. Changed2 schema fields changed
    • changedInput schema / properties / digest / description
      Previous value: -"Daily 'what should I flag' digest: a 30-day low-balance forecast, missed bills, unusual charges (large/price-change/fees), plan exceptions when a plan exists (breached spending limits, missed income, over-budget events, off-pace spending), and broken bank connections, in one bounded read-only call. Built for a scheduled/cron agent — safe to run every morning."New value: +"Daily 'what should I flag' digest: a 30-day low-balance forecast, missed bills (late payments out, never moves between your own accounts), late income (paychecks and other deposits of $25 or more that haven't arrived), unusual charges (large/price-change/fees), plan exceptions when a plan exists (breached spending limits, missed income, over-budget events, off-pace spending), and broken bank connections, in one bounded read-only call. Built for a scheduled/cron agent — safe to run every morning."
    • changedInput schema / properties / rollup_by / description
      Previous value: -"private_book: return GROUPS instead of rows — per group its position count and its per-currency totals, and no positions at all. The whole register in one call: 86 positions is ~78KB of rows and past most tool-result limits, where the same book by segment is a handful of lines. Each group names its DIMENSION as the key ({ segment: \"syndicate\", n, totals }), so the value can be sent straight back as that filter; a position with no value for the dimension buckets under \"undeclared\". Groups cover the whole filtered set, so limit and cursor do not apply — there are no rows to page."New value: +"private_book: return GROUPS instead of rows — per group its included position count, resolved_omitted count when resolved positions were left out, and its per-currency totals, and no positions at all. A resolved-only group has n:0 and empty totals; include_resolved counts those positions and omits resolved_omitted. The whole register in one call: 86 positions is ~78KB of rows and past most tool-result limits, where the same book by segment is a handful of lines. Each group names its DIMENSION as the key ({ segment: \"syndicate\", n, totals }), so the value can be sent straight back as that filter; a position with no value for the dimension buckets under \"undeclared\". Groups cover the whole filtered set, so limit and cursor do not apply — there are no rows to page."
  11. Changed2 schema fields changed
    • changedInput schema / properties / tax_documents / description
      Previous value: -"Which tax forms to expect, derived from the money Cashflow can see: wages→W-2, interest→1099-INT, dividends→1099-DIV (kept per issuer), plus categorized tuition/childcare/charitable → 1098-T/statement/acknowledgment. Each form carries its issuer, amount, and confidence (form vs issuer). Returns a `cannot_see` list (mortgage 1098, 1099-B, 1099-R, income we can't see…) so it's never read as exhaustive, and `needs_review` for possible-1099 income to chase. Defaults to the just-completed tax year (last_year Jan–Apr, else this_year); pass `year`/`period` to scope. A checklist to hand a preparer or reconcile against email — not a return, not tax advice."New value: +"Which tax forms to expect, derived from the money Cashflow can see: wages→W-2, interest→1099-INT, dividends→1099-DIV (kept per issuer), plus categorized tuition/childcare/charitable → 1098-T/statement/acknowledgment. Each form carries its issuer, amount, and confidence (form vs issuer). Returns a `cannot_see` list (mortgage 1098, 1099-B, 1099-R, income we can't see…) so it's never read as exhaustive, and `needs_review` for possible-1099 income to chase. Defaults to the just-completed tax year (last_year Jan–Apr, else this_year); pass `year`/`period` to scope. A checklist to hand a preparer or reconcile against email — not a return, not tax advice. US households only."
    • changedInput schema / properties / tax_ledger / description
      Previous value: -"What you paid the government this year: tax payments by category (Federal/State/Local/Property Tax), refunds from tax authorities, and net_paid. Returns an `excludes` note (e.g. paycheck withholding isn't visible in the bank feed) so a W2 user is never told they paid $0. Defaults to this_year. Organizes what happened to hand to a preparer — not tax advice."New value: +"What you paid the government this year: tax payments by category (Federal/State/Local/Property Tax), refunds from tax authorities, and net_paid. Returns an `excludes` note (e.g. paycheck withholding isn't visible in the bank feed) so a W2 user is never told they paid $0. Defaults to this_year. Organizes what happened to hand to a preparer — not tax advice. US households only."
  12. Changed4 schema fields changed
    • changedInput schema / properties / amount_max / description
      Previous value: -"Maximum absolute amount (dollars)"New value: +"Maximum absolute amount (household's currency)"
    • changedInput schema / properties / amount_min / description
      Previous value: -"Minimum absolute amount (dollars)"New value: +"Minimum absolute amount (household's currency)"
    • changedInput schema / properties / scenario / properties / add / description
      Previous value: -"New regular flows to add (e.g. a $600/mo rent increase). They hit the projected balance — the bills-tagged accounts when the forecast is narrowed to them"New value: +"New regular flows to add (e.g. a 600/mo rent increase). They hit the projected balance — the bills-tagged accounts when the forecast is narrowed to them"
    • changedInput schema / properties / scenario / properties / add / items / properties / amount / description
      Previous value: -"Amount in dollars per occurrence"New value: +"Amount in the household's currency per occurrence"
  13. Changed2 schema fields changed
    • changedInput schema / properties / changed_since / description
      Previous value: -"private_book: only positions with something RECORDED on or after this — an event recorded, or the position created or updated — each row carrying `changes` (the events with when they were recorded, and created / updated flags). A YYYY-MM-DD date (or a time with no offset) is read as UTC; the response echoes as_of (ISO) to pass back next time for an exact cutoff — but only when the whole matched set came back, so page to the end (has_more absent) before storing it. Limits: a position field change shows as updated:true without a diff, and an event edited or deleted after the cutoff is invisible (events carry only a recorded time)."New value: +"private_book: only positions with something RECORDED on or after this — an event recorded, or the position created or updated — each row carrying `changes` (the events with when they were recorded, and created / updated flags). A YYYY-MM-DD date (or a time with no offset) is read as UTC; the response echoes as_of (ISO) to pass back next time for an exact cutoff — but only when the whole matched set came back, so page to the end (has_more absent) before storing it. Limits: pages read live position state and return a completion-time watermark, so concurrent records or updates can be missed during pagination. A position field change shows as updated:true without a diff, and an event edited or deleted after the cutoff is invisible (events carry only a recorded time)."
    • changedInput schema / properties / since / description
      Previous value: -"Detail mode only: return just transactions that arrived (were synced) after this ISO timestamp — the `as_of` value from a previous run. For a scheduled 'what's new since last time' check; the response echoes a fresh `as_of` to store for next time — only on the page that completes the set, so page to the end (has_more absent) before storing it."New value: +"Detail mode only: transactions recorded on or after this ISO timestamp — the `as_of` from a previous run. The first page pins an upper recorded-time bound carried by its cursors, so later arrivals wait for the next run. Keep the original since and sort while paging; store as_of only after has_more is absent. Timestamp equality may replay boundary rows: deduplicate by transaction id."
  14. Changed1 schema field changed
    • changedInput schema / properties / since / description
      Previous value: -"Detail mode only: return just transactions that arrived (were synced) after this ISO timestamp — the `as_of` value from a previous run. For a scheduled 'what's new since last time' check; the response echoes a fresh `as_of` to store for next time."New value: +"Detail mode only: return just transactions that arrived (were synced) after this ISO timestamp — the `as_of` value from a previous run. For a scheduled 'what's new since last time' check; the response echoes a fresh `as_of` to store for next time — only on the page that completes the set, so page to the end (has_more absent) before storing it."
  15. Changed1 schema field changed
    • changedInput schema / properties / top / description
      Previous value: -"Limit grouped results to top N. In the time-series matrix (by + granularity) it caps every section's rows: expense groups past N fold into \"Other\" so groups still sum to the total (over by:tag, whose buckets overlap, the extra tags are dropped, not folded); nest.top caps the items under each group."New value: +"Limit grouped results to top N by amount; grouped comparisons rank by absolute change and include rows with only prior activity. In the time-series matrix (by + granularity) it caps every section's rows: expense groups past N fold into \"Other\" so groups still sum to the total (over by:tag, whose buckets overlap, the extra tags are dropped, not folded); nest.top caps the items under each group."
  16. Changed4 schema fields changed
    • changedInput schema / properties / changed_since / anyOf
      Previous value: -[
      -  {
      -    "format": "date",
      -    "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
      -    "type": "string"
      -  },
      -  {
      -    "format": "date-time",
      -    "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z||([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
      -    "type": "string"
      -  }
      -]New value: +[
      +  {
      +    "format": "date",
      +    "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
      +    "type": "string"
      +  },
      +  {
      +    "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d))|(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?)$",
      +    "type": "string"
      +  }
      +]
    • removedInput schema / properties / is_active / anyOf
      Removed value: -[
      -  {
      -    "type": "boolean"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedInput schema / properties / is_active / type
      Added value: +[
      +  "boolean",
      +  "null"
      +]
    • removedInput schema / required
      Removed value: -[
      -  "view"
      -]
  17. Changed6 schema fields changed
    • changedInput schema / properties / by / description
      Previous value: -"Aggregate by dimension(s). Triggers grouped mode. category_tag groups by canonical category tag (essential / discretionary / untagged); most useful with type=expense."New value: +"Aggregate by dimension(s). Triggers grouped mode. category_tag groups by canonical category tag (essential / discretionary / untagged); most useful with type=expense. country groups by merchant country (ISO alpha-2), city by merchant city; rows with none land in \"Unknown\"."
    • changedInput schema / properties / by / items / enum
      Previous value: -[
      -  "group",
      -  "category",
      -  "party",
      -  "account",
      -  "tag",
      -  "category_tag"
      -]New value: +[
      +  "group",
      +  "category",
      +  "party",
      +  "account",
      +  "tag",
      +  "category_tag",
      +  "country",
      +  "city"
      +]
    • addedInput schema / properties / city
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    }
      +  ],
      +  "description": "Merchant city — exact match, case-insensitive. Only where the bank reports one (mostly linked accounts)."
      +}
    • addedInput schema / properties / country
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    }
      +  ],
      +  "description": "Merchant country — ISO alpha-2 (\"GR\"), alpha-3 (\"GRC\") or English name (\"Greece\"), any case. The merchant's country as the bank or card network reports it; rows with no known country never match."
      +}
    • changedInput schema / properties / nest / properties / by / enum
      Previous value: -[
      -  "party",
      -  "category",
      -  "account",
      -  "tag",
      -  "category_tag"
      -]New value: +[
      +  "category",
      +  "party",
      +  "account",
      +  "tag",
      +  "category_tag",
      +  "country",
      +  "city"
      +]
    • changedInput schema / properties / split_by / enum
      Previous value: -[
      -  "group",
      -  "category",
      -  "party",
      -  "account",
      -  "tag",
      -  "category_tag"
      -]New value: +[
      +  "group",
      +  "category",
      +  "party",
      +  "account",
      +  "tag",
      +  "category_tag",
      +  "country",
      +  "city"
      +]
  18. Changed1 schema field changed
    • changedInput schema / properties / view / description
      Previous value: -"Reporting view (summary, grouped, time-series). 'as_booked' (default; alias 'actual') = raw actuals; 'adjusted' = with the adjustment overlay folded into the headline totals, and into the prior period under `compare`, so vs_prior compares adjusted to adjusted. Manage entries via admin { entity: 'adjustment' }."New value: +"Reporting view (summary, grouped, time-series). 'as_booked' (default; alias 'actual') = raw actuals; 'adjusted' = with the adjustment overlay folded into the headline totals, and into the prior period under `compare`, so vs_prior compares adjusted to adjusted. category/group filters (and their exclude_*) scope the overlay; any other filter returns as_booked. Manage entries via admin { entity: 'adjustment' }."
  19. First observed

TDQS

Score is being calculated.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources