Server definition
- Hash
- sha256:f67055e3e42d2b4ca7ecc9bc20e75c23576da7ecc86f4962135d62c0f9e6fa8e
- What it is
- What a remote MCP server returned when asked what it offers: 89 tools
The blob, as servednamed by its sha256
{
"instructions": "RateAPI serves live, evidence-backed rates published by US credit unions: mortgage (fixed, ARM, FHA/VA/USDA/jumbo, investor/DSCR), auto, RV, boat, motorcycle, powersports, HELOC, personal, student, equipment and credit-card rates, plus deposit APYs (savings, money market, CDs and share certificates). Coverage is roughly 2,950 credit unions with fresh rates across 55 US states and territories, re-observed daily on weekdays. Every rate is backed by a verbatim snippet from the institution's own page: if a rate cannot be evidenced, it is not served.\n\nWHICH TOOL:\n- The user is shopping and has no quote -> get_financing_decision (ranked offers with the savings math done).\n- The user already has a quoted rate and wants a verdict -> rate_sanity_check, not a fresh offer list.\n- A named product near a ZIP, no borrower details -> find_product_rates_near_zip; nearest institutions -> find_credit_unions_near_zip.\n- \"Can I join?\" -> find_eligible_credit_unions (person's own facts) or check_membership_eligibility (named institutions).\n- Several explicit loan/deposit products for one person -> get_personal_access_catalog. Keep membership, suitability, published price, underwriting and approval separate; unknown is never a denial.\n- An employer, school, association or worship name needs a canonical id -> search_eligibility_entities, then resolve_eligibility_entities. Only one exact normalized match is authoritative; resolution itself is never eligibility.\n- Compare confirmed before/after facts -> compare_reachable_offers. Evaluate a small explicitly supplied panel -> evaluate_eligibility_cohort; use neutral labels and never extrapolate it to a population or conversion rate.\n- The person described themselves in prose rather than fields -> extract_eligibility_facts first, confirm what it read back to them, then find_eligible_credit_unions. It never decides eligibility itself; only the deterministic graph does.\n- An eligibility answer came back mostly unknown -> that is not a no. Read next_questions, ask the top one or two, and call again with the answers merged into the same body.\n- Market context -> get_benchmarks, get_deposit_benchmarks, get_league_table. For deposit tools the MCP argument is product with exact underscore values such as money_market; REST uses product_category. Raw rows to filter yourself -> list_rates.\n- A question about THIS API rather than about a rate (\"how do I authenticate?\", \"what does rate_phase mean?\", \"what does it cost?\") -> search_docs, then get_doc. Do not guess at parameters or invent endpoints.\n\nCONSTRAINTS - breaking these produces answers the user cannot tell are wrong:\n- Published pricing is not an offer. Nothing here is a quote, pre-approval or commitment to lend; final terms come from the institution after underwriting, and membership is required first.\n- Always state the observed date. Every rate carries as_of; a rate quoted without one reads as current forever. Rates outside the freshness window are suppressed, so an empty result means \"nothing fresh enough\", not \"no such product\".\n- Benchmarks are medians across the credit unions tracked. Say \"credit union median\", never \"the national average\".\n- Name the institution behind any APR. An unattributed rate is not actionable.\n- Respect rate_phase: promotional and teaser rates are flagged. Label a teaser as a teaser or omit it.\n- Unknown is not ineligible, and an unanswered question is not a closed door. Never tell a user they cannot join an institution that returned unknown; tell them what we still need to know, from missing_facts / next_questions. Where unanswerable names a reason, say that instead of asking — no answer they can give will change it.\n- On eligibility, unknown never means no. A returned credit union with no proven matching path remains in the result as unknown; fom_completeness_unaffirmed means the published field-of-membership corpus is not attested complete, so never infer rejection. Legacy negative enum values are reserved for compatibility and are not a user-facing denial without a future typed closed-world attestation.\n- Never infer canonical *_org_ids from prose. Use only ids explicitly selected by the caller or returned as one exact resolution, and keep relative_* ids scoped to the relative. Do not put names, emails or account identifiers in cohort profile labels.\n- Quote the deterministic reasons text verbatim. distance_miles is straight-line, not driving distance. apr: null means the lender published none - render \"not published\", never a number.\n- Ranking is by true cost (APR including points and fees). RateAPI takes no affiliate or placement revenue, so position carries no commercial meaning.\n\nCoverage is US credit unions only - not banks, not benchmark indices like SOFR or Treasury yields, not non-US rates. Some core Rates and calculator tools run with no account. Dedicated RateAPI Routes tools require a signed-in Enterprise organization; a 402 means the credential is valid but the plan must change. Account-scoped tools (monitors, scenarios, cohorts, shares, campaigns) return a sign-in challenge.",
"tools": [
{
"description": "Add recipients (email + optional name) to a campaign. Up to 50 per request, 200 per campaign. Duplicate addresses are ignored.",
"inputSchema": {
"properties": {
"id": {
"description": "Campaign id. Required.",
"type": "string"
},
"recipients": {
"description": "Recipients to add.",
"items": {
"properties": {
"email": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"email"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"id",
"recipients"
],
"type": "object"
},
"name": "add_campaign_recipients",
"outputSchema": {
"additionalProperties": true,
"description": "Counts after adding recipients. Duplicates within the request and addresses already on the campaign are skipped, so `added` can be lower than the number submitted.",
"properties": {
"added": {
"description": "Recipients newly inserted by this call.",
"type": "number"
},
"total": {
"description": "Total recipients on the campaign afterwards (capped at 200).",
"type": "number"
}
},
"type": "object"
}
},
{
"description": "Compare projected cost of renting vs buying a home over a holding period, anchored to LIVE market mortgage rates. Given home price, down payment, monthly rent, and a holding period, returns year-by-year cumulative cost of each path (rent vs PITI), equity built, net cost of owning after sale, and the breakeven year where buying becomes cheaper than renting. If no rate is supplied, the current best market rate for the state is used. Use for 'should I rent or buy?' questions.",
"inputSchema": {
"properties": {
"annual_insurance": {
"description": "Homeowners insurance in dollars/year. Default max(800, 0.35% of home price).",
"type": "number"
},
"closing_cost_pct": {
"description": "Buying closing costs as % of home price. Default 3.0.",
"type": "number"
},
"down_payment": {
"description": "Cash down payment in dollars. Default 20% of home_price.",
"type": "number"
},
"holding_period_years": {
"description": "How many years you plan to own. Default 7.",
"type": "number"
},
"home_appreciation_rate": {
"description": "Annual home appreciation as %. Default 3.0.",
"type": "number"
},
"home_price": {
"description": "Purchase price in dollars. Required.",
"type": "number"
},
"investment_return_rate": {
"description": "Opportunity cost return on invested savings as %. Default 5.0.",
"type": "number"
},
"maintenance_rate": {
"description": "Annual maintenance as % of home value. Default 1.0.",
"type": "number"
},
"marginal_tax_rate": {
"description": "Marginal tax rate as %, used to model mortgage-interest/property-tax deduction. Default 0 (no deduction).",
"type": "number"
},
"monthly_hoa": {
"description": "HOA dues in dollars/month. Default 0.",
"type": "number"
},
"monthly_rent": {
"description": "Current monthly rent in dollars. Required.",
"type": "number"
},
"pmi_rate": {
"description": "Annual PMI as % of loan balance. Default 0.5, applied only when LTV > 80%.",
"type": "number"
},
"property_tax_rate": {
"description": "Annual property tax as % of home value. Default 1.1.",
"type": "number"
},
"rate": {
"description": "Annual interest rate, e.g. 6.5. If omitted, best market rate for the state is used.",
"type": "number"
},
"rent_growth_rate": {
"description": "Annual rent growth as %. Default 3.0.",
"type": "number"
},
"selling_cost_pct": {
"description": "Selling costs as % of sale price. Default 6.0.",
"type": "number"
},
"state": {
"description": "2-letter US state code for the market-rate lookup. Default CA.",
"type": "string"
},
"term_months": {
"description": "Loan term in months. Default 360.",
"type": "number"
}
},
"required": [
"home_price",
"monthly_rent"
],
"type": "object"
},
"name": "analyze_rent_vs_buy",
"outputSchema": {
"additionalProperties": true,
"properties": {
"assumed_defaults": {
"description": "Every input that was defaulted rather than supplied. Rent-vs-buy swings hard on these, so surface them.",
"items": {
"additionalProperties": true,
"properties": {
"field": {
"description": "Name of the defaulted input, e.g. 'rate', 'property_tax_rate', 'annual_insurance'.",
"type": [
"string",
"null"
]
},
"reason": {
"description": "Why that value was chosen, e.g. resolved from live market data for the state or a national default.",
"type": [
"string",
"null"
]
},
"value": {
"description": "Value used for that input, formatted as a percent or dollar string.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"breakeven": {
"additionalProperties": true,
"description": "When buying overtakes renting on the assumptions used.",
"properties": {
"months": {
"description": "The same crossover expressed in months from the start.",
"type": [
"number",
"null"
]
},
"note": {
"description": "Plain-English statement of the crossover and whether it falls inside the modeled horizon.",
"type": [
"string",
"null"
]
},
"year": {
"description": "Year in which buying becomes cheaper than renting. Null when it never does within the horizon.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"buy": {
"additionalProperties": true,
"description": "The full economics of buying over the holding period.",
"properties": {
"monthly_breakdown": {
"description": "The monthly cost split into principal_interest, tax, insurance, pmi, hoa, and maintenance, each in dollars.",
"type": "object"
},
"monthly_piti": {
"description": "Total monthly housing cost in dollars when buying: principal, interest, taxes, insurance, plus PMI, HOA, and maintenance where modeled.",
"type": [
"number",
"null"
]
},
"net_cost_after_equity": {
"description": "True cost of owning in dollars: total paid less the proceeds recovered at sale. This is the figure to compare with renting.",
"type": [
"number",
"null"
]
},
"net_proceeds_at_sale": {
"description": "Cash in dollars left after selling at the end of the period and paying off the loan and selling costs.",
"type": [
"number",
"null"
]
},
"total_cost_over_period": {
"description": "All dollars paid out while owning over the holding period, including the down payment and monthly costs.",
"type": [
"number",
"null"
]
},
"year_by_year": {
"description": "One entry per year of the holding period, tracking equity, home value, loan balance, and cumulative cost in dollars.",
"type": "array"
},
"year_by_year_truncated_from": {
"description": "Full number of years modeled before the array above was shortened for display. Null when nothing was omitted.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"confidence": {
"description": "Qualitative confidence in the recommendation — 'high' when the margin is wide relative to the assumptions.",
"type": [
"string",
"null"
]
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"next_actions": {
"description": "Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.",
"items": {
"additionalProperties": true,
"properties": {
"tool": {
"description": "Name of the follow-up MCP tool to call next.",
"type": [
"string",
"null"
]
},
"why": {
"description": "One-line reason this follow-up tool would be useful given the current result.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"rate_source": {
"description": "Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.",
"type": [
"string",
"null"
]
},
"rate_used": {
"description": "Mortgage rate in percent used for the buy path (6 = 6.00%). Check rate_source to see whether it was supplied or resolved from live market data.",
"type": [
"number",
"null"
]
},
"recommendation": {
"description": "Which path the model favors on these assumptions: 'buy' or 'rent'.",
"type": [
"string",
"null"
]
},
"rent": {
"additionalProperties": true,
"description": "The full economics of renting over the same holding period.",
"properties": {
"opportunity_value_of_invested_savings": {
"description": "Dollars the renter is assumed to accumulate by investing the down payment and any monthly difference — this is credited to the rent side.",
"type": [
"number",
"null"
]
},
"starting_monthly_rent": {
"description": "Monthly rent in dollars at the start of the period, before the assumed annual increases.",
"type": [
"number",
"null"
]
},
"total_cost_over_period": {
"description": "All rent paid in dollars over the holding period.",
"type": [
"number",
"null"
]
},
"year_by_year": {
"description": "One entry per year, with the annual rent and cumulative cost in dollars as rent escalates.",
"type": "array"
},
"year_by_year_truncated_from": {
"description": "Full number of years modeled before the array above was shortened. Null when nothing was omitted.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"summary_note": {
"description": "One-sentence bottom line with the dollar gap between the two paths, safe to quote.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Frame a buy/refi-now vs wait recommendation. Combines recent rate movement (direction + magnitude over 1w/2w/4w) with break-even sensitivity on the borrower's loan to return a forward 'lock now' vs 'wait' lean, the bps swing that would change the call, and the cost of waiting. Use for 'should I lock now or wait for rates to drop?' questions. Distinct from get_rate_delta (raw historical deltas only) — this adds a forward recommendation. Not a rate forecast.",
"inputSchema": {
"properties": {
"closing_costs": {
"description": "Closing/refi costs in dollars (default 0)",
"type": "number"
},
"current_rate": {
"description": "Borrower's existing or quoted rate %, enables refi-now framing",
"type": "number"
},
"loan_amount": {
"description": "Loan amount in dollars — drives break-even sensitivity",
"type": "number"
},
"product_type": {
"description": "Loan product",
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"credit_card",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"rate_shift_bps": {
"description": "Hypothetical bps move if waiting; default derived from observed movement",
"type": "number"
},
"since": {
"description": "Movement window (default 4w)",
"enum": [
"1w",
"2w",
"4w"
],
"type": "string"
},
"state": {
"description": "2-letter US state code",
"type": "string"
},
"term_months": {
"description": "Loan term in months (default 360 for mortgage)",
"type": "number"
}
},
"required": [
"product_type",
"state",
"loan_amount"
],
"type": "object"
},
"name": "assess_buy_timing",
"outputSchema": {
"additionalProperties": true,
"properties": {
"assumed_defaults": {
"additionalProperties": true,
"description": "Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.",
"properties": {
"closing_costs": {
"description": "Closing costs in dollars assumed because the caller did not supply them.",
"type": [
"number",
"null"
]
},
"rate_shift_bps": {
"description": "Rate shift in basis points assumed for the wait scenario because the caller did not supply one.",
"type": [
"number",
"null"
]
},
"since": {
"description": "Lookback window assumed for the rate-movement comparison because the caller did not supply one.",
"type": [
"string",
"null"
]
},
"term_months": {
"description": "Loan term in months assumed because the caller did not supply one.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"break_even": {
"additionalProperties": true,
"description": "How the cost of waiting nets out against the hoped-for saving.",
"properties": {
"break_even_months": {
"description": "Months of the projected monthly saving needed to repay the cost of waiting.",
"type": [
"number",
"null"
]
},
"net_cost_of_waiting": {
"description": "Net dollars waiting would cost. A negative value means waiting would save money on these assumptions.",
"type": [
"number",
"null"
]
},
"payment_swing_per_25bps": {
"description": "Dollars the monthly payment moves for every 25 basis point change in rate; a quick sensitivity yardstick.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"confidence": {
"description": "Qualitative confidence in the recommendation — 'high', 'medium', or 'low' — driven by how much data and how large the margin is.",
"type": [
"string",
"null"
]
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"movement": {
"additionalProperties": true,
"description": "How the market has moved over the comparison window, from the earlier snapshot to now.",
"properties": {
"direction": {
"description": "Direction of the median move over the window: 'up', 'down', or 'flat'.",
"type": [
"string",
"null"
]
},
"median_delta_pct": {
"description": "Change in the median APR over the window, in percentage points (0.25 = 25 basis points). Negative means rates fell.",
"type": [
"number",
"null"
]
},
"now": {
"description": "Current market snapshot (min, median, max APR in percent, offer count, and as-of timestamp).",
"type": "object"
},
"then": {
"description": "Market snapshot at the start of the window, for comparison against `now`. Its `count` is often much smaller because history is retention-bounded.",
"type": "object"
}
},
"type": "object"
},
"next_actions": {
"description": "Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.",
"items": {
"additionalProperties": true,
"properties": {
"tool": {
"description": "Name of the follow-up MCP tool to call next.",
"type": [
"string",
"null"
]
},
"why": {
"description": "One-line reason this follow-up tool would be useful given the current result.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"note": {
"description": "A caveat about the DATA behind this call, not an error — e.g. limited rate history for that product and state, so the answer is a snapshot rather than a timing judgement. Present only when such a caveat applies; carry it into any answer.",
"type": [
"string",
"null"
]
},
"now": {
"additionalProperties": true,
"description": "The best deal available today, for comparison against waiting.",
"properties": {
"best_lender": {
"description": "Credit union publishing that best rate.",
"type": [
"string",
"null"
]
},
"best_rate": {
"description": "Best published rate in percent available right now for this product and state.",
"type": [
"number",
"null"
]
},
"monthly_payment": {
"description": "Monthly principal-and-interest payment in dollars at that best rate.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"product_type": {
"description": "Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.",
"type": [
"string",
"null"
]
},
"rationale": {
"description": "Plain-English explanation of why this recommendation was reached; safe to quote to the user as the reasoning.",
"type": [
"string",
"null"
]
},
"recommendation": {
"description": "The suggested move, e.g. 'buy_now' or 'wait'.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
},
"wait_scenario": {
"additionalProperties": true,
"description": "A what-if for waiting, built from the caller's assumed rate shift. It is a sensitivity test, not a forecast.",
"properties": {
"assumed_shift_bps": {
"description": "Rate change in basis points the wait scenario assumes (-25 = rates fall a quarter point). Supplied by the caller, not predicted.",
"type": [
"number",
"null"
]
},
"monthly_delta": {
"description": "Change in monthly payment in dollars if the assumed shift happens; negative means waiting would be cheaper per month.",
"type": [
"number",
"null"
]
},
"projected_monthly_payment": {
"description": "Monthly payment in dollars at the projected rate.",
"type": [
"number",
"null"
]
},
"projected_rate": {
"description": "Rate in percent implied by applying that shift to today's best rate.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"window": {
"description": "Lookback period used for the comparison, expressed as a short duration string such as '4w', '90d', or '180d'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Lock-window-aware lock-vs-float-down recommendation for a deal already in the pipeline. Given a known lock-expiration date, the currently locked rate, and the float-down cost, returns a defensible hold-lock vs exercise-float-down call a loan officer can document — combining recent market movement (1w/2w/4w) with payment and break-even math on this loan. Builds on the same recent-movement signal as assess_buy_timing but framed around the lock window/expiration. Not a rate forecast.",
"inputSchema": {
"properties": {
"float_down_bps": {
"description": "optional improvement in bps if float_down_rate omitted",
"type": "number"
},
"float_down_cost": {
"description": "$ to exercise float-down; default 0",
"type": "number"
},
"float_down_rate": {
"description": "optional explicit floated rate %",
"type": "number"
},
"loan_amount": {
"type": "number"
},
"lock_expiration_date": {
"description": "ISO date YYYY-MM-DD",
"type": "string"
},
"locked_rate": {
"description": "% already locked",
"type": "number"
},
"product_type": {
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"credit_card",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"since": {
"description": "movement window; default 4w",
"enum": [
"1w",
"2w",
"4w"
],
"type": "string"
},
"state": {
"description": "2-letter state code",
"type": "string"
},
"term_months": {
"description": "default 360",
"type": "number"
}
},
"required": [
"product_type",
"state",
"loan_amount",
"lock_expiration_date",
"locked_rate"
],
"type": "object"
},
"name": "assess_rate_lock",
"outputSchema": {
"additionalProperties": true,
"properties": {
"assumed_defaults": {
"additionalProperties": true,
"description": "Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.",
"properties": {
"closing_costs": {
"description": "Closing costs in dollars assumed because the caller did not supply them.",
"type": [
"number",
"null"
]
},
"float_down_cost": {
"description": "Float-down fee in dollars assumed because the caller did not supply one.",
"type": [
"number",
"null"
]
},
"since": {
"description": "Lookback window assumed for the rate-movement comparison because the caller did not supply one.",
"type": [
"string",
"null"
]
},
"term_months": {
"description": "Loan term in months assumed because the caller did not supply one.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"confidence": {
"description": "Qualitative confidence in the recommendation — 'high', 'medium', or 'low' — driven by how much data and how large the margin is.",
"type": [
"string",
"null"
]
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"float_down": {
"additionalProperties": true,
"description": "Economics of exercising a float-down to today's market rate.",
"properties": {
"available_improvement_bps": {
"description": "How far the market sits below the locked rate, in basis points (87.5 = 0.875 percentage points).",
"type": [
"number",
"null"
]
},
"break_even_months": {
"description": "Months of savings needed to repay the float-down fee.",
"type": [
"number",
"null"
]
},
"float_down_cost": {
"description": "Fee in dollars the lender charges to exercise the float-down.",
"type": [
"number",
"null"
]
},
"lifetime_savings": {
"description": "Total interest in dollars saved over the full term, before the float-down fee.",
"type": [
"number",
"null"
]
},
"monthly_savings": {
"description": "Dollars per month saved at the improved rate.",
"type": [
"number",
"null"
]
},
"net_benefit": {
"description": "Lifetime savings less the float-down fee, in dollars — the honest headline number.",
"type": [
"number",
"null"
]
},
"projected_rate": {
"description": "Rate in percent the borrower would move to by floating down.",
"type": [
"number",
"null"
]
},
"worth_it": {
"description": "True when the float-down clears its cost on these assumptions.",
"type": [
"boolean",
"null"
]
}
},
"type": "object"
},
"lock": {
"additionalProperties": true,
"description": "The borrower's existing rate lock and how much time is left on it.",
"properties": {
"days_remaining": {
"description": "Days left before the lock expires; the decision window for acting.",
"type": [
"number",
"null"
]
},
"expired": {
"description": "True when the lock has already lapsed, in which case the float-down analysis no longer applies.",
"type": [
"boolean",
"null"
]
},
"lock_expiration_date": {
"description": "Date the lock expires (ISO date).",
"type": [
"string",
"null"
]
},
"locked_rate": {
"description": "Rate in percent the borrower has locked.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"market_now": {
"additionalProperties": true,
"description": "Best deal currently available in the market, for comparison against the locked rate.",
"properties": {
"best_lender": {
"description": "Credit union publishing that best rate.",
"type": [
"string",
"null"
]
},
"best_rate": {
"description": "Best published rate in percent available right now.",
"type": [
"number",
"null"
]
},
"monthly_payment": {
"description": "Monthly principal-and-interest payment in dollars at that best rate.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"movement": {
"additionalProperties": true,
"description": "How the market has moved over the comparison window, from the earlier snapshot to now.",
"properties": {
"direction": {
"description": "Direction of the median move over the window: 'up', 'down', or 'flat'.",
"type": [
"string",
"null"
]
},
"median_delta_pct": {
"description": "Change in the median APR over the window, in percentage points (0.25 = 25 basis points). Negative means rates fell.",
"type": [
"number",
"null"
]
},
"now": {
"description": "Current market snapshot (min, median, max APR in percent, offer count, and as-of timestamp).",
"type": "object"
},
"then": {
"description": "Market snapshot at the start of the window, for comparison against `now`. Its `count` is often much smaller because history is retention-bounded.",
"type": "object"
}
},
"type": "object"
},
"next_actions": {
"description": "Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.",
"items": {
"additionalProperties": true,
"properties": {
"tool": {
"description": "Name of the follow-up MCP tool to call next.",
"type": [
"string",
"null"
]
},
"why": {
"description": "One-line reason this follow-up tool would be useful given the current result.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"note": {
"description": "A caveat about the inputs or data behind this call, not an error — e.g. the supplied lock-expiration date is already in the past, so the economics assume a fresh re-lock at current market. Present only when such a caveat applies; carry it into any answer.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.",
"type": [
"string",
"null"
]
},
"rationale": {
"description": "Plain-English explanation of why this recommendation was reached; safe to quote to the user as the reasoning.",
"type": [
"string",
"null"
]
},
"recommendation": {
"description": "The suggested move, e.g. 'exercise_float_down', 'hold_lock', or 'relock'.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
},
"window": {
"description": "Lookback period used for the comparison, expressed as a short duration string such as '4w', '90d', or '180d'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Score an array of inline financing scenarios in one stateless call; returns ranked decisions and top offers per item — no persisted cohorts, no per-borrower HTTP loops.",
"inputSchema": {
"properties": {
"credit_score": {
"description": "Optional default credit score applied to scenarios lacking one",
"type": "number"
},
"max_providers": {
"description": "Top-N offers returned per scenario (default 3)",
"type": "number"
},
"scenarios": {
"description": "Inline scenarios to score in one stateless call (no persisted cohorts).",
"items": {
"properties": {
"amount": {
"type": "number"
},
"credit_score": {
"description": "Overrides top-level credit_score",
"type": "number"
},
"down_payment_percent": {
"type": "number"
},
"id": {
"description": "Caller correlation id, echoed back",
"type": "string"
},
"intent": {
"enum": [
"purchase",
"refinance",
"cash_out",
"balance_transfer",
"new_credit"
],
"type": "string"
},
"product_type": {
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"personal_loan",
"heloc",
"credit_card",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"state": {
"description": "Overrides top-level state",
"type": "string"
},
"term_months": {
"type": "number"
}
},
"required": [
"product_type",
"intent",
"amount"
],
"type": "object"
},
"maxItems": 25,
"minItems": 1,
"type": "array"
},
"state": {
"description": "Optional 2-letter default state applied to scenarios lacking one",
"type": "string"
}
},
"required": [
"scenarios"
],
"type": "object"
},
"name": "batch_decisions",
"outputSchema": {
"additionalProperties": true,
"properties": {
"count": {
"description": "Number of scenarios evaluated in this batch.",
"type": [
"number",
"null"
]
},
"results": {
"description": "One result per scenario, ordered by rank rather than by the order submitted — match them back with `id`.",
"items": {
"additionalProperties": true,
"properties": {
"best_offer": {
"description": "The single best offer for this scenario, with lender, APR and rate in percent, and monthly payment in dollars.",
"type": "object"
},
"id": {
"description": "The caller's own identifier for this scenario, used to match results back to inputs.",
"type": [
"string",
"null"
]
},
"index": {
"description": "Zero-based position of this scenario in the submitted array.",
"type": [
"number",
"null"
]
},
"offers": {
"description": "All ranked offers found for this scenario, each with rank, lender, APR, rate, and monthly payment.",
"type": "array"
},
"rank": {
"description": "Ranking of this scenario against the others in the batch, 1 = strongest opportunity.",
"type": [
"number",
"null"
]
},
"recommended_action": {
"description": "Recommended move for this scenario, e.g. 'shop_providers'.",
"type": [
"string",
"null"
]
},
"status": {
"description": "Whether the scenario resolved: 'ok' means offers were found; other values mean no usable pricing.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"totals": {
"additionalProperties": true,
"description": "Batch-level tallies across all scenarios.",
"properties": {
"scenarios_no_offer": {
"description": "How many scenarios found nothing; those results carry no pricing and should not be reported as expensive.",
"type": [
"number",
"null"
]
},
"scenarios_with_offer": {
"description": "How many scenarios found at least one live offer.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
"type": "object"
}
},
{
"description": "Build a year-by-year amortization / payoff schedule for a loan: total lifetime interest, principal/interest split per period, and a what-if extra-payment accelerator showing months saved and interest saved. Resolves the market rate from real credit-union offers when no rate is provided.",
"inputSchema": {
"properties": {
"credit_score": {
"description": "Optional borrower credit score used to qualify the market offer.",
"type": "number"
},
"extra_monthly_payment": {
"description": "Optional extra principal paid each month. Drives the payoff-acceleration analysis (months saved, interest saved).",
"type": "number"
},
"extra_one_time_payment": {
"description": "Optional one-time extra principal payment.",
"type": "number"
},
"loan_amount": {
"description": "Loan principal in dollars (required, > 0).",
"type": "number"
},
"product_type": {
"description": "Loan product; required only when rate is omitted. Default mortgage.",
"enum": [
"mortgage",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"rate": {
"description": "Annual interest rate as a percent (e.g. 6.5). If omitted, the market rate is resolved from real credit-union offers via the decision engine.",
"type": "number"
},
"schedule_granularity": {
"description": "Schedule row granularity. Default year.",
"enum": [
"year",
"month"
],
"type": "string"
},
"state": {
"description": "2-letter US state code; required only when rate is omitted (for market-rate lookup).",
"type": "string"
},
"term_months": {
"description": "Loan term in months, e.g. 360 or 180 (required).",
"type": "number"
}
},
"required": [
"loan_amount",
"term_months"
],
"type": "object"
},
"name": "build_amortization_schedule",
"outputSchema": {
"additionalProperties": true,
"properties": {
"assumed_defaults": {
"additionalProperties": true,
"description": "Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.",
"properties": {
"extra_monthly_payment": {
"description": "Extra monthly principal in dollars assumed when the caller did not specify it.",
"type": [
"number",
"null"
]
},
"schedule_granularity": {
"description": "Row granularity used, 'year' or 'month'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"baseline": {
"additionalProperties": true,
"description": "The loan as scheduled, with no extra payments.",
"properties": {
"payoff_months": {
"description": "Months to payoff on the scheduled payment, equal to the term.",
"type": [
"number",
"null"
]
},
"total_interest": {
"description": "Total interest in dollars over the full term with scheduled payments only.",
"type": [
"number",
"null"
]
},
"total_paid": {
"description": "Principal plus interest in dollars over the full term.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"loan_amount": {
"description": "Principal in dollars the schedule amortizes.",
"type": [
"number",
"null"
]
},
"market_lender": {
"description": "Credit union whose published rate was used when the rate came from market data. Null when the caller supplied the rate."
},
"monthly_payment": {
"description": "Scheduled principal-and-interest payment in dollars, excluding any extra payment.",
"type": [
"number",
"null"
]
},
"next_actions": {
"description": "Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.",
"items": {
"additionalProperties": true,
"properties": {
"tool": {
"description": "Name of the follow-up MCP tool to call next.",
"type": [
"string",
"null"
]
},
"why": {
"description": "One-line reason this follow-up tool would be useful given the current result.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"rate": {
"description": "Annual note rate in percent used for the schedule.",
"type": [
"number",
"null"
]
},
"rate_source": {
"description": "Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.",
"type": [
"string",
"null"
]
},
"reason": {
"description": "Why no schedule could be built, present only in that case — e.g. no qualifying market offer for that product and state, in which case supply an explicit rate and retry.",
"type": [
"string",
"null"
]
},
"schedule": {
"description": "The amortization rows at the requested granularity (per month or per year).",
"items": {
"additionalProperties": true,
"properties": {
"ending_balance": {
"description": "Loan balance in dollars remaining at the end of this period.",
"type": [
"number",
"null"
]
},
"extra_principal_paid": {
"description": "Additional principal in dollars paid during this period beyond the scheduled payment.",
"type": [
"number",
"null"
]
},
"interest_paid": {
"description": "Interest in dollars paid during this period.",
"type": [
"number",
"null"
]
},
"label": {
"description": "Human-readable label for the row, e.g. 'Year 1'.",
"type": [
"string",
"null"
]
},
"period": {
"description": "Sequential index of this row: month number or year number depending on the granularity requested.",
"type": [
"number",
"null"
]
},
"principal_paid": {
"description": "Scheduled principal in dollars retired during this period; it grows every period as interest falls.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"term_months": {
"description": "Loan term in months (360 = 30 years, 180 = 15 years, 60 = 5 years).",
"type": [
"number",
"null"
]
},
"with_extra": {
"additionalProperties": true,
"description": "The same loan with the caller's extra monthly principal payment applied.",
"properties": {
"interest_saved": {
"description": "Interest in dollars avoided by the extra payment — the headline benefit.",
"type": [
"number",
"null"
]
},
"monthly_payment_total": {
"description": "Total monthly outlay in dollars including the extra principal.",
"type": [
"number",
"null"
]
},
"months_saved": {
"description": "Months knocked off the payoff by the extra payment.",
"type": [
"number",
"null"
]
},
"payoff_months": {
"description": "Months to payoff with the extra payment, shorter than the scheduled term.",
"type": [
"number",
"null"
]
},
"total_interest": {
"description": "Total interest in dollars paid when the extra payment is made every month.",
"type": [
"number",
"null"
]
},
"total_paid": {
"description": "Principal plus interest in dollars under the accelerated schedule.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
"type": "object"
}
},
{
"description": "Run compliance/suitability guardrails over a financing scenario and an optional recommendation. Returns flags (red/yellow with code + message) for things like DTI strain, long auto terms with negative-equity risk, possible balloon payments, and stale market data, plus generic disclaimers and an overall verdict (ok/caution/stop). Use this before presenting a rate recommendation to a borrower.",
"inputSchema": {
"properties": {
"recommendation": {
"description": "Optional recommended offer to evaluate.",
"properties": {
"apr": {
"description": "Recommended APR as a percentage.",
"type": "number"
},
"monthly_payment": {
"description": "Recommended monthly payment in dollars.",
"type": "number"
},
"rate": {
"description": "Recommended rate as a percentage.",
"type": "number"
}
},
"type": "object"
},
"scenario": {
"description": "The borrower scenario.",
"properties": {
"amount": {
"description": "Loan amount in dollars.",
"type": "number"
},
"credit_score": {
"description": "Borrower's credit score (300-850).",
"type": "number"
},
"intent": {
"description": "The loan intent (purchase/refinance/etc.).",
"type": "string"
},
"monthly_debt": {
"description": "Borrower's existing monthly debt payments in dollars.",
"type": "number"
},
"monthly_income": {
"description": "Borrower's gross monthly income in dollars.",
"type": "number"
},
"product_type": {
"description": "Type of financing product.",
"enum": [
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"mortgage",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"state": {
"description": "US state code (2-letter).",
"type": "string"
},
"term_months": {
"description": "Loan term in months.",
"type": "number"
}
},
"required": [
"product_type",
"state",
"amount",
"term_months"
],
"type": "object"
}
},
"required": [
"scenario"
],
"type": "object"
},
"name": "check_advice_guardrails",
"outputSchema": {
"additionalProperties": true,
"properties": {
"disclaimers": {
"description": "Statements that must be attached to any advice built on this scenario, such as that this is not financial advice and not an offer of credit.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"flags": {
"description": "Guardrail violations found in the proposed recommendation. An empty array means nothing was tripped.",
"items": {
"additionalProperties": true,
"properties": {
"code": {
"description": "Machine-readable identifier of the rule that fired, e.g. 'dti_exceeds_50'.",
"type": [
"string",
"null"
]
},
"level": {
"description": "Severity of the flag: 'red' blocks the recommendation, lower levels warn without stopping it.",
"type": [
"string",
"null"
]
},
"message": {
"description": "Plain-English explanation of the problem and the threshold that was breached; quote this rather than paraphrasing it.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"overall": {
"description": "Aggregate verdict on the proposed recommendation: 'stop' when a red flag blocks it, otherwise a pass or caution outcome.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "LENDER-side 'is my offer competitive' check — input your OWN published rate for a state+product, get the market percentile, bps vs the state median, and a leading/competitive/overpriced verdict. This is for a loan officer or credit union benchmarking their published pricing against the live market distribution. Do NOT use this for a consumer's quote: if the user is a BORROWER asking whether a rate they were offered is fair, use rate_sanity_check instead.",
"inputSchema": {
"properties": {
"apr": {
"description": "The lender's published APR. Optional — falls back to rate.",
"type": "number"
},
"product": {
"description": "Mortgage product the lender publishes. Required.",
"enum": [
"30yr_fixed",
"15yr_fixed"
],
"type": "string"
},
"rate": {
"description": "The lender's OWN published note rate as a percentage (e.g. 6.49). Required.",
"type": "number"
},
"state": {
"description": "US state code (2-letter, e.g. CA, TX). Required.",
"type": "string"
}
},
"required": [
"state",
"product",
"rate"
],
"type": "object"
},
"name": "check_competitive_position",
"outputSchema": {
"additionalProperties": true,
"properties": {
"bps_vs_median": {
"description": "Distance from the market median in basis points (-4 = 4 basis points below, i.e. better than median).",
"type": [
"number",
"null"
]
},
"market": {
"additionalProperties": true,
"description": "Distribution of live offers this position was measured against.",
"properties": {
"as_of": {
"description": "UTC timestamp of the newest rate in the market comparison set.",
"type": [
"string",
"null"
]
},
"count": {
"description": "Number of live published offers the min/median/max were computed from. Small counts make the median unreliable.",
"type": [
"number",
"null"
]
},
"max": {
"description": "Highest APR, in percent, among the live offers in this segment.",
"type": [
"number",
"null"
]
},
"median": {
"description": "Median APR, in percent, across the live offers in this segment; the fairest single number to describe 'the market'.",
"type": [
"number",
"null"
]
},
"min": {
"description": "Lowest APR, in percent, among the live offers in this market segment — the single best published deal, not a typical one.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"note": {
"description": "Ready-to-quote sentence stating how this offer ranks against live offers and by how many basis points.",
"type": [
"string",
"null"
]
},
"percentile": {
"description": "Where this offer sits in the market distribution, 0-100, lower being cheaper. 43 means about 43% of live offers are cheaper than it.",
"type": [
"number",
"null"
]
},
"product": {
"description": "Product key the offer was compared against, e.g. '30yr_fixed'.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
},
"verdict": {
"description": "Qualitative placement of the offer against the market, e.g. 'competitive', 'above_market', 'market_leading'.",
"type": [
"string",
"null"
]
},
"your_offer": {
"additionalProperties": true,
"description": "The rate and APR the caller supplied for comparison.",
"properties": {
"apr": {
"description": "The supplied APR in percent, including fees; this is what the percentile is computed on.",
"type": [
"number",
"null"
]
},
"rate": {
"description": "The supplied note rate in percent, excluding fees.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
"type": "object"
}
},
{
"description": "`relative_memberships` carries confirmed current/deceased relative membership scoped to one exact target credit union; one institution is never reused for another. Check whether a user can JOIN specific credit unions (field-of-membership eligibility). Batch-friendly: pass 1-50 credit_union_ids (from get_financing_decision offers, list_credit_unions, or get_credit_union) plus whatever is known about the user (home, worksite, and payroll geography are independent facts; employer, occupation, military_status, school plus school_relationship, and worship are also supported). City facts require their same-role state or a recognized same-role ZIP that uniquely identifies one state, and are accepted only when the closed Census gazetteer resolves them. Returns one row for every requested credit union. Positive outcomes include open_to_anyone, likely_eligible, eligible_via_employer, and eligible_via_military. A school name alone is not a positive signal: school_relationship is required to affirm a typed student, alumni, or school-employee path. Only a graph carrying exact active-publication lineage governs the top compatibility verdict; a publication-less shadow graph remains diagnostic and cannot replace the flat result. A non-match is returned as unknown, with `unknown_reason: fom_completeness_unaffirmed` when the published field-of-membership corpus is not attested complete. The legacy `geo_mismatch` enum value is reserved for wire compatibility and is not emitted by this MCP boundary without a future typed closed-world attestation. Verdicts are guidance based on each credit union's published membership criteria; the final membership determination is always the institution's. Non-matches carry `missing_facts` for the named institutions: the exact question to ask next, the `fact_field` an answer populates, and the institution's own words. A check that returns unknown for all of them and a question for each is a SUCCESSFUL call, not a failure — ask the questions, merge the answers into the same request, and call again. Home geography accepts both the original `zip`/`state`/`county` names and the `home_zip`/`home_state`/`home_county` aliases emitted by `missing_facts`; do not send conflicting values in both forms. Fact fields, in full — supply every one you know: `home_zip`, `home_state`, `home_county`, `home_city`; `work_zip`, `work_state`, `work_county`, `work_city`; `payroll_zip`, `payroll_state`, `payroll_county`, `payroll_city` (payroll can differ from the worksite and is a separate door); `property_zip`, `property_state`, `property_county`, `property_city` (where they OWN property — never inferred from where they live, and an absentee owner qualifies); `facility_zip`, `facility_state`, `facility_county`, `facility_city` (where their business maintains a location); `occupation`; `employer`; `school` plus `school_relationship` (student/alumni/employee — a school name without a relationship affirms nothing); `military_status` plus `military_service_state` (state National Guard doors need the state); `worship`; `family_relation` plus `relative_employers`, `relative_schools`, `relative_associations` (a great many people qualify only through a relative — ask); `applicant_kind` (person/trust/organization/partnership/corporation — some charters admit entities, and a person is never rejected by an entity-only door, only left unknown); and `asserted_org_qualifiers` (narrowings the person asserts about themselves, e.g. \"assigned as a recruiter in Arkansas\").",
"inputSchema": {
"properties": {
"applicant_kind": {
"description": "What the applicant IS. Some charters admit entities as well as people. Absent means a natural person; a person is never rejected by an entity-only door, only left unknown.",
"enum": [
"person",
"trust",
"organization",
"partnership",
"corporation",
"other_legal_entity"
],
"type": "string"
},
"asserted_org_qualifiers": {
"description": "Narrowings the user asserts about themselves, quoted back from a missing_facts question (e.g. \"assigned as Recruiters or ROTC Instructors within the State of Arkansas\"). Absence caps a narrowed door rather than closing it.",
"items": {
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"association_org_ids": {
"description": "Canonical association ids selected through resolve_eligibility_entities; each is type- and publication-revalidated.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"county": {
"description": "User's home county for residence matching. Original name; home_county is an equivalent merge-and-retry alias.",
"type": "string"
},
"credit_union_ids": {
"description": "Credit union ids to check (1-50), e.g. from get_financing_decision offers or list_credit_unions. Required.",
"items": {
"type": "string"
},
"maxItems": 50,
"minItems": 1,
"type": "array"
},
"employer": {
"description": "User's employer, matched against credit union employer/SEG membership lists.",
"type": "string"
},
"employer_org_ids": {
"description": "Canonical employer ids selected through resolve_eligibility_entities. The API revalidates entity type and active-publication authority before use.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"facility_city": {
"description": "Census-recognized city where the user's business maintains a location. Requires facility_state or a recognized facility_zip that uniquely identifies one state.",
"type": "string"
},
"facility_county": {
"description": "County where the user's business maintains a location.",
"type": "string"
},
"facility_state": {
"description": "State where the user's business maintains a location.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"facility_zip": {
"description": "ZIP where the user's business maintains a location. Distinct from the worksite ZIP.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"family_relation": {
"description": "How the user relates to a RELATIVE whose own affiliations may qualify them (e.g. 'spouse', 'child', 'immediate family'). Required alongside relative_employers/relative_schools/relative_associations — without it there is nobody for those organizations to belong to. Many SEG lists read 'Employees of the following companies AND THEIR IMMEDIATE FAMILIES are eligible'; this is how that door is answered.",
"type": "string"
},
"home_city": {
"description": "User's Census-recognized home city. Requires state or a recognized zip that uniquely identifies one state; unresolved labels are rejected rather than guessed.",
"type": "string"
},
"home_county": {
"description": "Alias for county, accepted so missing_facts can be merged into this same tool request. Conflicting duplicate forms are rejected.",
"type": "string"
},
"home_state": {
"description": "Alias for state, accepted so missing_facts can be merged into this same tool request. Conflicting duplicate forms are rejected.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"home_zip": {
"description": "Alias for zip, accepted so missing_facts can be merged into this same tool request. It must agree with state/home_state when either is supplied; conflicting duplicate forms are rejected.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"military_service_state": {
"description": "The state the user serves, or served, in. State National Guard doors (\"Oklahoma National Guard\") need this; without it such a door reads unknown.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"military_status": {
"description": "User's military affiliation, matched against military field-of-membership (yields eligible_via_military).",
"enum": [
"active_duty",
"veteran",
"reservist",
"dod_civilian",
"military_family"
],
"type": "string"
},
"occupation": {
"description": "User's occupation, matched against trade/industry/profession (TIP) charters.",
"type": "string"
},
"payroll_city": {
"description": "Census-recognized payroll city. Requires payroll_state or a recognized payroll_zip that uniquely identifies one state.",
"type": "string"
},
"payroll_county": {
"description": "County from which the user's employer issues payroll. This is distinct from work_county.",
"type": "string"
},
"payroll_state": {
"description": "Valid state code from which the user's employer issues payroll. This is distinct from work_state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"payroll_zip": {
"description": "ZIP from which the user's employer issues payroll. This is distinct from the worksite ZIP.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"property_city": {
"description": "Census-recognized city where the user owns real property. Requires property_state or a recognized property_zip that uniquely identifies one state.",
"type": "string"
},
"property_county": {
"description": "County where the user owns real property. Distinct from home_county.",
"type": "string"
},
"property_state": {
"description": "State where the user owns real property. Distinct from home_state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"property_zip": {
"description": "ZIP where the user OWNS REAL PROPERTY. A door of its own — never inferred from where they live, and an absentee owner qualifies.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"relative_association_org_ids": {
"description": "Canonical association ids for the relative named by family_relation, never for the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_associations": {
"description": "Associations the RELATIVE named by family_relation belongs to. Optional; same unknown-by-default contract as relative_employers.",
"items": {
"type": "string"
},
"type": "array"
},
"relative_employer_org_ids": {
"description": "Canonical employer ids for the relative named by family_relation, never for the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_employers": {
"description": "Employers of the RELATIVE named by family_relation (not the user's own employer). Optional; omitting it leaves compound family doors undecided (unknown), never negative.",
"items": {
"type": "string"
},
"type": "array"
},
"relative_memberships": {
"description": "Confirmed relative memberships scoped to one exact credit union. A membership at one institution is never reused for another; omit unconfirmed memberships and the corresponding family door remains unknown.",
"items": {
"additionalProperties": false,
"properties": {
"credit_union_id": {
"description": "The exact target credit union id.",
"type": "string"
},
"relation": {
"description": "The relative's relationship to the applicant.",
"type": "string"
},
"status": {
"enum": [
"current_member",
"deceased_member"
],
"type": "string"
}
},
"required": [
"credit_union_id",
"relation",
"status"
],
"type": "object"
},
"maxItems": 50,
"type": "array"
},
"relative_school_org_ids": {
"description": "Canonical school ids for the relative named by family_relation, never for the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_schools": {
"description": "Schools the RELATIVE named by family_relation attends. Optional; same unknown-by-default contract as relative_employers.",
"items": {
"type": "string"
},
"type": "array"
},
"school": {
"description": "User's school/college/university. Supply school_relationship too; the school name alone does not affirm eligibility.",
"type": "string"
},
"school_org_ids": {
"description": "Canonical school ids selected through resolve_eligibility_entities; never populate these from prose extraction.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"school_relationship": {
"description": "How the user relates to the named school. Required with school to affirm a typed student, alumni, or school-employee path.",
"enum": [
"student",
"alumni",
"employee"
],
"type": "string"
},
"state": {
"description": "User's valid 50-state/DC code for geographic field-of-membership matching. Lowercase is accepted and normalized.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"work_city": {
"description": "Census-recognized city where the user works. Requires work_state or a recognized work_zip that uniquely identifies one state.",
"type": "string"
},
"work_county": {
"description": "County where the user works, for work-area membership matching.",
"type": "string"
},
"work_state": {
"description": "Valid 50-state/DC code where the user works, for work-area membership matching. Lowercase is accepted and normalized.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"work_zip": {
"description": "User's US 5-digit work ZIP or ZIP+4. Resolves to a work county server-side; when work_state is supplied, the crosswalk must agree with it.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"worship": {
"description": "User's place of worship, matched against worship-org affinity lists (yields likely_eligible).",
"type": "string"
},
"worship_org_ids": {
"description": "Canonical worship-organization ids selected through resolve_eligibility_entities.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"zip": {
"description": "User's US 5-digit ZIP or ZIP+4. Resolves to a county server-side; when state is supplied, the ZIP crosswalk must agree with it.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
}
},
"required": [
"credit_union_ids"
],
"type": "object"
},
"name": "check_membership_eligibility",
"outputSchema": {
"additionalProperties": true,
"properties": {
"checked": {
"description": "Number of credit unions evaluated in this call, matching the length of `verdicts`.",
"type": [
"number",
"null"
]
},
"engine": {
"description": "`eligibility_publication_v1` when at least one verdict was decided from an exact active publication; `legacy+graph_shadow` for compatibility output.",
"type": [
"string",
"null"
]
},
"note": {
"description": "Required caveat that eligibility is guidance from published criteria and the credit union makes the final decision.",
"type": [
"string",
"null"
]
},
"summary": {
"description": "One-sentence plain-English summary of this result, safe to quote directly to the user.",
"type": [
"string",
"null"
]
},
"verdicts": {
"description": "One eligibility assessment per credit union requested, in the order supplied.",
"items": {
"additionalProperties": true,
"properties": {
"confidence": {
"description": "Confidence in the authoritative graph verdict when exact publication lineage is present; otherwise the legacy record confidence. Forced to 0 when publication authority is unavailable. From 0 to 1.",
"type": [
"number",
"null"
]
},
"credit_union_id": {
"description": "Internal composite identifier 'name|city|STATE' of the credit union assessed.",
"type": [
"string",
"null"
]
},
"details": {
"description": "Relative REST API path for the full eligibility record; an API reference, not a page to show the user.",
"type": [
"string",
"null"
]
},
"eligibility_type": {
"description": "`graph` when a graph carrying exact active-publication lineage is authoritative; otherwise the legacy charter shape such as community, multi, or unknown.",
"type": [
"string",
"null"
]
},
"evidence_url": {
"description": "Legacy record source page when no published graph authority is present. Omitted beside an authoritative published graph, and when publication authority is unavailable, because a flat URL may back an unrelated or stale path.",
"type": [
"string",
"null"
]
},
"graph": {
"additionalProperties": true,
"description": "Deterministic eligibility-graph verdict. Its optional publication binds an authoritative active generation; without publication it is a non-authoritative compatibility shadow. Current unattested negatives are normalized to open-world `unknown` without removing the evaluated credit union.",
"properties": {
"confidence": {
"description": "Confidence in the graph verdict, from 0 to 1.",
"maximum": 1,
"minimum": 0,
"type": "number"
},
"explain": {
"description": "Deterministic human-readable explanation of the verdict.",
"type": "string"
},
"paths": {
"description": "Structured membership-path evaluations. Unattested negatives and alternate paths that did not produce the overall verdict are retained only as actionless `unknown` diagnostics with neutral wording.",
"items": {
"additionalProperties": true,
"properties": {
"conditional_on": {
"additionalProperties": true,
"description": "Action that unlocks a proven conditional path. Present only when both the graph verdict and this path are conditionally_eligible.",
"type": "object"
},
"conditions_matched": {
"description": "Conditions proven on this path. A pending conditional action is never labelled matched; the array resets to empty when a failed or non-winning path is neutralized.",
"items": {
"type": "string"
},
"type": "array"
},
"conditions_unknown": {
"description": "Conditions still unresolved on a non-negative path. Omitted when a failed path is neutralized.",
"items": {
"type": "string"
},
"type": "array"
},
"reason": {
"description": "Neutral deterministic explanation of the path outcome.",
"type": [
"string",
"null"
]
},
"status": {
"description": "Path outcome; reserved `ineligible` instances are normalized to `unknown` without a typed closed-world attestation.",
"type": [
"string",
"null"
]
},
"unknown_reason": {
"description": "Machine-readable open-world reason, including `fom_completeness_unaffirmed`.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"publication": {
"description": "Exact immutable active publication evaluated for this verdict.",
"properties": {
"activated_at": {
"description": "When this publication became serving authority.",
"format": "date-time",
"type": "string"
},
"proposal_coverage": {
"additionalProperties": true,
"description": "Counts of source-page model proposals that were verified, published, or withheld; not a closed-world FOM attestation.",
"type": "object"
},
"publication_id": {
"description": "Database identifier of the active publication.",
"type": "integer"
},
"ruleset_sha256": {
"description": "SHA-256 digest of the publication's complete ordered rule set.",
"pattern": "^[0-9a-f]{64}$",
"type": "string"
}
},
"type": "object"
},
"status": {
"description": "Five-value wire vocabulary. `ineligible` is reserved for compatibility and is not emitted by MCP without a future typed closed-world attestation.",
"enum": [
"eligible",
"conditionally_eligible",
"possibly_eligible",
"ineligible",
"unknown"
],
"type": "string"
},
"unknown_reason": {
"description": "Machine-readable reason the supplied facts or corpus could not support a positive decision.",
"type": "string"
}
},
"type": "object"
},
"matched_rule": {
"description": "The specific flat rule that produced a legacy verdict. Omitted when an exact published graph is authoritative because graph paths carry the bound match provenance.",
"type": "object"
},
"record_confidence": {
"description": "Aligned to authoritative graph confidence when exact publication lineage is present; otherwise confidence in the underlying legacy eligibility record. Forced to 0 when publication authority is unavailable. From 0 to 1.",
"type": [
"number",
"null"
]
},
"status": {
"description": "Machine-readable compatibility outcome. Only a graph carrying exact active-publication lineage is authoritative and conservatively projected here; a publication-less shadow graph cannot replace the flat result. `geo_mismatch` remains reserved and current unattested instances become `unknown`.",
"type": [
"string",
"null"
]
},
"unknown_reason": {
"description": "Machine-readable reason for `unknown`; `fom_completeness_unaffirmed` means no closed-world membership-corpus attestation exists.",
"type": [
"string",
"null"
]
},
"verdict": {
"description": "Full user-facing sentence combining the outcome and the reason; the best single field to quote.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "Compare baseline and candidate confirmed person facts across the same 1-19 explicit products. Both catalogs use one pinned immutable eligibility graph snapshot; rate rows retain independent evidence and as_of. Returns access, membership-path, and like-for-like published-price basis-point deltas: APY for deposits, APR for lending when both sides publish APR, otherwise nominal rate only when both sides publish nominal rate. It never mixes APR and nominal rate. Never describe missing access as denial or infer savings, underwriting, approval, or final terms.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"baseline_person": {
"additionalProperties": false,
"description": "Explicit caller-supplied person facts. Unknown facts stay absent; do not infer them.",
"properties": {
"applicant_kind": {
"description": "What the applicant is; absence means a natural person.",
"enum": [
"person",
"trust",
"organization",
"partnership",
"corporation",
"other_legal_entity"
],
"type": "string"
},
"asserted_org_qualifiers": {
"description": "Narrow conditions the person explicitly asserted; never infer them.",
"items": {
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"association_org_ids": {
"description": "Explicit association ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"associations": {
"description": "Associations the person already belongs to.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"employer": {
"description": "Person-supplied employer name; use employer_org_ids after authoritative resolution.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"employer_org_ids": {
"description": "Explicit employer ids returned by resolve_eligibility_entities; rates-api revalidates type and active-publication authority.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"facility_city": {
"description": "Census-recognized facility city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_county": {
"description": "County where the applicant organization maintains a facility.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_state": {
"description": "Valid 50-state/DC facility state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"facility_zip": {
"description": "ZIP where the applicant organization maintains a facility.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"family_relation": {
"description": "Relationship to the relative whose affiliations are supplied.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"home_city": {
"description": "Census-recognized home city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_county": {
"description": "Home county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_state": {
"description": "Valid 50-state/DC home state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"home_zip": {
"description": "Home ZIP; never inferred from another role.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"military_service_state": {
"description": "State tied to a state-scoped military affiliation.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"military_status": {
"description": "Person-supplied military affiliation.",
"enum": [
"active_duty",
"veteran",
"reservist",
"dod_civilian",
"military_family"
],
"type": "string"
},
"occupation": {
"description": "Person-supplied occupation.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_city": {
"description": "Census-recognized payroll-origin city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_county": {
"description": "Payroll-origin county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_state": {
"description": "Valid 50-state/DC payroll-origin state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"payroll_zip": {
"description": "Payroll-origin ZIP, separate from the worksite.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"property_city": {
"description": "Census-recognized city where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_county": {
"description": "County where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_state": {
"description": "Valid 50-state/DC property state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"property_zip": {
"description": "ZIP where the person owns real property; never inferred from home.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"relative_association_org_ids": {
"description": "Canonical association ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_associations": {
"description": "Associations of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_employer_org_ids": {
"description": "Canonical employer ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_employers": {
"description": "Employers of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_memberships": {
"description": "Confirmed relative memberships, each scoped to one exact institution.",
"items": {
"additionalProperties": false,
"properties": {
"credit_union_id": {
"description": "Exact credit-union id.",
"maxLength": 300,
"minLength": 1,
"type": "string"
},
"relation": {
"description": "Relative relationship.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"status": {
"description": "Confirmed membership status.",
"enum": [
"current_member",
"deceased_member"
],
"type": "string"
}
},
"required": [
"credit_union_id",
"relation",
"status"
],
"type": "object"
},
"maxItems": 50,
"type": "array"
},
"relative_school_org_ids": {
"description": "Canonical school ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_schools": {
"description": "Schools of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"school": {
"description": "Person-supplied school name; school_relationship is needed for a typed positive path.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"school_org_ids": {
"description": "Explicit school ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"school_relationship": {
"description": "How the person relates to the supplied school.",
"enum": [
"student",
"alumni",
"employee"
],
"type": "string"
},
"willing_to_join_association": {
"description": "Whether documented joinable-association actions may be considered.",
"type": "boolean"
},
"work_city": {
"description": "Census-recognized worksite city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_county": {
"description": "Worksite county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_state": {
"description": "Valid 50-state/DC worksite state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"work_zip": {
"description": "Worksite ZIP, separate from home and payroll.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"worship": {
"description": "Person-supplied place of worship.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"worship_org_ids": {
"description": "Explicit worship-organization ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
}
},
"type": "object"
},
"candidate_person": {
"additionalProperties": false,
"description": "Explicit caller-supplied person facts. Unknown facts stay absent; do not infer them.",
"properties": {
"applicant_kind": {
"description": "What the applicant is; absence means a natural person.",
"enum": [
"person",
"trust",
"organization",
"partnership",
"corporation",
"other_legal_entity"
],
"type": "string"
},
"asserted_org_qualifiers": {
"description": "Narrow conditions the person explicitly asserted; never infer them.",
"items": {
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"association_org_ids": {
"description": "Explicit association ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"associations": {
"description": "Associations the person already belongs to.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"employer": {
"description": "Person-supplied employer name; use employer_org_ids after authoritative resolution.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"employer_org_ids": {
"description": "Explicit employer ids returned by resolve_eligibility_entities; rates-api revalidates type and active-publication authority.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"facility_city": {
"description": "Census-recognized facility city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_county": {
"description": "County where the applicant organization maintains a facility.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_state": {
"description": "Valid 50-state/DC facility state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"facility_zip": {
"description": "ZIP where the applicant organization maintains a facility.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"family_relation": {
"description": "Relationship to the relative whose affiliations are supplied.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"home_city": {
"description": "Census-recognized home city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_county": {
"description": "Home county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_state": {
"description": "Valid 50-state/DC home state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"home_zip": {
"description": "Home ZIP; never inferred from another role.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"military_service_state": {
"description": "State tied to a state-scoped military affiliation.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"military_status": {
"description": "Person-supplied military affiliation.",
"enum": [
"active_duty",
"veteran",
"reservist",
"dod_civilian",
"military_family"
],
"type": "string"
},
"occupation": {
"description": "Person-supplied occupation.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_city": {
"description": "Census-recognized payroll-origin city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_county": {
"description": "Payroll-origin county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_state": {
"description": "Valid 50-state/DC payroll-origin state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"payroll_zip": {
"description": "Payroll-origin ZIP, separate from the worksite.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"property_city": {
"description": "Census-recognized city where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_county": {
"description": "County where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_state": {
"description": "Valid 50-state/DC property state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"property_zip": {
"description": "ZIP where the person owns real property; never inferred from home.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"relative_association_org_ids": {
"description": "Canonical association ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_associations": {
"description": "Associations of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_employer_org_ids": {
"description": "Canonical employer ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_employers": {
"description": "Employers of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_memberships": {
"description": "Confirmed relative memberships, each scoped to one exact institution.",
"items": {
"additionalProperties": false,
"properties": {
"credit_union_id": {
"description": "Exact credit-union id.",
"maxLength": 300,
"minLength": 1,
"type": "string"
},
"relation": {
"description": "Relative relationship.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"status": {
"description": "Confirmed membership status.",
"enum": [
"current_member",
"deceased_member"
],
"type": "string"
}
},
"required": [
"credit_union_id",
"relation",
"status"
],
"type": "object"
},
"maxItems": 50,
"type": "array"
},
"relative_school_org_ids": {
"description": "Canonical school ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_schools": {
"description": "Schools of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"school": {
"description": "Person-supplied school name; school_relationship is needed for a typed positive path.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"school_org_ids": {
"description": "Explicit school ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"school_relationship": {
"description": "How the person relates to the supplied school.",
"enum": [
"student",
"alumni",
"employee"
],
"type": "string"
},
"willing_to_join_association": {
"description": "Whether documented joinable-association actions may be considered.",
"type": "boolean"
},
"work_city": {
"description": "Census-recognized worksite city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_county": {
"description": "Worksite county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_state": {
"description": "Valid 50-state/DC worksite state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"work_zip": {
"description": "Worksite ZIP, separate from home and payroll.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"worship": {
"description": "Person-supplied place of worship.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"worship_org_ids": {
"description": "Explicit worship-organization ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
}
},
"type": "object"
},
"limit_per_product": {
"maximum": 10,
"minimum": 1,
"type": "integer"
},
"products": {
"items": {
"additionalProperties": false,
"description": "Exact product request used for both eligibility-backed rate evaluation and ranking.",
"properties": {
"amount": {
"description": "Loan or credit amount in USD.",
"exclusiveMinimum": 0,
"type": "number"
},
"audience": {
"description": "Product audience.",
"enum": [
"business",
"consumer"
],
"type": "string"
},
"balance": {
"description": "Deposit balance in USD.",
"minimum": 0,
"type": "number"
},
"intent": {
"description": "Transaction intent when relevant.",
"enum": [
"purchase",
"refinance",
"cash_out",
"balance_transfer",
"new_credit"
],
"type": "string"
},
"occupancy": {
"description": "Property occupancy.",
"enum": [
"primary",
"secondary",
"investment"
],
"type": "string"
},
"product_type": {
"description": "Exact product family.",
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan",
"credit_card",
"savings",
"cd",
"share_certificate",
"money_market",
"ira_cd",
"ira",
"share_savings"
],
"type": "string"
},
"term_months": {
"description": "Requested term in months.",
"maximum": 600,
"minimum": 1,
"type": "integer"
},
"vehicle_condition": {
"description": "Vehicle condition.",
"enum": [
"new",
"used",
"certified_pre_owned",
"any"
],
"type": "string"
}
},
"required": [
"product_type"
],
"type": "object"
},
"maxItems": 19,
"minItems": 1,
"type": "array",
"uniqueItems": true
},
"total_limit": {
"maximum": 100,
"minimum": 1,
"type": "integer"
}
},
"required": [
"baseline_person",
"candidate_person",
"products"
],
"type": "object"
},
"name": "compare_personal_access_catalogs",
"outputSchema": {
"additionalProperties": true,
"description": "Two full access catalogs and evidence-linked changes under one immutable eligibility snapshot.",
"properties": {
"baseline": {
"additionalProperties": true,
"description": "Full baseline access catalog.",
"type": "object"
},
"candidate": {
"additionalProperties": true,
"description": "Full candidate access catalog.",
"type": "object"
},
"comparison_version": {
"description": "Stable comparison response contract version.",
"type": [
"string",
"null"
]
},
"deltas": {
"additionalProperties": true,
"description": "Per-product and portfolio reachability, membership-path, and published-price deltas. Per-product and portfolio reachable_now_counts contain exact baseline, candidate, and net product-offer-row counts; identity churn remains returned-detail scoped.",
"properties": {
"completeness": {
"additionalProperties": true,
"description": "Returned-detail identity-delta completeness disclosure.",
"type": "object"
},
"portfolio": {
"additionalProperties": true,
"description": "Portfolio totals, including exact reachable_now_counts in product-offer rows.",
"type": "object"
},
"products": {
"description": "Selector-aligned exact count and cap-scoped identity deltas.",
"items": {
"additionalProperties": true,
"properties": {
"best_published_price": {
"additionalProperties": true,
"description": "Like-for-like APY, APR, or nominal-rate comparison. APR and nominal rate are never mixed; prices and delta are null when neither measure exists on both sides.",
"type": "object"
},
"reachable_now_counts": {
"additionalProperties": true,
"description": "Exact baseline, candidate, and net reachable-now product-offer row counts.",
"type": "object"
}
},
"type": "object"
},
"type": "array"
}
},
"type": "object"
},
"disclosure": {
"description": "No savings, underwriting, approval, denial, or final-terms claim.",
"type": [
"string",
"null"
]
},
"semantics": {
"description": "Positive-evidence-only interpretation; absence is not denial.",
"type": [
"string",
"null"
]
},
"snapshot": {
"additionalProperties": true,
"description": "Pinned eligibility rules time and immutable graph generation; rates retain independent row as_of.",
"type": "object"
}
},
"type": "object"
}
},
{
"description": "Compare the best real rates across MULTIPLE lending products in a single call — e.g. show a buyer mortgage vs HELOC, or new vs used auto. Runs the decision engine for each product and returns a ranked, true-cost (APR + fees) table. Use this instead of calling get_financing_decision repeatedly. Each product returns its top offer with rate, APR, and monthly payment.",
"inputSchema": {
"properties": {
"amount": {
"description": "Loan/credit amount in dollars",
"type": "number"
},
"credit_score": {
"description": "Optional borrower credit score",
"type": "number"
},
"intent": {
"description": "purchase | refinance | cash_out | balance_transfer | new_credit",
"type": "string"
},
"product_types": {
"description": "Products to compare, e.g. [\"mortgage\",\"heloc\"]. Any of: mortgage, mortgage_arm, auto, rv, boat, motorcycle, powersports, heloc, personal_loan, credit_card, student_loan. \"mortgage\" is fixed-rate and \"mortgage_arm\" is adjustable — comparing them side by side is meaningful, but they are never blended into one ranking. Boats/RVs/motorcycles/powersports are first-class product types; auto means cars.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "US state code, e.g. \"CA\"",
"type": "string"
},
"term_months": {
"description": "Optional loan term in months",
"type": "number"
}
},
"required": [
"state",
"amount",
"product_types"
],
"type": "object"
},
"name": "compare_products",
"outputSchema": {
"additionalProperties": true,
"properties": {
"amount": {
"description": "Loan amount in dollars every product was priced at, so the rows are comparable.",
"type": [
"number",
"null"
]
},
"best_overall": {
"description": "Product type with the lowest true cost across the compared rows, e.g. 'heloc'.",
"type": [
"string",
"null"
]
},
"intent": {
"description": "Borrowing purpose the pricing assumes, e.g. 'purchase' or 'refinance'.",
"type": [
"string",
"null"
]
},
"note": {
"description": "Plain-English interpretation of the numbers above, already phrased for the user; quote it rather than re-deriving the comparison.",
"type": [
"string",
"null"
]
},
"products": {
"description": "One row per requested product type, each showing that product's single best lender.",
"items": {
"additionalProperties": true,
"properties": {
"apr": {
"description": "Best APR for this product as a percent string, including fees where published; this is what the rows were ranked on.",
"type": [
"string",
"null"
]
},
"available": {
"description": "True when live offers were found for this product; false means the row has no pricing rather than that the product is unattractive.",
"type": [
"boolean",
"null"
]
},
"best_lender": {
"description": "Credit union offering the best deal for this product type.",
"type": [
"string",
"null"
]
},
"display_name": {
"description": "Normalized name of the specific product that won this row, e.g. '15-Year Fixed'. Note that the winning term may differ between rows.",
"type": [
"string",
"null"
]
},
"monthly_payment": {
"description": "Estimated monthly payment as a formatted dollar string. Payments across rows are not like-for-like when the terms differ.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Product category for this row, e.g. 'mortgage', 'heloc'.",
"type": [
"string",
"null"
]
},
"rate": {
"description": "Best note rate for this product as a percent string, excluding fees.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Compare one baseline person-fact panel with one candidate panel against the same active eligibility snapshot and exact product request. Use this for explicit what-if questions such as adding a confirmed employer or association. Newly reachable means current positive evidence now proves a path; no_longer_reachable or absence never proves ineligibility. Supply only facts the person confirmed, preferably canonical *_org_ids from resolve_eligibility_entities. Person facts are forwarded transiently and are not stored by this tool.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"baseline_person": {
"additionalProperties": false,
"description": "Confirmed facts before the proposed change.",
"properties": {
"applicant_kind": {
"description": "What the applicant is; absence means a natural person.",
"enum": [
"person",
"trust",
"organization",
"partnership",
"corporation",
"other_legal_entity"
],
"type": "string"
},
"asserted_org_qualifiers": {
"description": "Narrow conditions the person explicitly asserted; never infer them.",
"items": {
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"association_org_ids": {
"description": "Explicit association ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"associations": {
"description": "Associations the person already belongs to.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"employer": {
"description": "Person-supplied employer name; use employer_org_ids after authoritative resolution.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"employer_org_ids": {
"description": "Explicit employer ids returned by resolve_eligibility_entities; rates-api revalidates type and active-publication authority.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"facility_city": {
"description": "Census-recognized facility city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_county": {
"description": "County where the applicant organization maintains a facility.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_state": {
"description": "Valid 50-state/DC facility state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"facility_zip": {
"description": "ZIP where the applicant organization maintains a facility.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"family_relation": {
"description": "Relationship to the relative whose affiliations are supplied.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"home_city": {
"description": "Census-recognized home city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_county": {
"description": "Home county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_state": {
"description": "Valid 50-state/DC home state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"home_zip": {
"description": "Home ZIP; never inferred from another role.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"military_service_state": {
"description": "State tied to a state-scoped military affiliation.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"military_status": {
"description": "Person-supplied military affiliation.",
"enum": [
"active_duty",
"veteran",
"reservist",
"dod_civilian",
"military_family"
],
"type": "string"
},
"occupation": {
"description": "Person-supplied occupation.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_city": {
"description": "Census-recognized payroll-origin city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_county": {
"description": "Payroll-origin county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_state": {
"description": "Valid 50-state/DC payroll-origin state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"payroll_zip": {
"description": "Payroll-origin ZIP, separate from the worksite.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"property_city": {
"description": "Census-recognized city where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_county": {
"description": "County where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_state": {
"description": "Valid 50-state/DC property state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"property_zip": {
"description": "ZIP where the person owns real property; never inferred from home.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"relative_association_org_ids": {
"description": "Canonical association ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_associations": {
"description": "Associations of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_employer_org_ids": {
"description": "Canonical employer ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_employers": {
"description": "Employers of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_memberships": {
"description": "Confirmed relative memberships, each scoped to one exact institution.",
"items": {
"additionalProperties": false,
"properties": {
"credit_union_id": {
"description": "Exact credit-union id.",
"maxLength": 300,
"minLength": 1,
"type": "string"
},
"relation": {
"description": "Relative relationship.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"status": {
"description": "Confirmed membership status.",
"enum": [
"current_member",
"deceased_member"
],
"type": "string"
}
},
"required": [
"credit_union_id",
"relation",
"status"
],
"type": "object"
},
"maxItems": 50,
"type": "array"
},
"relative_school_org_ids": {
"description": "Canonical school ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_schools": {
"description": "Schools of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"school": {
"description": "Person-supplied school name; school_relationship is needed for a typed positive path.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"school_org_ids": {
"description": "Explicit school ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"school_relationship": {
"description": "How the person relates to the supplied school.",
"enum": [
"student",
"alumni",
"employee"
],
"type": "string"
},
"willing_to_join_association": {
"description": "Whether documented joinable-association actions may be considered.",
"type": "boolean"
},
"work_city": {
"description": "Census-recognized worksite city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_county": {
"description": "Worksite county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_state": {
"description": "Valid 50-state/DC worksite state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"work_zip": {
"description": "Worksite ZIP, separate from home and payroll.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"worship": {
"description": "Person-supplied place of worship.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"worship_org_ids": {
"description": "Explicit worship-organization ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
}
},
"type": "object"
},
"candidate_person": {
"additionalProperties": false,
"description": "Confirmed facts after the proposed change.",
"properties": {
"applicant_kind": {
"description": "What the applicant is; absence means a natural person.",
"enum": [
"person",
"trust",
"organization",
"partnership",
"corporation",
"other_legal_entity"
],
"type": "string"
},
"asserted_org_qualifiers": {
"description": "Narrow conditions the person explicitly asserted; never infer them.",
"items": {
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"association_org_ids": {
"description": "Explicit association ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"associations": {
"description": "Associations the person already belongs to.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"employer": {
"description": "Person-supplied employer name; use employer_org_ids after authoritative resolution.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"employer_org_ids": {
"description": "Explicit employer ids returned by resolve_eligibility_entities; rates-api revalidates type and active-publication authority.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"facility_city": {
"description": "Census-recognized facility city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_county": {
"description": "County where the applicant organization maintains a facility.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_state": {
"description": "Valid 50-state/DC facility state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"facility_zip": {
"description": "ZIP where the applicant organization maintains a facility.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"family_relation": {
"description": "Relationship to the relative whose affiliations are supplied.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"home_city": {
"description": "Census-recognized home city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_county": {
"description": "Home county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_state": {
"description": "Valid 50-state/DC home state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"home_zip": {
"description": "Home ZIP; never inferred from another role.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"military_service_state": {
"description": "State tied to a state-scoped military affiliation.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"military_status": {
"description": "Person-supplied military affiliation.",
"enum": [
"active_duty",
"veteran",
"reservist",
"dod_civilian",
"military_family"
],
"type": "string"
},
"occupation": {
"description": "Person-supplied occupation.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_city": {
"description": "Census-recognized payroll-origin city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_county": {
"description": "Payroll-origin county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_state": {
"description": "Valid 50-state/DC payroll-origin state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"payroll_zip": {
"description": "Payroll-origin ZIP, separate from the worksite.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"property_city": {
"description": "Census-recognized city where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_county": {
"description": "County where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_state": {
"description": "Valid 50-state/DC property state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"property_zip": {
"description": "ZIP where the person owns real property; never inferred from home.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"relative_association_org_ids": {
"description": "Canonical association ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_associations": {
"description": "Associations of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_employer_org_ids": {
"description": "Canonical employer ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_employers": {
"description": "Employers of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_memberships": {
"description": "Confirmed relative memberships, each scoped to one exact institution.",
"items": {
"additionalProperties": false,
"properties": {
"credit_union_id": {
"description": "Exact credit-union id.",
"maxLength": 300,
"minLength": 1,
"type": "string"
},
"relation": {
"description": "Relative relationship.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"status": {
"description": "Confirmed membership status.",
"enum": [
"current_member",
"deceased_member"
],
"type": "string"
}
},
"required": [
"credit_union_id",
"relation",
"status"
],
"type": "object"
},
"maxItems": 50,
"type": "array"
},
"relative_school_org_ids": {
"description": "Canonical school ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_schools": {
"description": "Schools of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"school": {
"description": "Person-supplied school name; school_relationship is needed for a typed positive path.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"school_org_ids": {
"description": "Explicit school ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"school_relationship": {
"description": "How the person relates to the supplied school.",
"enum": [
"student",
"alumni",
"employee"
],
"type": "string"
},
"willing_to_join_association": {
"description": "Whether documented joinable-association actions may be considered.",
"type": "boolean"
},
"work_city": {
"description": "Census-recognized worksite city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_county": {
"description": "Worksite county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_state": {
"description": "Valid 50-state/DC worksite state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"work_zip": {
"description": "Worksite ZIP, separate from home and payroll.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"worship": {
"description": "Person-supplied place of worship.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"worship_org_ids": {
"description": "Explicit worship-organization ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
}
},
"type": "object"
},
"limit": {
"default": 10,
"description": "Visible items per bucket and delta list.",
"maximum": 50,
"minimum": 1,
"type": "integer"
},
"product": {
"additionalProperties": false,
"description": "Exact product request used for both eligibility-backed rate evaluation and ranking.",
"properties": {
"amount": {
"description": "Loan or credit amount in USD.",
"exclusiveMinimum": 0,
"type": "number"
},
"audience": {
"description": "Product audience.",
"enum": [
"business",
"consumer"
],
"type": "string"
},
"balance": {
"description": "Deposit balance in USD.",
"minimum": 0,
"type": "number"
},
"intent": {
"description": "Transaction intent when relevant.",
"enum": [
"purchase",
"refinance",
"cash_out",
"balance_transfer",
"new_credit"
],
"type": "string"
},
"occupancy": {
"description": "Property occupancy.",
"enum": [
"primary",
"secondary",
"investment"
],
"type": "string"
},
"product_type": {
"description": "Exact product family.",
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan",
"credit_card",
"savings",
"cd",
"share_certificate",
"money_market",
"ira_cd",
"ira",
"share_savings"
],
"type": "string"
},
"term_months": {
"description": "Requested term in months.",
"maximum": 600,
"minimum": 1,
"type": "integer"
},
"vehicle_condition": {
"description": "Vehicle condition.",
"enum": [
"new",
"used",
"certified_pre_owned",
"any"
],
"type": "string"
}
},
"required": [
"product_type"
],
"type": "object"
}
},
"required": [
"baseline_person",
"candidate_person",
"product"
],
"type": "object"
},
"name": "compare_reachable_offers",
"outputSchema": {
"additionalProperties": true,
"description": "Snapshot-consistent comparison of two caller-supplied person fact panels.",
"properties": {
"baseline": {
"additionalProperties": true,
"description": "Eligibility-backed offer buckets for the baseline facts.",
"type": "object"
},
"candidate": {
"additionalProperties": true,
"description": "Eligibility-backed offer buckets for the candidate facts.",
"type": "object"
},
"deltas": {
"additionalProperties": true,
"description": "Newly reachable, no-longer-reachable-or-unknown, changed-path, and best-offer comparisons with truncation flags.",
"type": "object"
},
"disclosure": {
"description": "Required limits on interpreting missing or changed results.",
"type": [
"string",
"null"
]
},
"product": {
"additionalProperties": true,
"description": "Exact product request shared by both evaluations.",
"type": "object"
},
"semantics": {
"description": "Positive-evidence-only and unknown-is-never-ineligible contract.",
"type": [
"string",
"null"
]
},
"snapshot": {
"additionalProperties": true,
"description": "Shared rules clock, serving-generation context, publication identities, and stated database consistency boundary.",
"type": "object"
}
},
"type": "object"
}
},
{
"description": "Apples-to-apples multi-lender ranking by TOTAL cost of a loan (upfront origination/lender fees + lifetime interest over the holding period), not just the headline rate. Re-ranks real credit union offers and flags when the lowest-rate lender is not the cheapest overall.",
"inputSchema": {
"properties": {
"amount": {
"description": "Loan principal",
"type": "number"
},
"credit_score": {
"type": "number"
},
"down_payment_percent": {
"type": "number"
},
"fees": {
"properties": {
"flat_fees": {
"type": "number"
},
"origination_percent": {
"type": "number"
}
},
"type": "object"
},
"holding_period_months": {
"description": "Horizon for total-cost; defaults to term_months",
"type": "number"
},
"intent": {
"description": "default purchase",
"enum": [
"purchase",
"refinance"
],
"type": "string"
},
"max_lenders": {
"description": "cap on ranked rows (default 10, max 25)",
"type": "number"
},
"product_type": {
"description": "Loan product to rank",
"enum": [
"mortgage",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"personal_loan",
"heloc",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"state": {
"description": "2-letter US state",
"type": "string"
},
"term_months": {
"type": "number"
}
},
"required": [
"product_type",
"state",
"amount"
],
"type": "object"
},
"name": "compare_total_cost",
"outputSchema": {
"additionalProperties": true,
"properties": {
"amount": {
"description": "Loan amount in dollars used for every lender in the comparison.",
"type": [
"number",
"null"
]
},
"cheapest": {
"additionalProperties": true,
"description": "The lender with the lowest total cost over the holding period.",
"properties": {
"lender": {
"description": "Name of the lowest-total-cost lender.",
"type": [
"string",
"null"
]
},
"total_cost": {
"description": "That lender's total cost in dollars over the holding period.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"holding_period_months": {
"description": "How long the borrower is assumed to keep the loan. Total cost is measured over this period, not the full term, so a shorter hold favors low-fee lenders.",
"type": [
"number",
"null"
]
},
"intent": {
"description": "Borrowing purpose the pricing assumes, e.g. 'purchase' or 'refinance'.",
"type": [
"string",
"null"
]
},
"next_actions": {
"description": "Suggested follow-up tools, as bare tool names.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"note": {
"description": "Plain-English interpretation of the numbers above, already phrased for the user; quote it rather than re-deriving the comparison.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.",
"type": [
"string",
"null"
]
},
"ranked": {
"description": "Lenders ordered cheapest-first by total cost over the holding period.",
"items": {
"additionalProperties": true,
"properties": {
"apr": {
"description": "APR in percent, including fees where published.",
"type": [
"number",
"null"
]
},
"credit_union_id": {
"description": "Internal composite identifier 'name|city|STATE'.",
"type": [
"string",
"null"
]
},
"credit_union_url": {
"description": "The credit union's own website.",
"type": [
"string",
"null"
]
},
"headline_rank": {
"description": "Where this lender would rank on headline APR alone; compare with `rank` to see when fees change the winner.",
"type": [
"number",
"null"
]
},
"interest_over_holding": {
"description": "Interest in dollars paid over the holding period only, not the full term.",
"type": [
"number",
"null"
]
},
"lender": {
"description": "Credit union offering this loan.",
"type": [
"string",
"null"
]
},
"monthly_payment": {
"description": "Principal-and-interest payment in dollars per month; excludes taxes, insurance, PMI, and HOA.",
"type": [
"number",
"null"
]
},
"principal_paid_over_holding": {
"description": "Principal in dollars retired over the holding period; this is equity built, not a cost.",
"type": [
"number",
"null"
]
},
"rank": {
"description": "Position by total cost over the holding period, 1 = cheapest.",
"type": [
"number",
"null"
]
},
"rate": {
"description": "Note rate in percent, excluding fees.",
"type": [
"number",
"null"
]
},
"remaining_balance": {
"description": "Loan balance in dollars still owed at the end of the holding period.",
"type": [
"number",
"null"
]
},
"total_cost": {
"description": "Upfront fees plus interest over the holding period, in dollars — the ranking metric. It excludes principal, which is not a cost.",
"type": [
"number",
"null"
]
},
"total_cost_vs_best": {
"description": "Dollars more expensive than the cheapest lender over the holding period. 0 marks the winner.",
"type": [
"number",
"null"
]
},
"upfront_fees": {
"description": "Origination and lender fees in dollars paid at closing, as modeled from the caller's fee assumptions.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"ranked_by": {
"description": "The metric the list is sorted by — 'total_cost' means cheapest over the holding period, which can differ from the lowest rate.",
"type": [
"string",
"null"
]
},
"rate_leader": {
"additionalProperties": true,
"description": "The lender with the lowest headline APR, which is not always the cheapest overall.",
"properties": {
"apr": {
"description": "That lender's APR in percent.",
"type": [
"number",
"null"
]
},
"lender": {
"description": "Name of the lowest-APR lender.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"reranked": {
"description": "True when accounting for fees changed the winner from the headline rate leader — the key finding to surface when it is true.",
"type": [
"boolean",
"null"
]
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
},
"term_months": {
"description": "Loan term in months (360 = 30 years, 180 = 15 years, 60 = 5 years).",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Subscribe a monitor to a SPECIFIC named credit union's published rate and alert via webhook when that CU changes its rate (vs the aggregate market-best decision). Returns the monitor with a webhook_signing_secret (shown once) and a baseline snapshot of the CU's current rate.",
"inputSchema": {
"properties": {
"audience": {
"description": "Scope offers by WHO they are for: 'business' returns business-audience products (DSCR mortgages, commercial vehicle loans, SBA); 'consumer' excludes them. Omit for both.",
"enum": [
"business",
"consumer"
],
"type": "string"
},
"conditions": {
"description": "Alert conditions on the named CU rate. Default: any change.",
"properties": {
"change_direction": {
"enum": [
"up",
"down",
"any"
],
"type": "string"
},
"min_change_bps": {
"description": "Min basis-point move to alert. Default 0.",
"type": "number"
}
},
"type": "object"
},
"cooldown_hours": {
"description": "1-168, default 24.",
"type": "number"
},
"loan_program": {
"description": "e.g. '30-year-fixed'.",
"type": "string"
},
"name": {
"description": "Descriptive monitor name. Required.",
"type": "string"
},
"occupancy": {
"description": "MORTGAGE/HELOC: property occupancy. 'investment' returns investor / non-owner-occupied / DSCR pricing; 'secondary' second-home pricing. Omit for standard primary-residence offers.",
"enum": [
"primary",
"secondary",
"investment"
],
"type": "string"
},
"product_type": {
"description": "Default mortgage.",
"enum": [
"mortgage",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"credit_card",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"state": {
"description": "2-letter state for the CU published rate.",
"type": "string"
},
"target_credit_union": {
"description": "The specific credit union whose published rate to watch. Required.",
"properties": {
"credit_union_id": {
"description": "CU id from list_credit_unions/get_credit_union.",
"type": "string"
},
"name": {
"description": "Optional human label / lookup by name.",
"type": "string"
}
},
"type": "object"
},
"webhook_url": {
"description": "HTTPS webhook. Required.",
"type": "string"
}
},
"required": [
"name",
"target_credit_union",
"webhook_url"
],
"type": "object"
},
"name": "create_competitor_monitor",
"outputSchema": {
"additionalProperties": true,
"description": "Result of creating a competitor-watch monitor targeting one named credit union.",
"properties": {
"disclosures": {
"description": "Scope caveats about what this monitor does and does not alert on.",
"items": {
"type": "string"
},
"type": "array"
},
"important": {
"description": "Warning that the signing secret is shown only once.",
"type": "string"
},
"monitor": {
"additionalProperties": true,
"description": "The created competitor monitor.",
"properties": {
"competitor": {
"additionalProperties": true,
"description": "The watched institution.",
"properties": {
"credit_union_id": {
"description": "Institution id, when resolved.",
"type": [
"string",
"null"
]
},
"credit_union_name": {
"description": "Institution name.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter state code.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"conditions": {
"description": "Change-direction and minimum-bps trigger conditions.",
"type": [
"object",
"array",
"null"
]
},
"cooldown_hours": {
"description": "Minimum hours between triggers.",
"type": [
"number",
"null"
]
},
"created_at": {
"description": "ISO-8601 creation timestamp.",
"type": [
"string",
"null"
]
},
"current_rate": {
"additionalProperties": true,
"description": "The competitor's rate at creation time, the baseline for future comparisons.",
"properties": {
"apr": {
"description": "Current APR percent.",
"type": [
"number",
"null"
]
},
"as_of": {
"description": "ISO-8601 timestamp of the baseline rate.",
"type": [
"string",
"null"
]
},
"rate": {
"description": "Current note rate percent.",
"type": [
"number",
"null"
]
}
},
"type": [
"object",
"null"
]
},
"id": {
"description": "Monitor id.",
"type": "string"
},
"loan_program": {
"description": "Loan program filter, when given.",
"type": [
"string",
"null"
]
},
"name": {
"description": "Caller-supplied label.",
"type": "string"
},
"product_type": {
"description": "Product the monitor watches.",
"type": [
"string",
"null"
]
},
"status": {
"description": "Lifecycle state, typically 'active'.",
"type": "string"
},
"target_type": {
"description": "Always 'competitor' for this tool.",
"type": "string"
},
"webhook_signing_secret_prefix": {
"description": "Non-secret prefix of the signing secret, for identifying it later.",
"type": [
"string",
"null"
]
},
"webhook_url": {
"description": "URL that fires on a trigger.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"next_actions": {
"description": "Suggested follow-up tool names.",
"items": {
"type": "string"
},
"type": "array"
},
"summary": {
"description": "One-line confirmation naming the monitor and the credit union it watches.",
"type": "string"
},
"webhook_signing_secret": {
"description": "Full HMAC signing secret. Shown once, at creation.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Create a branded rate-email campaign: on a cadence, email the campaign's recipient list the latest rates for one or more states (or a named region preset) under the org's branding, with ONE OR MORE products (1-5, no duplicates). Each product is one of: {category:'mortgage', subtype:'30-year-fixed'|'15-year-fixed'}, {category:'auto', condition:'new'|'used'|'any', term_months?:36|48|60|72|84} (auto = cars only), or {category:'rv'|'boat'|'motorcycle', condition:'new'|'used'|'any'}. Defaults to a single 30-year-fixed mortgage if products is omitted. Created 'paused'; add recipients, then activate via update_email_campaign (activation requires branding display_name + business_address). Requires a Pro plan. Provide exactly one of state_code, state_codes, or region.",
"inputSchema": {
"properties": {
"cadence": {
"description": "Send cadence (default weekly).",
"enum": [
"daily",
"weekly",
"monthly"
],
"type": "string"
},
"intro_text_override": {
"description": "Per-campaign intro; falls back to branding intro_text.",
"type": "string"
},
"name": {
"description": "Campaign label. Required.",
"type": "string"
},
"products": {
"description": "1-5 products to feature (no duplicates). Each is {category:'mortgage', subtype:'30-year-fixed'|'15-year-fixed'}, {category:'auto', condition:'new'|'used'|'any', term_months?:36|48|60|72|84}, or {category:'rv'|'boat'|'motorcycle', condition:'new'|'used'|'any'}.",
"items": {
"type": "object"
},
"type": "array"
},
"region": {
"description": "Named region preset (e.g. east_coast); expands server-side to its member states.",
"enum": [
"east_coast",
"west_coast",
"midwest",
"south",
"northeast",
"southeast",
"southwest",
"mountain_west",
"new_england",
"mid_atlantic",
"pacific_northwest"
],
"type": "string"
},
"state_code": {
"description": "Legacy single 2-letter US state code (e.g. CA). Prefer state_codes or region for multi-state coverage.",
"type": "string"
},
"state_codes": {
"description": "2-letter US state codes (up to 25) — best rates are ranked ACROSS all of them, not per state.",
"items": {
"type": "string"
},
"maxItems": 25,
"type": "array"
}
},
"required": [
"name"
],
"type": "object"
},
"name": "create_email_campaign",
"outputSchema": {
"additionalProperties": true,
"description": "The created branded rate-email campaign. Requires a Pro (tier 2+) organization.",
"properties": {
"amount": {
"description": "Loan amount used when pricing the featured rates.",
"type": [
"number",
"null"
]
},
"cadence": {
"description": "'daily', 'weekly', or 'monthly'.",
"type": [
"string",
"null"
]
},
"created_at": {
"description": "Epoch-ms creation time.",
"type": [
"number",
"null"
]
},
"credit_score": {
"description": "Assumed borrower credit score.",
"type": [
"number",
"null"
]
},
"id": {
"description": "Campaign id (camp_...) — pass to the other campaign tools.",
"type": "string"
},
"intro_text_override": {
"description": "Per-campaign intro, overriding the org default.",
"type": [
"string",
"null"
]
},
"last_run_at": {
"description": "Epoch-ms of the last send, null if never.",
"type": [
"number",
"null"
]
},
"name": {
"description": "Campaign label.",
"type": "string"
},
"organization_id": {
"description": "Owning organization.",
"type": "string"
},
"product_category": {
"description": "'mortgage', 'auto', 'heloc', or 'personal'.",
"type": [
"string",
"null"
]
},
"product_subtype": {
"description": "Product subtype, when set.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Primary product type, e.g. '30-year-fixed'.",
"type": [
"string",
"null"
]
},
"products": {
"description": "Parsed list of products the email covers.",
"type": [
"array",
"null"
]
},
"region_preset": {
"description": "Region preset key when the campaign was scoped by region, else null.",
"type": [
"string",
"null"
]
},
"state_code": {
"description": "Legacy scalar state — always the first entry of state_codes.",
"type": [
"string",
"null"
]
},
"state_codes": {
"description": "Full list of two-letter state codes the campaign covers.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"status": {
"description": "'draft', 'active', or 'paused'. New campaigns start as 'draft'.",
"type": [
"string",
"null"
]
},
"term_months": {
"description": "Term in months.",
"type": [
"number",
"null"
]
},
"updated_at": {
"description": "Epoch-ms last-modified time.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Create a new decision monitor that watches for rate changes and sends webhook notifications when conditions are met. Returns the monitor with a webhook_signing_secret for verifying webhook payloads.",
"inputSchema": {
"properties": {
"conditions": {
"description": "Array of conditions that must be met to trigger the monitor. Required.",
"items": {
"properties": {
"field": {
"description": "The field to evaluate.",
"enum": [
"rate",
"apr",
"monthly_payment"
],
"type": "string"
},
"operator": {
"description": "Comparison operator (lt=less than, lte=less than or equal, gt=greater than, gte=greater than or equal, eq=equal, change_pct=percentage change).",
"enum": [
"lt",
"lte",
"gt",
"gte",
"eq",
"change_pct"
],
"type": "string"
},
"value": {
"description": "The value to compare against.",
"type": "number"
}
},
"required": [
"field",
"operator",
"value"
],
"type": "object"
},
"type": "array"
},
"cooldown_hours": {
"description": "Minimum hours between webhook triggers (1-168). Defaults to 24.",
"type": "number"
},
"decision_context": {
"description": "The context for evaluating rate changes. Required.",
"properties": {
"amount": {
"description": "Loan amount in dollars (minimum 1000). Required.",
"type": "number"
},
"intent": {
"description": "The loan intent. Required.",
"enum": [
"purchase",
"refinance",
"cash_out",
"balance_transfer",
"new_credit"
],
"type": "string"
},
"product_type": {
"description": "Type of loan product. Defaults to \"mortgage\".",
"type": "string"
},
"state": {
"description": "US state code (2-letter, e.g., CA, TX, NY). Required.",
"type": "string"
},
"term_months": {
"description": "Loan term in months (12-480). Defaults to 360 (30-year mortgage).",
"type": "number"
}
},
"required": [
"state",
"intent",
"amount"
],
"type": "object"
},
"name": {
"description": "A descriptive name for the monitor. Required.",
"type": "string"
},
"subscribed_product_types": {
"description": "Optional array of product types to monitor (e.g., [\"30yr_fixed\", \"15yr_fixed\"]).",
"items": {
"type": "string"
},
"type": "array"
},
"subscribed_states": {
"description": "Optional array of state codes to monitor. If not provided, monitors all states.",
"items": {
"type": "string"
},
"type": "array"
},
"webhook_url": {
"description": "The URL to send webhook notifications to. Required.",
"type": "string"
}
},
"required": [
"name",
"decision_context",
"conditions",
"webhook_url"
],
"type": "object"
},
"name": "create_monitor",
"outputSchema": {
"additionalProperties": true,
"description": "Result of creating a rate monitor. The webhook signing secret is returned once and never again.",
"properties": {
"important": {
"description": "Warning that the signing secret will not be shown again.",
"type": "string"
},
"monitor": {
"additionalProperties": true,
"description": "The created monitor.",
"properties": {
"conditions": {
"description": "Trigger conditions evaluated against rate changes.",
"type": [
"array",
"null"
]
},
"cooldown_hours": {
"description": "Minimum hours between two triggers of this monitor.",
"type": [
"number",
"null"
]
},
"created_at": {
"description": "ISO-8601 creation timestamp.",
"type": [
"string",
"null"
]
},
"decision_context": {
"additionalProperties": true,
"description": "Stored decision context (loan amount, term, intent) used when evaluating triggers.",
"type": [
"object",
"null"
]
},
"id": {
"description": "Monitor id, used by get_monitor / update_monitor / delete_monitor.",
"type": "string"
},
"name": {
"description": "Caller-supplied monitor label.",
"type": "string"
},
"status": {
"description": "Lifecycle state, typically 'active' or 'paused'.",
"type": "string"
},
"subscribed_product_types": {
"description": "Product types the monitor watches.",
"type": [
"array",
"null"
]
},
"subscribed_states": {
"description": "Two-letter state codes the monitor watches.",
"type": [
"array",
"null"
]
},
"webhook_signing_secret": {
"description": "HMAC secret for verifying webhook payloads. Shown only on creation.",
"type": [
"string",
"null"
]
},
"webhook_url": {
"description": "URL that fires when the monitor triggers.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"summary": {
"description": "One-line confirmation naming the monitor that was created.",
"type": "string"
}
},
"type": "object"
}
},
{
"description": "Permanently delete a saved cohort by id. This action cannot be undone.",
"inputSchema": {
"properties": {
"id": {
"description": "Cohort id. Required.",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "delete_cohort",
"outputSchema": {
"additionalProperties": true,
"description": "Deletion acknowledgement. The route replies 204 with no body, which the client renders as a bare success flag.",
"properties": {
"success": {
"description": "True when the cohort was deleted.",
"type": "boolean"
}
},
"type": "object"
}
},
{
"description": "Delete a scheduled digest by id. Stops the recurring email.",
"inputSchema": {
"properties": {
"id": {
"description": "The digest id to delete.",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "delete_digest",
"outputSchema": {
"additionalProperties": true,
"description": "Deletion acknowledgement. The route replies 204 with no body, which the client renders as a bare success flag.",
"properties": {
"success": {
"description": "True when the digest was deleted.",
"type": "boolean"
}
},
"type": "object"
}
},
{
"description": "Delete a branded rate-email campaign and its recipients. This cannot be undone.",
"inputSchema": {
"properties": {
"id": {
"description": "Campaign id. Required.",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "delete_email_campaign",
"outputSchema": {
"additionalProperties": true,
"description": "Deletion acknowledgement. The route deletes the campaign and its recipients, then replies 204 with no body, which the client renders as a bare success flag.",
"properties": {
"success": {
"description": "True when the campaign was deleted.",
"type": "boolean"
}
},
"type": "object"
}
},
{
"description": "Permanently delete a monitor. This action cannot be undone.",
"inputSchema": {
"properties": {
"monitor_id": {
"description": "The unique identifier of the monitor to delete. Required.",
"type": "string"
}
},
"required": [
"monitor_id"
],
"type": "object"
},
"name": "delete_monitor",
"outputSchema": {
"additionalProperties": true,
"description": "Result of deleting a monitor. On a missing id the tool returns a not-found shape instead of throwing.",
"properties": {
"deleted": {
"description": "True when the monitor was deleted. Absent on not-found.",
"type": "boolean"
},
"error": {
"description": "Present and set to 'not_found' when the monitor id does not exist.",
"type": [
"string",
"null"
]
},
"monitor_id": {
"description": "The id that was deleted.",
"type": "string"
},
"summary": {
"description": "Confirmation of deletion, or a not-found message.",
"type": "string"
}
},
"type": "object"
}
},
{
"description": "Delete a saved scenario by id.",
"inputSchema": {
"properties": {
"id": {
"description": "Scenario id",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "delete_scenario",
"outputSchema": {
"additionalProperties": true,
"description": "Deletion acknowledgement. The route replies 204 with no body, which the client renders as a bare success flag.",
"properties": {
"success": {
"description": "True when the scenario was deleted.",
"type": "boolean"
}
},
"type": "object"
}
},
{
"description": "Send a test webhook for a monitor using a simulated rate change. This actually delivers an HTTP request to the monitor's configured webhook URL. IMPORTANT: a test delivery is NOT signed with the monitor's signing secret — only a hash of that secret is stored, so test deliveries use a placeholder and will FAIL signature verification. Use this to test payload handling, not signature verification. Only use when the user explicitly requests a test webhook delivery.",
"inputSchema": {
"properties": {
"monitor_id": {
"description": "The unique identifier of the monitor to test. Required.",
"type": "string"
},
"rate_change": {
"description": "The simulated rate change event. Required.",
"properties": {
"new_rate": {
"description": "The new rate value. Required.",
"type": "number"
},
"previous_rate": {
"description": "The previous rate value. Required.",
"type": "number"
},
"product_type": {
"description": "The product type that changed (e.g., \"30yr_fixed\"). Required.",
"type": "string"
},
"state": {
"description": "US state code where the rate changed. Required.",
"type": "string"
}
},
"required": [
"state",
"product_type",
"previous_rate",
"new_rate"
],
"type": "object"
}
},
"required": [
"monitor_id",
"rate_change"
],
"type": "object"
},
"name": "deliver_test_webhook",
"outputSchema": {
"additionalProperties": true,
"description": "Result of firing a real test webhook at the monitor's stored URL, overriding the cooldown. On a missing id the tool returns a not-found shape instead of throwing.",
"properties": {
"error": {
"description": "Present and set to 'not_found' when the monitor id does not exist.",
"type": [
"string",
"null"
]
},
"evaluation": {
"additionalProperties": true,
"description": "Why the monitor did or did not fire.",
"properties": {
"conditions_met": {
"description": "Whether the trigger conditions were satisfied.",
"type": [
"boolean",
"array",
"null"
]
},
"conditions_summary": {
"description": "Per-condition explanation.",
"type": [
"string",
"array",
"null"
]
}
},
"type": "object"
},
"rate_change": {
"additionalProperties": true,
"description": "The simulated change, with rates pre-formatted as percent strings.",
"properties": {
"change_pct": {
"description": "Signed change as a percent string.",
"type": [
"string",
"null"
]
},
"new_rate": {
"description": "New rate as a percent string.",
"type": [
"string",
"null"
]
},
"previous_rate": {
"description": "Prior rate as a percent string.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Product type.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter state code.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"summary": {
"description": "Whether the test webhook was delivered and whether the monitor would have triggered, or a not-found message.",
"type": "string"
},
"webhook_delivery": {
"additionalProperties": true,
"description": "Outcome of the HTTP POST to the monitor's webhook URL. Omitted when the backend reported no delivery attempt.",
"properties": {
"delivered": {
"description": "True when the endpoint accepted the payload.",
"type": [
"boolean",
"null"
]
},
"error": {
"description": "Failure reason when delivery did not succeed.",
"type": [
"string",
"null"
]
},
"status_code": {
"description": "HTTP status returned by the endpoint.",
"type": [
"number",
"null"
]
}
},
"type": [
"object",
"null"
]
},
"would_trigger": {
"description": "Whether the monitor's conditions were satisfied by the supplied change.",
"type": "boolean"
}
},
"type": "object"
}
},
{
"description": "Borrower-facing home affordability estimate: given gross income, existing monthly debts, down payment, and front-end/back-end DTI caps, compute the max monthly payment, max loan amount, and max home price. Surfaces the max_loan annuity engine. If no rate is supplied, the current best market rate for the state is used.",
"inputSchema": {
"properties": {
"back_end_dti": {
"description": "Total-debt DTI cap as a decimal. Default 0.36.",
"type": "number"
},
"down_payment": {
"description": "Cash down payment in dollars. Default 0.",
"type": "number"
},
"front_end_dti": {
"description": "Housing-payment DTI cap as a decimal. Default 0.28.",
"type": "number"
},
"income_annual": {
"description": "Gross annual income in dollars",
"type": "number"
},
"monthly_debts": {
"description": "Existing recurring monthly debt payments. Default 0.",
"type": "number"
},
"product_type": {
"description": "Product for the market-rate lookup. Default mortgage.",
"type": "string"
},
"rate": {
"description": "Optional annual interest rate, e.g. 6.5. If omitted, best market rate is used.",
"type": "number"
},
"state": {
"description": "US state code for the market-rate lookup. Default CA.",
"type": "string"
},
"term_months": {
"description": "Loan term in months. Default 360.",
"type": "number"
}
},
"required": [
"income_annual"
],
"type": "object"
},
"name": "estimate_affordability",
"outputSchema": {
"additionalProperties": true,
"properties": {
"affordable": {
"description": "True when the income supports a meaningful loan after debts; false means the DTI budget is exhausted, not that nothing is purchasable.",
"type": [
"boolean",
"null"
]
},
"assumed_defaults": {
"additionalProperties": true,
"description": "Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.",
"properties": {
"back_end_dti": {
"description": "Back-end (total-debt) DTI cap assumed, as a decimal (0.36 = 36%).",
"type": [
"number",
"null"
]
},
"down_payment": {
"description": "Down payment in dollars assumed.",
"type": [
"number",
"null"
]
},
"front_end_dti": {
"description": "Front-end (housing-only) DTI cap assumed, as a decimal (0.28 = 28%).",
"type": [
"number",
"null"
]
},
"monthly_debts": {
"description": "Existing monthly debt payments in dollars assumed.",
"type": [
"number",
"null"
]
},
"product_type": {
"description": "Product type assumed when resolving the market rate.",
"type": [
"string",
"null"
]
},
"state": {
"description": "State code assumed for market-rate lookups because the caller did not supply one.",
"type": [
"string",
"null"
]
},
"term_months": {
"description": "Loan term in months assumed because the caller did not supply one.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"back_end_budget_value": {
"description": "Total monthly debt budget in dollars under the back-end DTI cap, including existing debts. Compare with max_payment_value to see the headroom.",
"type": [
"number",
"null"
]
},
"binding_constraint": {
"description": "Which limit caps the budget: 'front_end_dti' (housing payment alone) or 'back_end_dti' (all debts). This tells the user what to fix to buy more.",
"type": [
"string",
"null"
]
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"down_payment": {
"description": "Down payment in dollars assumed, as a formatted string.",
"type": [
"string",
"null"
]
},
"max_home_price": {
"description": "Largest purchase price in dollars, being the max loan amount plus the down payment.",
"type": [
"string",
"null"
]
},
"max_loan_amount": {
"description": "Largest loan principal in dollars that payment supports at the rate and term used.",
"type": [
"string",
"null"
]
},
"max_monthly_payment": {
"description": "Largest housing payment in dollars supported by the binding DTI constraint, as a formatted string.",
"type": [
"string",
"null"
]
},
"max_payment_value": {
"description": "The same maximum housing payment as a raw number in dollars, for further math.",
"type": [
"number",
"null"
]
},
"next_actions": {
"description": "Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.",
"items": {
"additionalProperties": true,
"properties": {
"tool": {
"description": "Name of the follow-up MCP tool to call next.",
"type": [
"string",
"null"
]
},
"why": {
"description": "One-line reason this follow-up tool would be useful given the current result.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"note": {
"description": "Explanation of how the front-end and back-end DTI caps interact and which one binds.",
"type": [
"string",
"null"
]
},
"rate_source": {
"description": "Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.",
"type": [
"string",
"null"
]
},
"rate_used": {
"description": "Interest rate, in percent, used for every calculation in this result. Check rate_source to see whether it came from the caller or from live market data.",
"type": [
"string",
"null"
]
},
"reason": {
"description": "Why the affordable amount is constrained or zero, present only in that case — e.g. 'Existing debts exceed the back-end DTI budget.'",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Total monthly housing cost (PITI): principal+interest plus property tax, homeowners insurance, PMI, and HOA, so affordability reflects real monthly outlay. If no rate is supplied, the current best market rate for the state is used.",
"inputSchema": {
"properties": {
"annual_insurance": {
"description": "Homeowners insurance in dollars/year. Default max(800, 0.35% of home price).",
"type": "number"
},
"credit_score": {
"description": "Optional borrower credit score, used for the market-rate lookup.",
"type": "number"
},
"down_payment": {
"description": "Cash down payment in dollars. Default 0. loan_amount = home_price - down_payment.",
"type": "number"
},
"home_price": {
"description": "Purchase price in dollars. Required unless loan_amount is given.",
"type": "number"
},
"loan_amount": {
"description": "Optional explicit loan amount; overrides home_price - down_payment.",
"type": "number"
},
"monthly_hoa": {
"description": "HOA dues in dollars/month. Default 0.",
"type": "number"
},
"pmi_rate": {
"description": "Annual PMI as % of loan balance. Default 0.5, applied only when LTV > 80%.",
"type": "number"
},
"property_tax_rate": {
"description": "Annual property tax as % of home value. Default 1.1.",
"type": "number"
},
"rate": {
"description": "Annual interest rate, e.g. 6.5. If omitted, best market rate for the state is used.",
"type": "number"
},
"state": {
"description": "2-letter US state code for the market-rate lookup. Default CA.",
"type": "string"
},
"term_months": {
"description": "Loan term in months. Default 360.",
"type": "number"
}
},
"required": [],
"type": "object"
},
"name": "estimate_monthly_cost",
"outputSchema": {
"additionalProperties": true,
"properties": {
"annual_total": {
"description": "Twelve months of the total monthly payment, in dollars.",
"type": [
"string",
"null"
]
},
"assumed_defaults": {
"additionalProperties": true,
"description": "Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.",
"properties": {
"annual_insurance": {
"description": "Annual homeowners insurance premium in dollars assumed.",
"type": [
"string",
"null"
]
},
"monthly_hoa": {
"description": "Monthly HOA dues in dollars assumed.",
"type": [
"string",
"null"
]
},
"pmi_rate": {
"description": "Annual PMI rate assumed, as a percent of the loan balance.",
"type": [
"string",
"null"
]
},
"property_tax_rate": {
"description": "Annual property tax rate assumed, as a percent string. Real county rates vary widely from this.",
"type": [
"string",
"null"
]
},
"state": {
"description": "State code assumed for market-rate lookups because the caller did not supply one.",
"type": [
"string",
"null"
]
},
"term_months": {
"description": "Loan term in months assumed because the caller did not supply one.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"breakdown": {
"additionalProperties": true,
"description": "Share of the total monthly payment taken by each component, as percent strings.",
"properties": {
"hoa_pct": {
"description": "Share of the total payment that is HOA dues.",
"type": [
"string",
"null"
]
},
"insurance_pct": {
"description": "Share of the total payment that is homeowners insurance.",
"type": [
"string",
"null"
]
},
"p_and_i_pct": {
"description": "Share of the total payment that is principal and interest.",
"type": [
"string",
"null"
]
},
"pmi_pct": {
"description": "Share of the total payment that is PMI; '0%' when PMI does not apply.",
"type": [
"string",
"null"
]
},
"tax_pct": {
"description": "Share of the total payment that is property tax.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"down_payment": {
"description": "Cash in dollars put down at closing.",
"type": [
"string",
"null"
]
},
"home_price": {
"description": "Purchase price in dollars, as a formatted string.",
"type": [
"string",
"null"
]
},
"loan_amount": {
"description": "Amount borrowed in dollars, being the home price less the down payment.",
"type": [
"string",
"null"
]
},
"ltv": {
"description": "Loan-to-value ratio as a percent string. PMI generally applies above 80%.",
"type": [
"string",
"null"
]
},
"monthly_hoa": {
"description": "Monthly HOA dues in dollars, as supplied or defaulted.",
"type": [
"string",
"null"
]
},
"monthly_insurance": {
"description": "Monthly homeowners insurance in dollars, one twelfth of the annual premium used.",
"type": [
"string",
"null"
]
},
"monthly_pmi": {
"description": "Monthly private mortgage insurance in dollars. $0 when LTV is at or below 80%.",
"type": [
"string",
"null"
]
},
"monthly_property_tax": {
"description": "Estimated monthly property tax in dollars, derived from the assumed tax rate rather than an actual county assessment.",
"type": [
"string",
"null"
]
},
"next_actions": {
"description": "Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.",
"items": {
"additionalProperties": true,
"properties": {
"tool": {
"description": "Name of the follow-up MCP tool to call next.",
"type": [
"string",
"null"
]
},
"why": {
"description": "One-line reason this follow-up tool would be useful given the current result.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"pmi_applies": {
"description": "True when the LTV requires private mortgage insurance.",
"type": [
"boolean",
"null"
]
},
"principal_and_interest": {
"description": "Monthly principal-and-interest payment in dollars — only part of the total housing cost.",
"type": [
"string",
"null"
]
},
"rate_source": {
"description": "Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.",
"type": [
"string",
"null"
]
},
"rate_used": {
"description": "Interest rate, in percent, used for every calculation in this result. Check rate_source to see whether it came from the caller or from live market data.",
"type": [
"string",
"null"
]
},
"total_monthly_payment": {
"description": "Full monthly housing cost in dollars: principal, interest, taxes, insurance, plus PMI and HOA where they apply.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Evaluate a caller-supplied panel of 1-10 named fact profiles for one exact product against one serving snapshot, deduplicating reachable institutions and exact offers. This is descriptive only for the supplied panel: never call it a population estimate, conversion rate, approval forecast, or negative eligibility result. Use neutral profile labels instead of names, emails, account numbers, or other direct identifiers. Profiles are forwarded transiently and are not stored by this tool; unknown remains unknown.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"limit": {
"default": 50,
"description": "Maximum aggregate institutions and deduplicated offers returned.",
"maximum": 200,
"minimum": 1,
"type": "integer"
},
"product": {
"additionalProperties": false,
"description": "Exact product request used for both eligibility-backed rate evaluation and ranking.",
"properties": {
"amount": {
"description": "Loan or credit amount in USD.",
"exclusiveMinimum": 0,
"type": "number"
},
"audience": {
"description": "Product audience.",
"enum": [
"business",
"consumer"
],
"type": "string"
},
"balance": {
"description": "Deposit balance in USD.",
"minimum": 0,
"type": "number"
},
"intent": {
"description": "Transaction intent when relevant.",
"enum": [
"purchase",
"refinance",
"cash_out",
"balance_transfer",
"new_credit"
],
"type": "string"
},
"occupancy": {
"description": "Property occupancy.",
"enum": [
"primary",
"secondary",
"investment"
],
"type": "string"
},
"product_type": {
"description": "Exact product family.",
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan",
"credit_card",
"savings",
"cd",
"share_certificate",
"money_market",
"ira_cd",
"ira",
"share_savings"
],
"type": "string"
},
"term_months": {
"description": "Requested term in months.",
"maximum": 600,
"minimum": 1,
"type": "integer"
},
"vehicle_condition": {
"description": "Vehicle condition.",
"enum": [
"new",
"used",
"certified_pre_owned",
"any"
],
"type": "string"
}
},
"required": [
"product_type"
],
"type": "object"
},
"profiles": {
"description": "Caller-supplied named panel. Names must be unique within this request.",
"items": {
"additionalProperties": false,
"properties": {
"name": {
"description": "Unique neutral panel label, such as profile-01; do not put PII here.",
"maxLength": 120,
"minLength": 1,
"type": "string"
},
"person": {
"additionalProperties": false,
"description": "Explicit caller-supplied person facts. Unknown facts stay absent; do not infer them.",
"properties": {
"applicant_kind": {
"description": "What the applicant is; absence means a natural person.",
"enum": [
"person",
"trust",
"organization",
"partnership",
"corporation",
"other_legal_entity"
],
"type": "string"
},
"asserted_org_qualifiers": {
"description": "Narrow conditions the person explicitly asserted; never infer them.",
"items": {
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"association_org_ids": {
"description": "Explicit association ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"associations": {
"description": "Associations the person already belongs to.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"employer": {
"description": "Person-supplied employer name; use employer_org_ids after authoritative resolution.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"employer_org_ids": {
"description": "Explicit employer ids returned by resolve_eligibility_entities; rates-api revalidates type and active-publication authority.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"facility_city": {
"description": "Census-recognized facility city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_county": {
"description": "County where the applicant organization maintains a facility.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_state": {
"description": "Valid 50-state/DC facility state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"facility_zip": {
"description": "ZIP where the applicant organization maintains a facility.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"family_relation": {
"description": "Relationship to the relative whose affiliations are supplied.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"home_city": {
"description": "Census-recognized home city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_county": {
"description": "Home county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_state": {
"description": "Valid 50-state/DC home state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"home_zip": {
"description": "Home ZIP; never inferred from another role.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"military_service_state": {
"description": "State tied to a state-scoped military affiliation.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"military_status": {
"description": "Person-supplied military affiliation.",
"enum": [
"active_duty",
"veteran",
"reservist",
"dod_civilian",
"military_family"
],
"type": "string"
},
"occupation": {
"description": "Person-supplied occupation.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_city": {
"description": "Census-recognized payroll-origin city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_county": {
"description": "Payroll-origin county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_state": {
"description": "Valid 50-state/DC payroll-origin state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"payroll_zip": {
"description": "Payroll-origin ZIP, separate from the worksite.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"property_city": {
"description": "Census-recognized city where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_county": {
"description": "County where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_state": {
"description": "Valid 50-state/DC property state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"property_zip": {
"description": "ZIP where the person owns real property; never inferred from home.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"relative_association_org_ids": {
"description": "Canonical association ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_associations": {
"description": "Associations of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_employer_org_ids": {
"description": "Canonical employer ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_employers": {
"description": "Employers of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_memberships": {
"description": "Confirmed relative memberships, each scoped to one exact institution.",
"items": {
"additionalProperties": false,
"properties": {
"credit_union_id": {
"description": "Exact credit-union id.",
"maxLength": 300,
"minLength": 1,
"type": "string"
},
"relation": {
"description": "Relative relationship.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"status": {
"description": "Confirmed membership status.",
"enum": [
"current_member",
"deceased_member"
],
"type": "string"
}
},
"required": [
"credit_union_id",
"relation",
"status"
],
"type": "object"
},
"maxItems": 50,
"type": "array"
},
"relative_school_org_ids": {
"description": "Canonical school ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_schools": {
"description": "Schools of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"school": {
"description": "Person-supplied school name; school_relationship is needed for a typed positive path.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"school_org_ids": {
"description": "Explicit school ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"school_relationship": {
"description": "How the person relates to the supplied school.",
"enum": [
"student",
"alumni",
"employee"
],
"type": "string"
},
"willing_to_join_association": {
"description": "Whether documented joinable-association actions may be considered.",
"type": "boolean"
},
"work_city": {
"description": "Census-recognized worksite city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_county": {
"description": "Worksite county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_state": {
"description": "Valid 50-state/DC worksite state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"work_zip": {
"description": "Worksite ZIP, separate from home and payroll.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"worship": {
"description": "Person-supplied place of worship.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"worship_org_ids": {
"description": "Explicit worship-organization ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
}
},
"type": "object"
}
},
"required": [
"name",
"person"
],
"type": "object"
},
"maxItems": 10,
"minItems": 1,
"type": "array"
}
},
"required": [
"profiles",
"product"
],
"type": "object"
},
"name": "evaluate_eligibility_cohort",
"outputSchema": {
"additionalProperties": true,
"description": "One-snapshot evaluation of a small caller-supplied panel.",
"properties": {
"aggregate": {
"additionalProperties": true,
"description": "Deduplicated reachable institutions and exact offers, profile reach, counts, and truncation flags.",
"type": "object"
},
"disclosure": {
"description": "Required warning that the panel is not a population estimate, conversion rate, approval forecast, or rejection.",
"type": [
"string",
"null"
]
},
"methodology": {
"additionalProperties": true,
"description": "Panel size/source, deduplication identities, and explicit no-extrapolation/no-conversion semantics.",
"type": "object"
},
"product": {
"additionalProperties": true,
"description": "Exact product request evaluated for the panel.",
"type": "object"
},
"profiles": {
"description": "Per-profile counts, best evidenced offer, and observation timestamp.",
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
"semantics": {
"description": "Positive-evidence-only and unknown-is-never-ineligible contract.",
"type": [
"string",
"null"
]
},
"snapshot": {
"additionalProperties": true,
"description": "Shared rules clock and database observation boundaries.",
"type": "object"
}
},
"type": "object"
}
},
{
"description": "Explain WHY each top lender ranked where it did for a financing decision. Takes a full decision scenario (same shape as get_financing_decision) and returns a structured per-offer cost breakdown (rate, points, fees, lifetime interest), scoring signals, how much each offer beats the next by, and a plain-language summary of the ranking weights. Use this when a user asks why one lender beat another.",
"inputSchema": {
"properties": {
"amount": {
"description": "Loan amount in dollars. Required.",
"type": "number"
},
"credit_score": {
"description": "Borrower's credit score (300-850).",
"type": "number"
},
"intent": {
"description": "The loan intent.",
"enum": [
"purchase",
"refinance",
"cash_out",
"balance_transfer",
"new_credit"
],
"type": "string"
},
"max_providers": {
"description": "Maximum number of lenders to explain (1-5). Defaults to 5.",
"type": "number"
},
"product_type": {
"description": "Type of financing product.",
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"personal_loan",
"heloc",
"credit_card",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"state": {
"description": "US state code (2-letter). Required.",
"type": "string"
},
"term_months": {
"description": "Loan term in months.",
"type": "number"
}
},
"required": [
"state",
"intent",
"amount"
],
"type": "object"
},
"name": "explain_ranking",
"outputSchema": {
"additionalProperties": true,
"properties": {
"offers": {
"description": "Ranked offers with the scoring inputs that produced each position.",
"items": {
"additionalProperties": true,
"properties": {
"beats_next_by": {
"description": "Margin over the next-ranked offer, in APR percentage points, dollars per month, and dollars of lifetime interest. All zeros mean it is effectively a tie.",
"type": "object"
},
"cost_breakdown": {
"description": "The cost inputs behind this offer: rate and APR in percent, points, fees and monthly payment in dollars, and lifetime interest in dollars.",
"type": "object"
},
"lender": {
"description": "Credit union publishing this offer.",
"type": [
"string",
"null"
]
},
"rank": {
"description": "Position in the ranking, 1 = best weighted score.",
"type": [
"number",
"null"
]
},
"signals": {
"description": "Scoring signals with their raw value, weight, and contribution to the final score; use them to explain why one lender outranked another.",
"type": "array"
},
"signals_truncated_from": {
"description": "Full number of signals scored before the list above was shortened. Null when nothing was omitted.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"product_type": {
"description": "Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.",
"type": [
"string",
"null"
]
},
"request_id": {
"description": "Opaque identifier for this call, useful only for support or debugging; never show it to the user.",
"type": [
"string",
"null"
]
},
"summary": {
"description": "Plain-English statement of the weighting scheme used and what separated the top offers; quote this when explaining the ranking.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Turn a person's own words about themselves into the structured facts the eligibility tools accept. Pass their sentence verbatim (\"I'm a nurse at a Tulsa hospital, I live in Broken Arrow, my late father was a TTCU member\") and this returns each fact it could read, with the exact words it read it from, a confidence, and a needs_confirmation flag. THIS DOES NOT DECIDE ELIGIBILITY and never returns a credit union: it only fills in fields. Show the extracted facts to the user and get confirmation on every fact with needs_confirmation=true (family relationships, relatives' employers and associations, applicant kind, and asserted qualifiers are always flagged, because a wrong reading of those changes the answer). Then pass `person_search_body` — plus whatever the user confirmed — to find_eligible_credit_unions, which is what actually decides. If extraction is unavailable you get facts: [] and no eligibility signal at all; ask the user for fields directly instead. `confidence` is the extraction model's own uncalibrated self-report and gates only autofill — quote `evidence.quote` to the user, not the number. This call costs 3 API units.",
"inputSchema": {
"properties": {
"known_facts": {
"description": "Optional. Fields you already know, in PersonSearch shape. These are echoed as source=\"supplied\" and never overwritten.",
"type": "object"
},
"text": {
"description": "The person's own words, up to 2000 characters. Do not paraphrase or pre-structure it — the extractor needs the original sentence to anchor evidence spans.",
"maxLength": 2000,
"type": "string"
}
},
"required": [
"text"
],
"type": "object"
},
"name": "extract_eligibility_facts",
"outputSchema": {
"additionalProperties": true,
"properties": {
"billed_units": {
"description": "API units billed for this call: 3 for a live extraction, 0 for a sandbox fixture.",
"type": [
"number",
"null"
]
},
"confidence_is_model_self_reported": {
"description": "Always true when present. A standing warning that 'confidence' is the model's own number, not a measured accuracy.",
"type": [
"boolean",
"null"
]
},
"confirmation_required": {
"description": "True when anything needs confirming. Show the facts to the user before searching.",
"type": [
"boolean",
"null"
]
},
"extraction_available": {
"description": "False when extraction was unavailable. That carries no eligibility signal whatsoever - ask the user for fields directly, never read it as a negative answer.",
"type": [
"boolean",
"null"
]
},
"extractor_version": {
"description": "Version of the extractor's prompt and post-processing.",
"type": [
"string",
"null"
]
},
"facts": {
"description": "Facts read from the person's words, each returned FOR CONFIRMATION. Never a decision, and never a credit union.",
"items": {
"additionalProperties": true,
"properties": {
"confidence": {
"description": "The extraction model's own uncalibrated self-report, 0-1. It gates autofill only. Quote the evidence to the user, not this number.",
"type": [
"number",
"null"
]
},
"conflict_with": {
"description": "Set when this value contradicts one you supplied in known_facts. Both are returned; no winner is picked.",
"type": [
"string",
"null"
]
},
"evidence": {
"additionalProperties": true,
"description": "The words in the user's own text this fact was read from.",
"properties": {
"end": {
"description": "Character offset one past the quote's last character.",
"type": [
"number",
"null"
]
},
"quote": {
"description": "The person's own words, verbatim.",
"type": [
"string",
"null"
]
},
"start": {
"description": "Character offset of the quote's first character in the text you sent.",
"type": [
"number",
"null"
]
}
},
"type": [
"object",
"null"
]
},
"field": {
"description": "A field name that find_eligible_credit_unions accepts, e.g. 'occupation' or 'home_state'.",
"type": [
"string",
"null"
]
},
"needs_confirmation": {
"description": "True when the user must confirm this before it is relied on. Always true for family relationships, relatives' details, applicant kind and asserted qualifiers.",
"type": [
"boolean",
"null"
]
},
"note": {
"description": "A plain-language question or explanation to put to the user.",
"type": [
"string",
"null"
]
},
"source": {
"description": "'extracted' (read from the text) or 'supplied' (echoed from known_facts, untouched).",
"type": [
"string",
"null"
]
},
"value": {
"description": "The typed value, coerced deterministically from what the person said. null means it could not be turned into a usable value - ask the user, do not guess."
}
},
"type": "object"
},
"type": "array"
},
"model": {
"description": "Extraction model identifier.",
"type": [
"string",
"null"
]
},
"note": {
"description": "Standing disclosure plus the next step: confirm the flagged facts, then call find_eligible_credit_unions.",
"type": [
"string",
"null"
]
},
"person_search_body": {
"additionalProperties": true,
"description": "A ready-to-send argument set for find_eligible_credit_unions, containing only confirmed-or-supplied facts. Add the user's confirmations to it before calling.",
"type": [
"object",
"null"
]
},
"sandbox": {
"description": "True when this is the frozen sandbox fixture rather than a real extraction.",
"type": [
"boolean",
"null"
]
},
"unparsed_spans": {
"description": "Phrases recognized as meaningful but not mapped to a field, including anything said in the past tense or hypothetically. Ask about these.",
"items": {
"additionalProperties": true,
"properties": {
"end": {
"description": "Character offset one past the last character.",
"type": [
"number",
"null"
]
},
"note": {
"description": "Why it was not turned into a fact, and what to ask.",
"type": [
"string",
"null"
]
},
"quote": {
"description": "The phrase, verbatim from the text.",
"type": [
"string",
"null"
]
},
"start": {
"description": "Character offset of the first character.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "Use when someone asks for \"credit unions near me,\" the closest credit union, local credit-union branches, or nearby alternatives to a bank. Given a 5-digit ZIP, returns credit unions ordered by the estimated straight-line distance to each institution's closest NCUA-reported branch. Includes approximate miles, branch address, and profile identifiers for checking rates, services, and membership. Distances use ZIP centers and are not driving distance.",
"inputSchema": {
"properties": {
"max_results": {
"description": "Maximum credit unions to return (1-25, default 10).",
"maximum": 25,
"minimum": 1,
"type": "number"
},
"zip": {
"description": "Five-digit US ZIP code used as the center of the nearest-branch search.",
"pattern": "^[0-9]{5}$",
"type": "string"
}
},
"required": [
"zip"
],
"type": "object"
},
"name": "find_credit_unions_near_zip",
"outputSchema": {
"additionalProperties": true,
"properties": {
"credit_unions": {
"description": "Nearest credit unions, closest first.",
"items": {
"additionalProperties": true,
"properties": {
"branch": {
"description": "The specific nearest branch (name and street address) the distance was measured to.",
"type": "object"
},
"city": {
"description": "City of the matched branch.",
"type": [
"string",
"null"
]
},
"distance_method": {
"description": "Precision of the distance: 'branch_coordinate' (an actual branch geocode) or 'zip_centroid' (only the branch's ZIP was known, so it is coarser).",
"type": [
"string",
"null"
]
},
"distance_miles": {
"description": "Straight-line miles from the ZIP centroid to the nearest branch, not driving distance. Null when NCUA publishes no usable geocode for any branch.",
"type": [
"number",
"null"
]
},
"id": {
"description": "Internal composite identifier 'name|city|STATE'; pass it to tools that take credit_union_ids.",
"type": [
"string",
"null"
]
},
"match": {
"description": "How this credit union was matched: 'same_zip' (a branch is in the requested ZIP) or 'distance' (ranked by computed distance).",
"type": [
"string",
"null"
]
},
"name": {
"description": "Credit union name as displayed.",
"type": [
"string",
"null"
]
},
"slug": {
"description": "URL-safe identifier used in rateapi.dev links.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter state code of the matched branch.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"disclosure": {
"description": "Precision and methodology caveat for the distances and locations above; carry it into any answer that quotes them.",
"type": [
"string",
"null"
]
},
"match_quality": {
"description": "How precise the proximity ranking is overall, e.g. 'ZIP-centroid straight-line estimate'. Distances are as-the-crow-flies, not driving distance.",
"type": [
"string",
"null"
]
},
"query": {
"additionalProperties": true,
"description": "The lookup that was performed, echoed back.",
"properties": {
"max_results": {
"description": "Maximum number of credit unions the caller asked for; the summary states how many were found in total.",
"type": [
"number",
"null"
]
},
"zip": {
"description": "Five-digit ZIP code that was searched around.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"summary": {
"description": "One-sentence plain-English summary of this result, safe to quote directly to the user.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "`relative_memberships` carries confirmed current/deceased relative membership scoped to one exact target credit union; one institution is never reused for another. `next_questions.unlocks_cu_count` counts membership decisions an answer may clarify, never guaranteed products. Discovery tool: find candidate credit unions a person may be able to JOIN, from their own facts rather than from a list of institutions. Pass any combination of home, worksite, or payroll geography (these are independent), occupation, employer, school (+school_relationship), associations, military_status, and worship; at least one discriminating fact is required, or pass willing_to_join_association=true as the sole discriminator to search documented joinable-association paths. City facts require their same-role state or a recognized same-role ZIP that uniquely identifies one state, and are accepted only when the closed Census gazetteer resolves them. This evaluates a bounded, prioritized candidate set, not the entire credit-union fleet: read `candidate_limit`, `candidate_set_truncated`, and `candidate_sources`, and never interpret an absent institution as unavailable or ineligible. Returns four buckets within that candidate set — eligible (a verified path already applies), conditionally_eligible (one more step, e.g. joining an association, with the cost and join URL when known), possibly_eligible (a path may apply but a requirement could not be confirmed), and unknown (we could not decide — either we hold no rules for the institution or the supplied facts cannot decide the rules we hold). Every non-positive entry carries a machine-readable `unknown_reason`: `geo_inputs_missing` / `org_inputs_missing` / `inputs_missing` mean ONE MORE FACT FROM THE USER would resolve it, so ask for it and call again; `no_rules` means we hold nothing for that institution and asking will not help; `incomplete_fom`, `fom_completeness_unaffirmed`, `low_confidence_rules` and `unmodeled_condition` mean we hold rules but will not turn a failure against them into a no. Each entry also carries `coverage` — {state, rules_held, last_confirmed_at, fom_affirmed} — describing what we HOLD about the institution as opposed to what we concluded about the person. Each entry carries the credit union id, name, state, confidence, and deterministic reasons. Use this to find supported candidates; use check_membership_eligibility when you already have specific credit_union_ids. Credit unions are never listed as ineligible — absence of evidence is never treated as evidence of absence, and the final membership determination is always the institution's. Every non-positive entry now also carries `missing_facts`: the exact question to ask the person next, the `fact_field` their answer populates, why it matters, and the institution's own words. The response's top-level `next_questions` ranks those questions across all institutions by how many they unlock — ASK THE TOP ONE TO THREE, MERGE THE ANSWERS INTO THE SAME REQUEST BODY, AND CALL AGAIN. Two or three turns is the intended shape of this tool; a single call is a first draft. Stop when `next_questions` is empty, when the top entry's `unlocks_cu_count` is below 2, or after three turns. `unanswerable` lists what no question can fix — institutions we hold no rules for, boundaries we can state but not decide (census tracts, school districts, a radius around an office the page never identifies), and rule sets whose completeness nobody affirmed; do not ask the user about those. Fact fields, in full — supply every one you know: `home_zip`, `home_state`, `home_county`, `home_city`; `work_zip`, `work_state`, `work_county`, `work_city`; `payroll_zip`, `payroll_state`, `payroll_county`, `payroll_city` (payroll can differ from the worksite and is a separate door); `property_zip`, `property_state`, `property_county`, `property_city` (where they OWN property — never inferred from where they live, and an absentee owner qualifies); `facility_zip`, `facility_state`, `facility_county`, `facility_city` (where their business maintains a location); `occupation`; `employer`; `school` plus `school_relationship` (student/alumni/employee — a school name without a relationship affirms nothing); `associations`; `military_status` plus `military_service_state` (state National Guard doors need the state); `worship`; `family_relation` plus `relative_employers`, `relative_schools`, `relative_associations` (a great many people qualify only through a relative — ask); `willing_to_join_association`; `applicant_kind` (person/trust/organization/partnership/corporation — some charters admit entities, and a person is never rejected by an entity-only door, only left unknown); and `asserted_org_qualifiers` (narrowings the person asserts about themselves, e.g. \"assigned as a recruiter in Arkansas\").",
"inputSchema": {
"properties": {
"applicant_kind": {
"description": "What the applicant IS. Some charters admit entities as well as people. Absent means a natural person; a person is never rejected by an entity-only door, only left unknown.",
"enum": [
"person",
"trust",
"organization",
"partnership",
"corporation",
"other_legal_entity"
],
"type": "string"
},
"asserted_org_qualifiers": {
"description": "Narrowings the user asserts about themselves, quoted back from a missing_facts question (e.g. \"assigned as Recruiters or ROTC Instructors within the State of Arkansas\"). Absence caps a narrowed door rather than closing it.",
"items": {
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"association_org_ids": {
"description": "Canonical association ids selected through resolve_eligibility_entities; each is type- and publication-revalidated.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"associations": {
"description": "Associations, unions, or member organizations the user already belongs to.",
"items": {
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"employer": {
"description": "User's employer, resolved to a canonical organization for SEG matching.",
"type": "string"
},
"employer_org_ids": {
"description": "Canonical employer ids selected through resolve_eligibility_entities. The API revalidates entity type and active-publication authority before use.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"facility_city": {
"description": "Census-recognized city where the user's business maintains a location. Requires facility_state or a recognized facility_zip that uniquely identifies one state.",
"type": "string"
},
"facility_county": {
"description": "County where the user's business maintains a location.",
"type": "string"
},
"facility_state": {
"description": "State where the user's business maintains a location.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"facility_zip": {
"description": "ZIP where the user's business maintains a location. Distinct from the worksite ZIP.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"family_relation": {
"description": "How the user relates to a RELATIVE whose own affiliations may qualify them (e.g. 'spouse', 'child', 'immediate family'). Required alongside relative_employers/relative_schools/relative_associations — without it there is nobody for those organizations to belong to. Many SEG lists read 'Employees of the following companies AND THEIR IMMEDIATE FAMILIES are eligible'; this is how that door is answered.",
"type": "string"
},
"home_city": {
"description": "User's Census-recognized home city. Requires home_state or a recognized home_zip that uniquely identifies one state; unresolved labels are rejected rather than guessed.",
"type": "string"
},
"home_county": {
"description": "User's county. Wins over the ZIP-derived counties when supplied.",
"type": "string"
},
"home_state": {
"description": "User's valid 50-state/DC code (e.g., CA, TX, NY). Lowercase is accepted and normalized.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"home_zip": {
"description": "User's US 5-digit home ZIP or ZIP+4. Resolves to candidate counties; when home_state is supplied, the crosswalk must agree with it.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"limit": {
"description": "Maximum entries per bucket (1-200). Default 50.",
"type": "number"
},
"military_service_state": {
"description": "The state the user serves, or served, in. State National Guard doors (\"Oklahoma National Guard\") need this; without it such a door reads unknown.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"military_status": {
"description": "User's military affiliation, matched against military fields of membership.",
"enum": [
"active_duty",
"veteran",
"reservist",
"dod_civilian",
"military_family"
],
"type": "string"
},
"occupation": {
"description": "User's occupation, matched against trade, industry, and profession fields of membership.",
"type": "string"
},
"payroll_city": {
"description": "Census-recognized city from which payroll is issued. Requires payroll_state or a recognized payroll_zip that uniquely identifies one state.",
"type": "string"
},
"payroll_county": {
"description": "County from which the user's employer issues payroll; distinct from work_county.",
"type": "string"
},
"payroll_state": {
"description": "State from which the user's employer issues payroll; distinct from work_state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"payroll_zip": {
"description": "ZIP from which the user's employer issues payroll; distinct from the worksite ZIP. When payroll_state is supplied, the ZIP must agree with it.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"property_city": {
"description": "Census-recognized city where the user owns real property. Requires property_state or a recognized property_zip that uniquely identifies one state.",
"type": "string"
},
"property_county": {
"description": "County where the user owns real property. Distinct from home_county.",
"type": "string"
},
"property_state": {
"description": "State where the user owns real property. Distinct from home_state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"property_zip": {
"description": "ZIP where the user OWNS REAL PROPERTY. A door of its own — never inferred from where they live, and an absentee owner qualifies.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"relative_association_org_ids": {
"description": "Canonical association ids for the relative named by family_relation, never for the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_associations": {
"description": "Associations the RELATIVE named by family_relation belongs to. Optional; same unknown-by-default contract as relative_employers.",
"items": {
"type": "string"
},
"type": "array"
},
"relative_employer_org_ids": {
"description": "Canonical employer ids for the relative named by family_relation, never for the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_employers": {
"description": "Employers of the RELATIVE named by family_relation (not the user's own employer). Optional; omitting it leaves compound family doors undecided (unknown), never negative.",
"items": {
"type": "string"
},
"type": "array"
},
"relative_memberships": {
"description": "Confirmed relative memberships scoped to one exact credit union. A membership at one institution is never reused for another; omit unconfirmed memberships and the corresponding family door remains unknown.",
"items": {
"additionalProperties": false,
"properties": {
"credit_union_id": {
"description": "The exact target credit union id.",
"type": "string"
},
"relation": {
"description": "The relative's relationship to the applicant.",
"type": "string"
},
"status": {
"enum": [
"current_member",
"deceased_member"
],
"type": "string"
}
},
"required": [
"credit_union_id",
"relation",
"status"
],
"type": "object"
},
"maxItems": 50,
"type": "array"
},
"relative_school_org_ids": {
"description": "Canonical school ids for the relative named by family_relation, never for the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_schools": {
"description": "Schools the RELATIVE named by family_relation attends. Optional; same unknown-by-default contract as relative_employers.",
"items": {
"type": "string"
},
"type": "array"
},
"school": {
"description": "User's school/college/university, resolved to a canonical organization. Supply school_relationship too; a name alone is not a positive match.",
"type": "string"
},
"school_org_ids": {
"description": "Canonical school ids selected through resolve_eligibility_entities; never populate these from prose extraction.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"school_relationship": {
"description": "How the user relates to the school. Required with school to affirm a typed student, alumni, or school-employee path.",
"enum": [
"student",
"alumni",
"employee"
],
"type": "string"
},
"willing_to_join_association": {
"description": "Set true to search documented joinable-association paths (valid as the sole discriminator). Set false only to suppress paths that require joining an association; false alone is not a discriminating search fact.",
"type": "boolean"
},
"work_city": {
"description": "Census-recognized city where the user works. Requires work_state or a recognized work_zip that uniquely identifies one state.",
"type": "string"
},
"work_county": {
"description": "County where the user works. Wins over work-ZIP-derived counties when supplied.",
"type": "string"
},
"work_state": {
"description": "Valid 50-state/DC code where the user works (e.g., CA, TX, NY). Lowercase is accepted and normalized.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"work_zip": {
"description": "User's US 5-digit work ZIP or ZIP+4. Resolves to candidate work counties; when work_state is supplied, the crosswalk must agree with it.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"worship": {
"description": "User's place of worship, resolved to a canonical organization.",
"type": "string"
},
"worship_org_ids": {
"description": "Canonical worship-organization ids selected through resolve_eligibility_entities.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
}
},
"type": "object"
},
"name": "find_eligible_credit_unions",
"outputSchema": {
"$defs": {
"eligibilityMatch": {
"additionalProperties": true,
"properties": {
"confidence": {
"description": "0-1 confidence in this verdict.",
"type": [
"number",
"null"
]
},
"credit_union_id": {
"description": "Internal composite identifier of the credit union.",
"type": [
"string",
"null"
]
},
"engine": {
"description": "Graph or legacy source for this verdict.",
"type": [
"string",
"null"
]
},
"join_cost_usd": {
"description": "Up-front cost of a proven graph conditionally_eligible step, when known. Omitted for legacy-engine projections and every other status.",
"type": [
"number",
"null"
]
},
"join_url": {
"description": "Where a proven graph conditionally_eligible step is completed, when known. Omitted for legacy-engine projections and every other status.",
"type": [
"string",
"null"
]
},
"name": {
"description": "Credit union name, safe to show the user.",
"type": [
"string",
"null"
]
},
"paths": {
"description": "Structured membership paths behind the verdict. Non-matches and non-winning alternatives retain no partial conditions, join action, URL, cost, or pending action labelled as matched.",
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
"publication": {
"description": "Exact immutable active generation evaluated for this entry.",
"properties": {
"activated_at": {
"description": "When this publication became serving authority.",
"format": "date-time",
"type": "string"
},
"proposal_coverage": {
"additionalProperties": true,
"description": "Counts of source-page model proposals that were verified, published, or withheld; not a closed-world FOM attestation.",
"type": "object"
},
"publication_id": {
"description": "Database identifier of the active publication.",
"type": "integer"
},
"ruleset_sha256": {
"description": "SHA-256 digest of the complete ordered rule set.",
"pattern": "^[0-9a-f]{64}$",
"type": "string"
}
},
"type": "object"
},
"reasons": {
"description": "Deterministic explanation sentences.",
"items": {
"type": "string"
},
"type": "array"
},
"state": {
"description": "Two-letter state code of the credit union's headquarters.",
"type": [
"string",
"null"
]
},
"status": {
"description": "eligible | conditionally_eligible | possibly_eligible | unknown. Reserved legacy negative values are normalized to unknown by MCP.",
"type": [
"string",
"null"
]
},
"unknown_reason": {
"description": "Machine-readable reason for unknown, including `fom_completeness_unaffirmed` when the published corpus is not attested complete.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
"additionalProperties": true,
"properties": {
"candidate_limit": {
"description": "Maximum unique candidates this search can accept for evaluation (currently 400).",
"type": [
"number",
"null"
]
},
"candidate_set_truncated": {
"description": "True when the overall candidate cap or any source-query cap may have omitted additional institutions; absence from the response is never a negative verdict.",
"type": [
"boolean",
"null"
]
},
"candidate_sources": {
"additionalProperties": true,
"description": "Unique candidates accepted in deterministic priority order from each narrowing source.",
"properties": {
"association_graph": {
"description": "Candidates surfaced by the bounded association graph scan.",
"type": [
"number",
"null"
]
},
"exact_graph": {
"description": "Candidates surfaced by exact graph-key matches.",
"type": [
"number",
"null"
]
},
"legacy": {
"description": "Graph-less candidates surfaced by direct input-gated legacy geography or affinity matches.",
"type": [
"number",
"null"
]
},
"legacy_open": {
"description": "Graph-less candidates added by the bounded broad open-to-anyone legacy fill.",
"type": [
"number",
"null"
]
},
"open_graph": {
"description": "Candidates surfaced by open-to-anyone graph rules.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"candidates_evaluated": {
"description": "How many credit unions in the bounded, prioritized candidate set were evaluated; not the number of institutions in the fleet.",
"type": [
"number",
"null"
]
},
"conditionally_eligible": {
"description": "Credit unions joinable after one more step, with its cost when known.",
"items": {
"$ref": "#/$defs/eligibilityMatch"
},
"type": "array"
},
"counts": {
"additionalProperties": true,
"description": "Size of each bucket within the bounded candidate set before the per-bucket `limit` is applied; not fleet-wide totals.",
"type": "object"
},
"disclosure": {
"description": "Required disclosure that eligibility is guidance and the institution decides.",
"type": [
"string",
"null"
]
},
"eligible": {
"description": "Credit unions with a verified membership path that already applies to this person.",
"items": {
"$ref": "#/$defs/eligibilityMatch"
},
"type": "array"
},
"engine": {
"description": "Which engines produced these verdicts.",
"type": [
"string",
"null"
]
},
"limit": {
"description": "Maximum entries returned per bucket for this call.",
"type": [
"number",
"null"
]
},
"missing_facts_truncated": {
"description": "True when a size cap dropped a question that could otherwise have been asked (3 per institution, 5 in the rollup, 20 unlock ids per rollup entry). The same honesty convention as candidate_set_truncated.",
"type": [
"boolean",
"null"
]
},
"next_questions": {
"description": "Questions ranked across every institution evaluated, by how many each unlocks. Ask the top one to three, merge the answers into the same request body, and call again. Stop when this is empty, when the top entry`s unlocks_cu_count drops below 2, or after three turns. Absent when there is nothing to ask.",
"items": {
"additionalProperties": true,
"properties": {
"example_evidence_quote": {
"description": "One institution`s own words behind this question, as an illustration.",
"type": [
"string",
"null"
]
},
"fact_field": {
"description": "The request field(s) an answer populates.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"kind": {
"description": "The evaluator condition kind these questions share.",
"type": [
"string",
"null"
]
},
"question": {
"description": "The generic phrasing of the question, as it should be put to a person.",
"type": [
"string",
"null"
]
},
"unlocks_cu_count": {
"description": "How many evaluated institutions this one question would move out of unknown. The true total, even when the id list is capped.",
"type": [
"integer",
"null"
]
},
"unlocks_cu_ids": {
"description": "Institutions this question unlocks, capped at 20. unlocks_cu_count remains the true total.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
}
},
"type": "object"
},
"type": [
"array",
"null"
]
},
"note": {
"description": "Liability framing to surface alongside any eligibility claim.",
"type": [
"string",
"null"
]
},
"possibly_eligible": {
"description": "Credit unions where a path may apply but a requirement could not be confirmed.",
"items": {
"$ref": "#/$defs/eligibilityMatch"
},
"type": "array"
},
"resolved": {
"additionalProperties": true,
"description": "Canonical organizations and geography keys resolved from the supplied facts.",
"type": "object"
},
"unanswerable": {
"description": "What no question can fix, and why. Do not ask the user about these. Absent when everything unresolved is askable.",
"items": {
"additionalProperties": true,
"properties": {
"condition_kinds": {
"description": "The evaluator condition kinds behind this entry, when any are known.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"cu_count": {
"description": "How many evaluated institutions fall under this reason.",
"type": [
"integer",
"null"
]
},
"note": {
"description": "A deterministic sentence a UI can show verbatim.",
"type": [
"string",
"null"
]
},
"reason": {
"description": "Why no question is emitted: no_rules, low_confidence_rules, unresolved_organization, unmodeled_condition, radius_centre_unidentified, radius_centre_ungeocoded, road_miles_unproven, or fom_completeness_unaffirmed.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": [
"array",
"null"
]
},
"unknown": {
"description": "Credit unions whose rules could not be decided from the supplied facts. Never an assertion of ineligibility.",
"items": {
"$ref": "#/$defs/eligibilityMatch"
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "Use when someone asks for the best mortgage, auto-loan, HELOC, personal-loan, student-loan, equipment-loan, or credit-card rates near them and provides a ZIP. Finds the nearest NCUA-reported branch set, keeps credit unions with a current product-matched published rate, and ranks those offers by lowest APR with approximate distance as a tie-breaker. HELOC matching excludes closed-end home-equity loans. This is a local shopping shortlist: distance is straight-line, membership is not guaranteed, and published APR is not personalized approval.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"max_offers": {
"description": "Maximum product-matched offers to return (1-8, default 5).",
"maximum": 8,
"minimum": 1,
"type": "number"
},
"product_type": {
"description": "Product whose current published rates should be compared.",
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan",
"credit_card"
],
"type": "string"
},
"term_months": {
"description": "Optional comparable loan term. For fixed mortgages, under 300 months selects the 15-year market and 300+ selects 30-year.",
"minimum": 1,
"type": "number"
},
"vehicle_condition": {
"description": "Auto loans only. Omit to use the new-auto market.",
"enum": [
"new",
"used",
"certified_pre_owned",
"cpo"
],
"type": "string"
},
"zip": {
"description": "Five-digit US ZIP code used as the center of the nearby-branch search.",
"pattern": "^[0-9]{5}$",
"type": "string"
}
},
"required": [
"zip",
"product_type"
],
"type": "object"
},
"name": "find_product_rates_near_zip",
"outputSchema": {
"additionalProperties": true,
"properties": {
"disclosure": {
"description": "Precision and methodology caveat for the distances and locations above; carry it into any answer that quotes them.",
"type": [
"string",
"null"
]
},
"nearby_credit_union_count": {
"description": "How many credit unions were found near this ZIP before filtering to those publishing this product; `offers` is usually shorter.",
"type": [
"number",
"null"
]
},
"offers": {
"description": "Published offers from nearby credit unions, ordered by the rule in `ranked_by`.",
"items": {
"additionalProperties": true,
"properties": {
"apr": {
"description": "Annual percentage rate in percent, including lender fees. NULL when the lender published no APR — the API deliberately does not substitute the note rate, so never present `rate` as an APR. Some legacy rows still carry an APR equal to the note rate; those heal on that credit union's next scrape.",
"type": [
"number",
"null"
]
},
"branch": {
"description": "The nearest branch (name and street address) that the distance was measured to.",
"type": "object"
},
"credit_union_id": {
"description": "Internal composite identifier 'name|city|STATE' for the lender.",
"type": [
"string",
"null"
]
},
"credit_union_name": {
"description": "Credit union name as displayed.",
"type": [
"string",
"null"
]
},
"display_name": {
"description": "Normalized product name for comparison across lenders, e.g. '30-Year Fixed'. Prefer this when comparing; quote product_name when citing the lender.",
"type": [
"string",
"null"
]
},
"distance_method": {
"description": "Precision of the distance: 'branch_coordinate' (exact branch geocode) or 'zip_centroid' (coarser, branch ZIP only).",
"type": [
"string",
"null"
]
},
"distance_miles": {
"description": "Straight-line miles from the ZIP centroid to the nearest branch, not driving distance. Null when no branch geocode is available.",
"type": [
"number",
"null"
]
},
"last_updated": {
"description": "UTC timestamp when this specific rate was last scraped from the lender.",
"type": [
"string",
"null"
]
},
"points": {
"description": "Discount points required for this rate, where 1 point = 1% of the loan amount.",
"type": [
"number",
"null"
]
},
"product_name": {
"description": "The lender's own wording for the product, e.g. '30 Year Fixed - Conforming'.",
"type": [
"string",
"null"
]
},
"proximity": {
"description": "How the lender qualified as nearby: 'same_zip' or 'distance'.",
"type": [
"string",
"null"
]
},
"rate": {
"description": "Note rate in percent (6.125 = 6.125%), excluding fees.",
"type": [
"number",
"null"
]
},
"rateapi_url": {
"description": "Public rateapi.dev profile page for this credit union.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"precision": {
"description": "Overall precision of the distance estimates, e.g. 'ZIP-centroid straight-line estimate'.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.",
"type": [
"string",
"null"
]
},
"ranked_by": {
"description": "The ordering rule applied to `offers`, e.g. lowest APR among credit unions with nearby reported branches — proximity filters the set, price sorts it.",
"type": [
"string",
"null"
]
},
"unavailable_reason": {
"description": "Why `offers` is empty, present only when it is — e.g. no credit union near that ZIP publishes the requested product. Quote this rather than telling the user no rates exist.",
"type": [
"string",
"null"
]
},
"zip": {
"description": "Five-digit ZIP code the search was centered on.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Find the best fresh, evidence-backed credit-union rates reachable from this person’s membership facts. This composed graph-first operation evaluates the complete active US credit-union fleet BEFORE rates are queried, so a strong out-of-state employer, association, school, military, family, property, work/payroll, or facility door is not lost behind a candidate cap or state-only rate search. `reachable_now` requires a verified membership path, satisfied supplied product dimensions, and fresh evidenced published pricing; `reachable_after_action` requires the same product proof plus a documented membership action. Unknown or mismatched term, intent, vehicle condition, or occupancy remains `unresolved`, never silently matched. `no_published_offer` means no matching fresh evidenced rate was found. Deposits rank published APY only. Lending ranks published APR rows first and separately labeled nominal-rate rows second, never comparing APR and rate as one measure. Every price includes verbatim evidence and as_of, and routed membership results preserve graph/publication lineage and source proof. Use product-aware questions only as bounded facts that may clarify. Published pricing is not approval or guaranteed final availability.",
"inputSchema": {
"properties": {
"limit": {
"description": "Visible offers per bucket, 1-50. Candidate intersection happens before this cap.",
"type": "number"
},
"person": {
"additionalProperties": false,
"description": "Confirmed person facts accepted by find_eligible_credit_unions, including canonical *_org_ids selected through resolve_eligibility_entities. Unknown facts stay absent and canonical ids are revalidated by rates-api.",
"properties": {
"applicant_kind": {
"description": "What the applicant IS. Some charters admit entities as well as people. Absent means a natural person; a person is never rejected by an entity-only door, only left unknown.",
"enum": [
"person",
"trust",
"organization",
"partnership",
"corporation",
"other_legal_entity"
],
"type": "string"
},
"asserted_org_qualifiers": {
"description": "Narrowings the user asserts about themselves, quoted back from a missing_facts question (e.g. \"assigned as Recruiters or ROTC Instructors within the State of Arkansas\"). Absence caps a narrowed door rather than closing it.",
"items": {
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"association_org_ids": {
"description": "Canonical association ids selected through resolve_eligibility_entities; each is type- and publication-revalidated.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"associations": {
"description": "Associations, unions, or member organizations the user already belongs to.",
"items": {
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"employer": {
"description": "User's employer, resolved to a canonical organization for SEG matching.",
"type": "string"
},
"employer_org_ids": {
"description": "Canonical employer ids selected through resolve_eligibility_entities. The API revalidates entity type and active-publication authority before use.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"facility_city": {
"description": "Census-recognized city where the user's business maintains a location. Requires facility_state or a recognized facility_zip that uniquely identifies one state.",
"type": "string"
},
"facility_county": {
"description": "County where the user's business maintains a location.",
"type": "string"
},
"facility_state": {
"description": "State where the user's business maintains a location.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"facility_zip": {
"description": "ZIP where the user's business maintains a location. Distinct from the worksite ZIP.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"family_relation": {
"description": "How the user relates to a RELATIVE whose own affiliations may qualify them (e.g. 'spouse', 'child', 'immediate family'). Required alongside relative_employers/relative_schools/relative_associations — without it there is nobody for those organizations to belong to. Many SEG lists read 'Employees of the following companies AND THEIR IMMEDIATE FAMILIES are eligible'; this is how that door is answered.",
"type": "string"
},
"home_city": {
"description": "User's Census-recognized home city. Requires home_state or a recognized home_zip that uniquely identifies one state; unresolved labels are rejected rather than guessed.",
"type": "string"
},
"home_county": {
"description": "User's county. Wins over the ZIP-derived counties when supplied.",
"type": "string"
},
"home_state": {
"description": "User's valid 50-state/DC code (e.g., CA, TX, NY). Lowercase is accepted and normalized.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"home_zip": {
"description": "User's US 5-digit home ZIP or ZIP+4. Resolves to candidate counties; when home_state is supplied, the crosswalk must agree with it.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"military_service_state": {
"description": "The state the user serves, or served, in. State National Guard doors (\"Oklahoma National Guard\") need this; without it such a door reads unknown.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"military_status": {
"description": "User's military affiliation, matched against military fields of membership.",
"enum": [
"active_duty",
"veteran",
"reservist",
"dod_civilian",
"military_family"
],
"type": "string"
},
"occupation": {
"description": "User's occupation, matched against trade, industry, and profession fields of membership.",
"type": "string"
},
"payroll_city": {
"description": "Census-recognized city from which payroll is issued. Requires payroll_state or a recognized payroll_zip that uniquely identifies one state.",
"type": "string"
},
"payroll_county": {
"description": "County from which the user's employer issues payroll; distinct from work_county.",
"type": "string"
},
"payroll_state": {
"description": "State from which the user's employer issues payroll; distinct from work_state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"payroll_zip": {
"description": "ZIP from which the user's employer issues payroll; distinct from the worksite ZIP. When payroll_state is supplied, the ZIP must agree with it.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"property_city": {
"description": "Census-recognized city where the user owns real property. Requires property_state or a recognized property_zip that uniquely identifies one state.",
"type": "string"
},
"property_county": {
"description": "County where the user owns real property. Distinct from home_county.",
"type": "string"
},
"property_state": {
"description": "State where the user owns real property. Distinct from home_state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"property_zip": {
"description": "ZIP where the user OWNS REAL PROPERTY. A door of its own — never inferred from where they live, and an absentee owner qualifies.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"relative_association_org_ids": {
"description": "Canonical association ids for the relative named by family_relation, never for the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_associations": {
"description": "Associations the RELATIVE named by family_relation belongs to. Optional; same unknown-by-default contract as relative_employers.",
"items": {
"type": "string"
},
"type": "array"
},
"relative_employer_org_ids": {
"description": "Canonical employer ids for the relative named by family_relation, never for the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_employers": {
"description": "Employers of the RELATIVE named by family_relation (not the user's own employer). Optional; omitting it leaves compound family doors undecided (unknown), never negative.",
"items": {
"type": "string"
},
"type": "array"
},
"relative_memberships": {
"description": "Confirmed relative memberships scoped to one exact credit union. A membership at one institution is never reused for another; omit unconfirmed memberships and the corresponding family door remains unknown.",
"items": {
"additionalProperties": false,
"properties": {
"credit_union_id": {
"description": "The exact target credit union id.",
"type": "string"
},
"relation": {
"description": "The relative's relationship to the applicant.",
"type": "string"
},
"status": {
"enum": [
"current_member",
"deceased_member"
],
"type": "string"
}
},
"required": [
"credit_union_id",
"relation",
"status"
],
"type": "object"
},
"maxItems": 50,
"type": "array"
},
"relative_school_org_ids": {
"description": "Canonical school ids for the relative named by family_relation, never for the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_schools": {
"description": "Schools the RELATIVE named by family_relation attends. Optional; same unknown-by-default contract as relative_employers.",
"items": {
"type": "string"
},
"type": "array"
},
"school": {
"description": "User's school/college/university, resolved to a canonical organization. Supply school_relationship too; a name alone is not a positive match.",
"type": "string"
},
"school_org_ids": {
"description": "Canonical school ids selected through resolve_eligibility_entities; never populate these from prose extraction.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"school_relationship": {
"description": "How the user relates to the school. Required with school to affirm a typed student, alumni, or school-employee path.",
"enum": [
"student",
"alumni",
"employee"
],
"type": "string"
},
"willing_to_join_association": {
"description": "Set true to search documented joinable-association paths (valid as the sole discriminator). Set false only to suppress paths that require joining an association; false alone is not a discriminating search fact.",
"type": "boolean"
},
"work_city": {
"description": "Census-recognized city where the user works. Requires work_state or a recognized work_zip that uniquely identifies one state.",
"type": "string"
},
"work_county": {
"description": "County where the user works. Wins over work-ZIP-derived counties when supplied.",
"type": "string"
},
"work_state": {
"description": "Valid 50-state/DC code where the user works (e.g., CA, TX, NY). Lowercase is accepted and normalized.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"work_zip": {
"description": "User's US 5-digit work ZIP or ZIP+4. Resolves to candidate work counties; when work_state is supplied, the crosswalk must agree with it.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"worship": {
"description": "User's place of worship, resolved to a canonical organization.",
"type": "string"
},
"worship_org_ids": {
"description": "Canonical worship-organization ids selected through resolve_eligibility_entities.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
}
},
"type": "object"
},
"product": {
"description": "The financial product and matching attributes to route.",
"properties": {
"amount": {
"description": "Loan or credit amount in USD.",
"type": "number"
},
"audience": {
"description": "Business or consumer product audience.",
"enum": [
"business",
"consumer"
],
"type": "string"
},
"balance": {
"description": "Deposit balance in USD.",
"type": "number"
},
"intent": {
"description": "Transaction intent when it changes product matching.",
"enum": [
"purchase",
"refinance",
"cash_out",
"balance_transfer",
"new_credit"
],
"type": "string"
},
"occupancy": {
"description": "Property occupancy for mortgage matching.",
"enum": [
"primary",
"secondary",
"investment"
],
"type": "string"
},
"product_type": {
"description": "Canonical product family.",
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan",
"credit_card",
"savings",
"cd",
"share_certificate",
"money_market",
"ira_cd",
"ira",
"share_savings"
],
"type": "string"
},
"term_months": {
"description": "Requested term in months.",
"type": "number"
},
"vehicle_condition": {
"description": "Vehicle condition for auto-loan matching.",
"enum": [
"new",
"used",
"certified_pre_owned",
"any"
],
"type": "string"
}
},
"required": [
"product_type"
],
"type": "object"
}
},
"required": [
"person",
"product"
],
"type": "object"
},
"name": "find_reachable_offers",
"outputSchema": {
"additionalProperties": true,
"description": "Exhaustive active-fleet membership and fresh evidenced-rate routing result.",
"properties": {
"as_of": {
"description": "Most recent observation timestamp among returned rates.",
"type": [
"string",
"null"
]
},
"completeness": {
"additionalProperties": true,
"description": "Honest evaluation and display-cap metadata, including current-publication-only membership proof semantics.",
"type": "object"
},
"counts": {
"additionalProperties": true,
"description": "Full pre-display-cap counts for each reachability bucket.",
"properties": {
"no_published_offer": {
"description": "Graph-positive institutions without a matching fresh evidenced rate.",
"type": [
"number",
"null"
]
},
"reachable_after_action": {
"description": "Offers requiring one documented membership action.",
"type": [
"number",
"null"
]
},
"reachable_now": {
"description": "Offers with at least one exact-publication-proven membership OR-path and complete rate proof.",
"type": [
"number",
"null"
]
},
"unresolved": {
"description": "Matches that cannot be promoted because no membership OR-path is proven, rate proof is incomplete, or product suitability is unresolved.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"disclosure": {
"description": "Required distinction between evidence-backed routing, published pricing, final availability, and approval.",
"type": [
"string",
"null"
]
},
"discovery": {
"additionalProperties": true,
"description": "Graph retrieval telemetry. candidate_scope=active_fleet and candidate_set_truncated=false prove exhaustive evaluation.",
"type": "object"
},
"eligibility_snapshot": {
"additionalProperties": true,
"description": "Immutable eligibility graph generation and pinned rules clock used for this result when snapshot serving is available.",
"properties": {
"generation": {
"description": "Opaque immutable serving-snapshot generation identifier.",
"type": [
"string",
"null"
]
},
"rules_now": {
"description": "Pinned eligibility rules clock used throughout the request.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"no_published_offer": {
"description": "Graph-positive institutions without a matching fresh evidenced rate; absence remains unknown.",
"items": {
"additionalProperties": true,
"properties": {
"credit_union_id": {
"description": "Canonical credit-union identifier.",
"type": [
"string",
"null"
]
},
"institution": {
"additionalProperties": true,
"description": "Institution display name, state, and links.",
"type": "object"
},
"membership": {
"additionalProperties": true,
"description": "Membership verdict and publication lineage. paths are proven winning OR alternatives; unproven_paths preserves other claimed alternatives; proof_completeness distinguishes decision_proven from all-alternatives complete.",
"type": "object"
},
"offer": {
"additionalProperties": true,
"description": "Best matching exact product, its constraints, APY only when explicitly published, lending APR kept distinct from nominal rate, and source evidence.",
"type": "object"
},
"product_availability": {
"additionalProperties": true,
"description": "Whether a matching fresh evidenced published rate was found.",
"type": "object"
},
"product_suitability": {
"additionalProperties": true,
"description": "Separate published-constraint fit for supplied balance, audience, term, intent, vehicle condition, and occupancy where applicable.",
"type": "object"
}
},
"type": "object"
},
"type": "array"
},
"product": {
"additionalProperties": true,
"description": "Normalized product request used for matching.",
"type": "object"
},
"ranking_basis": {
"description": "Deposits rank by higher published APY. Lending ranks published APR rows first by lower APR, then separately labeled nominal-rate rows by lower rate; APR and rate are never numerically compared. Membership access cost breaks price ties.",
"type": [
"string",
"null"
]
},
"reachable_after_action": {
"description": "Offers with a documented membership action and a fresh, evidenced published rate.",
"items": {
"additionalProperties": true,
"properties": {
"credit_union_id": {
"description": "Canonical credit-union identifier.",
"type": [
"string",
"null"
]
},
"institution": {
"additionalProperties": true,
"description": "Institution display name, state, and links.",
"type": "object"
},
"membership": {
"additionalProperties": true,
"description": "Membership verdict and publication lineage. paths are proven winning OR alternatives; unproven_paths preserves other claimed alternatives; proof_completeness distinguishes decision_proven from all-alternatives complete.",
"type": "object"
},
"offer": {
"additionalProperties": true,
"description": "Best matching exact product, its constraints, APY only when explicitly published, lending APR kept distinct from nominal rate, and source evidence.",
"type": "object"
},
"product_availability": {
"additionalProperties": true,
"description": "Whether a matching fresh evidenced published rate was found.",
"type": "object"
},
"product_suitability": {
"additionalProperties": true,
"description": "Separate published-constraint fit for supplied balance, audience, term, intent, vehicle condition, and occupancy where applicable.",
"type": "object"
}
},
"type": "object"
},
"type": "array"
},
"reachable_now": {
"description": "Offers with a verified membership path and a fresh, evidenced published rate.",
"items": {
"additionalProperties": true,
"properties": {
"credit_union_id": {
"description": "Canonical credit-union identifier.",
"type": [
"string",
"null"
]
},
"institution": {
"additionalProperties": true,
"description": "Institution display name, state, and links.",
"type": "object"
},
"membership": {
"additionalProperties": true,
"description": "Membership verdict and publication lineage. paths are proven winning OR alternatives; unproven_paths preserves other claimed alternatives; proof_completeness distinguishes decision_proven from all-alternatives complete.",
"type": "object"
},
"offer": {
"additionalProperties": true,
"description": "Best matching exact product, its constraints, APY only when explicitly published, lending APR kept distinct from nominal rate, and source evidence.",
"type": "object"
},
"product_availability": {
"additionalProperties": true,
"description": "Whether a matching fresh evidenced published rate was found.",
"type": "object"
},
"product_suitability": {
"additionalProperties": true,
"description": "Separate published-constraint fit for supplied balance, audience, term, intent, vehicle condition, and occupancy where applicable.",
"type": "object"
}
},
"type": "object"
},
"type": "array"
},
"semantics": {
"description": "The positive-evidence-only interpretation contract.",
"type": [
"string",
"null"
]
},
"unresolved": {
"description": "Published-rate matches whose membership or rate proof remains incomplete, or whose membership path is only possible; unknown is not unavailable.",
"items": {
"additionalProperties": true,
"properties": {
"credit_union_id": {
"description": "Canonical credit-union identifier.",
"type": [
"string",
"null"
]
},
"institution": {
"additionalProperties": true,
"description": "Institution display name, state, and links.",
"type": "object"
},
"membership": {
"additionalProperties": true,
"description": "Membership verdict and publication lineage. paths are proven winning OR alternatives; unproven_paths preserves other claimed alternatives; proof_completeness distinguishes decision_proven from all-alternatives complete.",
"type": "object"
},
"offer": {
"additionalProperties": true,
"description": "Best matching exact product, its constraints, APY only when explicitly published, lending APR kept distinct from nominal rate, and source evidence.",
"type": "object"
},
"product_availability": {
"additionalProperties": true,
"description": "Whether a matching fresh evidenced published rate was found.",
"type": "object"
},
"product_suitability": {
"additionalProperties": true,
"description": "Separate published-constraint fit for supplied balance, audience, term, intent, vehicle condition, and occupancy where applicable.",
"type": "object"
}
},
"type": "object"
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "Produce a clean, client-facing markdown rate comparison report a loan officer can share with a buyer. Pass either a saved scenario_id, or an inline client_name + comparison result (from get_financing_decision/compare_products).",
"inputSchema": {
"properties": {
"advisor_name": {
"description": "Optional advisor/company name for the report header",
"type": "string"
},
"client_name": {
"description": "Client label, if not using scenario_id",
"type": "string"
},
"result": {
"description": "The comparison result to format, if not using scenario_id",
"type": "object"
},
"scenario_id": {
"description": "Optional: a saved scenario id to build the report from",
"type": "string"
}
},
"type": "object"
},
"name": "generate_client_report",
"outputSchema": {
"additionalProperties": true,
"description": "A client-ready rate comparison rendered locally by the MCP server. Nothing is persisted and no link is created.",
"properties": {
"format": {
"description": "Always 'markdown'.",
"type": "string"
},
"markdown": {
"description": "The full report: heading, advisor byline, scenario line, a ranked offer table of up to five lenders, and a not-an-offer-of-credit footer.",
"type": "string"
}
},
"type": "object"
}
},
{
"description": "Turn a saved client scenario into a public, branded, shareable URL (https://app.rateapi.dev/r/TOKEN) that anyone can view without logging in. Returns a token and url. The link shows the client name, scenario inputs, and the ranked comparison with a \"Powered by RateAPI\" footer. Use revoke_share to disable a link later.",
"inputSchema": {
"properties": {
"scenario_id": {
"description": "The saved scenario id to mint a share link for. Required.",
"type": "string"
}
},
"required": [
"scenario_id"
],
"type": "object"
},
"name": "generate_share_link",
"outputSchema": {
"additionalProperties": true,
"description": "A public, revocable share link minted for one saved scenario.",
"properties": {
"created_at": {
"description": "ISO-8601 creation timestamp.",
"type": [
"string",
"null"
]
},
"scenario_id": {
"description": "Scenario the link renders.",
"type": "string"
},
"token": {
"description": "Share token — pass to revoke_share to disable the link.",
"type": "string"
},
"url": {
"description": "Public URL of the hosted report (app.rateapi.dev/r/<token>).",
"type": "string"
}
},
"type": "object"
}
},
{
"description": "Get rate benchmark statistics (min/median/max APR) across all institutions. Use this for market analysis, comparing user quotes against market rates, or building benchmark dashboards. Returns statistics for mortgages (30yr fixed, 15yr fixed, and `mortgage_arm` — one bucket covering every adjustable-rate mortgage regardless of initial fixed period), auto loans (new/used — cars only), RV/boat/motorcycle/powersports (first-class vehicle categories), HELOCs, and personal loans. Each product shows the lowest APR institution, median APR, and count of institutions.",
"inputSchema": {
"properties": {
"product_type": {
"description": "Filter to a specific product type. If omitted, returns benchmarks for all product types.",
"enum": [
"mortgage_30yr",
"mortgage_15yr",
"mortgage_arm",
"auto_loan_new",
"auto_loan_used",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"student_loan"
],
"type": "string"
},
"state": {
"description": "Filter to a specific US state (2-letter code). If omitted, returns nationwide benchmarks.",
"type": "string"
}
},
"type": "object"
},
"name": "get_benchmarks",
"outputSchema": {
"additionalProperties": true,
"properties": {
"benchmarks": {
"description": "Formatted per-product benchmark rows, one per product category, ready to present.",
"items": {
"additionalProperties": true,
"properties": {
"aprSpread": {
"description": "Distance between highest and lowest APR, written out in percentage points; the size of the shopping-around prize.",
"type": [
"string",
"null"
]
},
"asOf": {
"description": "UTC timestamp of the newest rate behind this product's benchmark.",
"type": [
"string",
"null"
]
},
"highestAPR": {
"description": "Highest published APR as a percent string.",
"type": [
"string",
"null"
]
},
"institutions": {
"description": "Number of credit unions publishing this product; small counts make the median and spread unreliable.",
"type": [
"number",
"null"
]
},
"lowestAPR": {
"description": "Best published APR for this product as a percent string — one outlier deal, not what a typical borrower gets.",
"type": [
"string",
"null"
]
},
"lowestAPRProvider": {
"description": "Credit union publishing the lowest APR, with its state in parentheses.",
"type": [
"string",
"null"
]
},
"medianAPR": {
"description": "Median published APR as a percent string; the fairest single number for 'the going rate'.",
"type": [
"string",
"null"
]
},
"product": {
"description": "Human-readable product this row benchmarks, e.g. 'New Auto Loan (60 months)'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"generatedAt": {
"description": "UTC timestamp when this benchmark response was assembled; the underlying rates are older, see each row's asOf.",
"type": [
"string",
"null"
]
},
"rawData": {
"description": "The same benchmarks as unformatted numbers, for calculation rather than display.",
"items": {
"additionalProperties": true,
"properties": {
"count": {
"description": "Number of published offers behind this row's statistics.",
"type": [
"number",
"null"
]
},
"displayName": {
"description": "Human-readable label for the product category.",
"type": [
"string",
"null"
]
},
"maxAPR": {
"description": "Highest published APR in percent.",
"type": [
"number",
"null"
]
},
"medianAPR": {
"description": "Median published APR in percent; the robust central number for this product.",
"type": [
"number",
"null"
]
},
"minAPR": {
"description": "Lowest published APR in percent. Extreme lows can be data artifacts such as promotional or calculator-default values, so sanity-check against medianAPR.",
"type": [
"number",
"null"
]
},
"minAPRInstitution": {
"description": "Credit union publishing the lowest APR for this product.",
"type": [
"string",
"null"
]
},
"minAPRInstitutionId": {
"description": "Internal composite identifier 'name|city|STATE' of that lender.",
"type": [
"string",
"null"
]
},
"minAPRState": {
"description": "Two-letter state code of the lender publishing the lowest APR.",
"type": [
"string",
"null"
]
},
"productType": {
"description": "Normalized product category key, e.g. 'auto_loan_new', 'auto_loan_used', 'boat'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"stateFilter": {
"description": "Scope of the benchmark set as a label — 'Nationwide' when no state narrowing was applied. Check this before describing the numbers as local.",
"type": [
"string",
"null"
]
},
"summary": {
"description": "Plain-English headline of the benchmark set, e.g. the range of 30-year fixed APRs and how many credit unions publish them.",
"type": [
"string",
"null"
]
},
"totalInstitutions": {
"description": "Number of institutions behind the benchmark set, returned as a string rather than a number.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Get a single saved cohort by id, including all members and the last scan snapshot (triage list).",
"inputSchema": {
"properties": {
"id": {
"description": "Cohort id. Required.",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "get_cohort",
"outputSchema": {
"additionalProperties": true,
"description": "IMPORTANT: this tool runs a LIVE re-scan of the cohort and returns the scan result, not the stored cohort record. It does not return the member list. The payload is identical to scan_portfolio.",
"properties": {
"changed": {
"description": "Members whose best offer moved since the previous snapshot.",
"items": {
"additionalProperties": true,
"properties": {
"apr_delta": {
"description": "Change in APR in percentage points.",
"type": [
"number",
"null"
]
},
"change": {
"description": "'new', 'best_lender_changed', or 'apr_changed'.",
"type": "string"
},
"from": {
"additionalProperties": true,
"description": "Prior best_lender and best_apr. Absent for a new member.",
"type": [
"object",
"null"
]
},
"label": {
"description": "Member label.",
"type": "string"
},
"to": {
"additionalProperties": true,
"description": "Current best_lender and best_apr.",
"type": "object"
}
},
"type": "object"
},
"type": "array"
},
"scanned": {
"description": "Members evaluated in this scan.",
"type": "number"
},
"triage": {
"description": "Every member's current best offer, the work list.",
"items": {
"additionalProperties": true,
"properties": {
"best_apr": {
"description": "Best APR percent, null when none was found.",
"type": [
"number",
"null"
]
},
"best_lender": {
"description": "Institution with the best offer, null when none was found.",
"type": [
"string",
"null"
]
},
"label": {
"description": "Member label.",
"type": "string"
},
"monthly_payment": {
"description": "Monthly payment on the best offer.",
"type": [
"number",
"null"
]
},
"savings_vs_current": {
"description": "Monthly saving against the member's stated current rate, when one was supplied.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "Introspect what mortgage/loan data the API covers BEFORE scanning — which states, lenders, and product types are present, row counts per segment, and last-updated freshness per segment. Returns a coverage matrix so an agent can pick a scannable state/product before calling scan_savings or get_financing_decision. Mirrors the /meta global counts, expanded into a per-segment matrix. Boats, RVs, motorcycles, and powersports are first-class product categories; auto means cars.",
"inputSchema": {
"properties": {
"freshness_days": {
"description": "Optional uniform staleness window in days (1-90). OMIT to use per-category freshness windows — supplying a value overrides every category and is echoed back as freshness_mode=override.",
"type": "number"
},
"group_by": {
"description": "Optional segmentation axis. Default 'state'.",
"enum": [
"state",
"product",
"state_product"
],
"type": "string"
},
"product_category": {
"description": "Optional. Restrict the matrix to one product category. Omit for all.",
"enum": [
"mortgage",
"auto",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal",
"credit_card",
"student",
"equipment"
],
"type": "string"
},
"state": {
"description": "Optional 2-letter US state code to scope the matrix to a single state.",
"type": "string"
}
},
"required": [],
"type": "object"
},
"name": "get_coverage",
"outputSchema": {
"additionalProperties": true,
"properties": {
"coverage": {
"additionalProperties": true,
"description": "Which states and product types appear in the data, as flat lists.",
"properties": {
"product_types": {
"description": "Product type keys present, possibly truncated — see product_types_truncated_from.",
"type": "array"
},
"product_types_truncated_from": {
"description": "Full number of product types before the list above was truncated for display. Null when nothing was truncated.",
"type": [
"number",
"null"
]
},
"states": {
"description": "Two-letter state codes present in this coverage snapshot.",
"type": "array"
}
},
"type": "object"
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"freshness_days": {
"description": "Age limit in days a rate must be within to be counted here; rows older than this are excluded from the totals.",
"type": [
"number",
"null"
]
},
"freshness_mode": {
"description": "How the freshness window was chosen: 'per_category' applies a category-specific window instead of one global value.",
"type": [
"string",
"null"
]
},
"generated_at": {
"description": "UTC timestamp when this coverage snapshot was computed.",
"type": [
"string",
"null"
]
},
"institution_profiles": {
"additionalProperties": true,
"description": "Coverage of the NCUA institution reference data that backs lender context, separate from rate coverage.",
"properties": {
"branches": {
"description": "Total branch records held across all profiles.",
"type": [
"number",
"null"
]
},
"cycle_date": {
"description": "Quarter-end date of the NCUA call report the profiles come from.",
"type": [
"string",
"null"
]
},
"linked_credit_unions": {
"description": "Number of credit unions successfully linked to an NCUA profile.",
"type": [
"number",
"null"
]
},
"member_counts": {
"description": "Number of profiles carrying a member count.",
"type": [
"number",
"null"
]
},
"profiles": {
"description": "Number of institution profiles held.",
"type": [
"number",
"null"
]
},
"source": {
"description": "Name of the regulatory dataset behind the institution profiles.",
"type": [
"string",
"null"
]
},
"websites": {
"description": "Number of profiles carrying a website URL; the shortfall against `profiles` is the gap.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"next_actions": {
"description": "Suggested follow-up tools given this coverage picture, as bare tool names.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"note": {
"description": "Plain-English description of how this coverage matrix is grouped and what it totals.",
"type": [
"string",
"null"
]
},
"segments": {
"description": "Coverage broken down by the requested grouping, largest first.",
"items": {
"additionalProperties": true,
"properties": {
"apr": {
"description": "Observed APR range in this segment, as min and max in percent. Wide ranges usually mean the segment mixes dissimilar products.",
"type": "object"
},
"credit_unions": {
"description": "Number of distinct credit unions contributing to this segment.",
"type": [
"number",
"null"
]
},
"is_fresh": {
"description": "True when the segment's newest rate falls inside window_days; false means the segment is stale and should be quoted with caution.",
"type": [
"boolean",
"null"
]
},
"key": {
"description": "Machine key for the segment, e.g. 'CA|30-year-fixed'.",
"type": [
"string",
"null"
]
},
"label": {
"description": "Human-readable segment label, e.g. 'California · 30-year-fixed'.",
"type": [
"string",
"null"
]
},
"last_updated": {
"description": "UTC timestamp of the newest rate in this segment.",
"type": [
"string",
"null"
]
},
"product_category": {
"description": "Broad category the segment belongs to, e.g. 'mortgage'.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Product type of the segment. 'other' is a catch-all for products that did not classify into a named type.",
"type": [
"string",
"null"
]
},
"rows": {
"description": "Number of rate rows in this segment.",
"type": [
"number",
"null"
]
},
"state": {
"description": "Two-letter state code of the segment. Null when the grouping is not state-based.",
"type": [
"string",
"null"
]
},
"window_days": {
"description": "Freshness window in days applied to this specific segment.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"totals": {
"additionalProperties": true,
"description": "Overall size of the covered dataset within the freshness window.",
"properties": {
"credit_unions": {
"description": "Number of distinct credit unions contributing those rows.",
"type": [
"number",
"null"
]
},
"product_types": {
"description": "Number of distinct product types represented.",
"type": [
"number",
"null"
]
},
"rows": {
"description": "Number of individual rate rows counted.",
"type": [
"number",
"null"
]
},
"states": {
"description": "Number of distinct states represented.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
"type": "object"
}
},
{
"description": "Reference tool: Get a credit union's rates, membership eligibility, and source-labelled NCUA quarterly profile: members, assets, year opened, charter, reported services, and branch locations. Eligibility annotates published criteria and never asserts that an individual is ineligible; profile facts are regulatory snapshots, not live prices. Use this when a user asks about a specific credit union. For personalized rate recommendations, use get_financing_decision instead.",
"inputSchema": {
"properties": {
"slug": {
"description": "Credit union slug (URL-friendly name, e.g., \"navy-federal-credit-union\"). Required.",
"type": "string"
},
"state": {
"description": "US state code (2-letter, e.g., CA, TX, NY). Required.",
"type": "string"
}
},
"required": [
"state",
"slug"
],
"type": "object"
},
"name": "get_credit_union",
"outputSchema": {
"additionalProperties": true,
"properties": {
"all_rates": {
"description": "Every rate currently on file for this credit union, deposits and loans together.",
"items": {
"additionalProperties": true,
"properties": {
"apr": {
"description": "APR as a percent string, e.g. '6.147%'. The literal string 'not published' when the lender disclosed no APR — never quote `rate` in its place.",
"type": [
"string",
"null"
]
},
"display_name": {
"description": "Normalized, human-readable product name for comparison across lenders.",
"type": [
"string",
"null"
]
},
"last_updated": {
"description": "UTC timestamp when this rate was last scraped from the lender.",
"type": [
"string",
"null"
]
},
"points": {
"description": "Discount points required for this rate, where 1 point = 1% of the loan amount.",
"type": [
"number",
"null"
]
},
"product_name": {
"description": "The lender's own wording for the product, which may be a balance tier such as '$10,000.00+'.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Normalized product category, e.g. 'savings', 'cd_18mo', '30-year-fixed', 'auto_loan_new'.",
"type": [
"string",
"null"
]
},
"rate": {
"description": "Published rate as a percent string. For deposit products this is the yield the member earns, not a borrowing cost.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"best_rate": {
"additionalProperties": true,
"description": "The single most attractive rate on file for this credit union across every product it publishes — it may be a deposit product, so check `product` before calling it a loan rate.",
"properties": {
"apr": {
"description": "APR of the best-ranked product as a percent string. The literal string 'not published' when the lender disclosed no APR — never quote `rate` in its place.",
"type": [
"string",
"null"
]
},
"points": {
"description": "Discount points required for that rate, where 1 point = 1% of the loan amount.",
"type": [
"number",
"null"
]
},
"product": {
"description": "Name of the product this best rate belongs to, in the lender's own wording.",
"type": [
"string",
"null"
]
},
"rate": {
"description": "Note rate of that product as a percent string.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"credit_union": {
"additionalProperties": true,
"description": "Core identity and freshness facts for this credit union.",
"properties": {
"city": {
"description": "Headquarters city, lower-cased as stored.",
"type": [
"string",
"null"
]
},
"last_verified": {
"description": "UTC timestamp when this credit union's rates were last successfully re-scraped. Null means never successfully scraped.",
"type": [
"string",
"null"
]
},
"name": {
"description": "Full credit union name as displayed.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter state code of the headquarters.",
"type": [
"string",
"null"
]
},
"state_name": {
"description": "Full state name of the headquarters.",
"type": [
"string",
"null"
]
},
"url": {
"description": "The credit union's own website.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"eligibility": {
"additionalProperties": true,
"description": "Who may join this credit union, derived from its published membership criteria — guidance, not an underwriting decision.",
"properties": {
"associations": {
"description": "Associations or groups whose members qualify, often the easiest path for outsiders.",
"type": "array"
},
"confidence": {
"description": "Confidence in this eligibility record, from 0 to 1. Values below about 0.7 should be presented as uncertain.",
"type": [
"number",
"null"
]
},
"credit_union_id": {
"description": "Internal composite identifier 'name|city|STATE'.",
"type": [
"string",
"null"
]
},
"disclosure": {
"description": "Required caveat that eligibility is guidance from public data and the credit union makes the final decision.",
"type": [
"string",
"null"
]
},
"eligibility_type": {
"description": "Type of charter driving membership, e.g. 'community' (geography-based), 'multi' (several qualifying paths), 'unknown'.",
"type": [
"string",
"null"
]
},
"employers": {
"description": "Employers whose staff qualify for membership. Empty means no employer-based path was found.",
"type": "array"
},
"evidence_url": {
"description": "Page on the credit union's site that the eligibility rules were read from; cite it when stating who can join.",
"type": [
"string",
"null"
]
},
"extracted_at": {
"description": "UTC timestamp when the eligibility rules were first extracted.",
"type": [
"string",
"null"
]
},
"family_membership": {
"description": "True when a family member of an existing member also qualifies.",
"type": [
"boolean",
"null"
]
},
"geo_cities": {
"description": "Cities whose residents or workers qualify. Empty means eligibility is not defined at city level.",
"type": "array"
},
"geo_counties": {
"description": "Counties whose residents or workers qualify under a community charter.",
"type": "array"
},
"geo_states": {
"description": "States whose residents qualify. Empty means eligibility is not defined at state level.",
"type": "array"
},
"join_path": {
"description": "The easiest documented route to membership when one is known. Null means no simple published path was found, not that none exists."
},
"membership_fee_usd": {
"description": "One-time membership or association fee in dollars. Null means no fee was published, not that it is free."
},
"military": {
"additionalProperties": true,
"description": "Verified military-service membership paths, when published.",
"type": "object"
},
"min_deposit_usd": {
"description": "Minimum share deposit in dollars required to open membership. Null means none was published."
},
"occupations": {
"description": "Occupations that qualify for membership, e.g. teachers or first responders.",
"type": "array"
},
"open_to_anyone": {
"description": "True when anyone can join, typically via a small association or donation. False means a specific qualification is required.",
"type": [
"boolean",
"null"
]
},
"publication": {
"additionalProperties": true,
"description": "Exact immutable active graph publication backing `rules`.",
"properties": {
"activated_at": {
"description": "UTC timestamp when this publication became serving authority.",
"type": [
"string",
"null"
]
},
"proposal_coverage": {
"additionalProperties": true,
"description": "Coverage of model-proposed claims on the source page. It does not assert that every real-world membership path is known.",
"properties": {
"proposal_survival": {
"description": "Verified divided by proposed claims, or null when none were proposed.",
"type": [
"number",
"null"
]
},
"proposed_claims": {
"description": "Claims proposed from the source page.",
"type": [
"integer",
"null"
]
},
"published_rules": {
"description": "Verified rules published from those claims.",
"type": [
"integer",
"null"
]
},
"scope": {
"description": "Always source_page_model_proposals; distinguishes this metric from real-world FOM completeness.",
"type": [
"string",
"null"
]
},
"verified_claims": {
"description": "Proposed claims that survived evidence verification.",
"type": [
"integer",
"null"
]
},
"withheld_claims": {
"description": "Claims withheld because verification did not pass.",
"type": [
"integer",
"null"
]
},
"withheld_reasons": {
"additionalProperties": true,
"description": "Counts of withheld claims grouped by machine-readable reason.",
"type": "object"
}
},
"type": "object"
},
"publication_id": {
"description": "Database identifier of the active publication.",
"type": [
"integer",
"null"
]
},
"ruleset_sha256": {
"description": "SHA-256 digest of the complete ordered published rule set.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"requirements_summary": {
"description": "One-line plain-English statement of who qualifies; the best field to quote to the user.",
"type": [
"string",
"null"
]
},
"rules": {
"description": "Every verified rule in the exact active publication, including machine-readable conditions and evidence provenance. Unverified proposals are not included.",
"items": {
"additionalProperties": true,
"properties": {
"conditions": {
"description": "Conditions that must all hold for this membership path.",
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
"confidence": {
"description": "Confidence in this verified rule from 0 to 1.",
"type": [
"number",
"null"
]
},
"description": {
"description": "Deterministic human-readable rendering of the rule.",
"type": [
"string",
"null"
]
},
"evidence_quote": {
"description": "Verbatim source excerpt supporting the rule.",
"type": [
"string",
"null"
]
},
"kind": {
"description": "Membership-path category.",
"type": [
"string",
"null"
]
},
"last_confirmed_at": {
"description": "UTC timestamp of the latest confirmation.",
"type": [
"string",
"null"
]
},
"observed_at": {
"description": "UTC timestamp when the source evidence was observed.",
"type": [
"string",
"null"
]
},
"rule_id": {
"description": "Stable identifier of the published rule.",
"type": [
"integer",
"null"
]
},
"source_url": {
"description": "Source page containing the supporting evidence.",
"type": [
"string",
"null"
]
},
"verification_status": {
"description": "How far evidence and semantic verification progressed.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"rules_summary": {
"additionalProperties": true,
"description": "Deterministic counts and freshness summary of the returned verified rules; not a closed-world field-of-membership attestation.",
"type": "object"
},
"schools": {
"description": "Schools or districts whose students, staff, or alumni qualify.",
"type": "array"
},
"source": {
"description": "Where the eligibility record came from, e.g. 'scraped' from the credit union's own website.",
"type": [
"string",
"null"
]
},
"updated_at": {
"description": "UTC timestamp when the eligibility record was last refreshed.",
"type": [
"string",
"null"
]
},
"worship_orgs": {
"description": "Congregations or religious organizations whose members qualify.",
"type": "array"
}
},
"type": "object"
},
"ncua_profile": {
"additionalProperties": true,
"description": "Institution facts from the NCUA quarterly call report — regulator-filed data, independent of the scraped rates.",
"properties": {
"charterNumber": {
"description": "The credit union's NCUA charter number.",
"type": [
"string",
"null"
]
},
"charterState": {
"description": "State that issued the charter, which can differ from where branches operate.",
"type": [
"string",
"null"
]
},
"charterType": {
"description": "Charter code and its label, e.g. federally insured state-chartered versus federally chartered.",
"type": "object"
},
"cycleDate": {
"description": "Quarter-end date of the NCUA call report these figures are from; they can be several months old.",
"type": [
"string",
"null"
]
},
"designations": {
"description": "Special NCUA designations such as low-income or minority depository institution status.",
"type": "object"
},
"financials": {
"description": "Balance-sheet size from the call report: total assets in dollars, current members, and potential members in the field of membership.",
"type": "object"
},
"insuredSince": {
"description": "Date federal share insurance began for this institution.",
"type": [
"string",
"null"
]
},
"locations": {
"description": "Branch footprint: total branches reported, how many are included here, and the branch records themselves.",
"type": "object"
},
"officialName": {
"description": "Legal name as filed with NCUA, usually upper-cased and often differing from the marketing name.",
"type": [
"string",
"null"
]
},
"services": {
"description": "Which services the institution reports offering, such as online membership applications and online loan applications.",
"type": "object"
},
"source": {
"description": "Name of the regulatory dataset these institution facts come from.",
"type": [
"string",
"null"
]
},
"sourceUrl": {
"description": "NCUA page the call-report data is published on.",
"type": [
"string",
"null"
]
},
"websiteUrl": {
"description": "Website as reported to NCUA; may be stale or differ from credit_union.url.",
"type": [
"string",
"null"
]
},
"yearOpened": {
"description": "Four-digit year the credit union was founded.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"summary": {
"description": "One-sentence plain-English summary of this result, safe to quote directly to the user.",
"type": [
"string",
"null"
]
},
"widget": {
"additionalProperties": true,
"description": "Pre-built embeddable rendering of this credit union's rates for UI surfaces; ignore it when composing a text answer.",
"properties": {
"data": {
"description": "Rows and labels the widget renders; a restatement of the rates above, not new data.",
"type": "object"
},
"type": {
"description": "Widget renderer to use, e.g. 'rate_table'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
"type": "object"
}
},
{
"description": "Best/median/spread credit-union deposit APY by product, term, and state, with per-CU peer ranking. Pass the MCP field `product` using one exact underscore value: savings, cd, share_certificate, money_market, ira_cd, ira, or share_savings. The MCP server translates it to REST `product_category`; do not send `product_category`, `mma`, or `money-market` to this tool. Deposits quote APY (no APR); CDs/share certificates include term. Current + recent data; history is retention-bounded.",
"inputSchema": {
"properties": {
"limit": {
"description": "Top N credit unions to rank (default 10, clamp 1..50).",
"type": "number"
},
"metric": {
"description": "Deposits rank by APY, highest first. No APR.",
"enum": [
"apy"
],
"type": "string"
},
"product": {
"description": "MCP field for the deposit product category. Use an exact enum value such as `money_market`; do not use REST field name `product_category`, `mma`, or `money-market`. Omit for all deposit types.",
"enum": [
"savings",
"cd",
"share_certificate",
"money_market",
"ira_cd",
"ira",
"share_savings"
],
"type": "string"
},
"state": {
"description": "2-letter US state code; omit for nationwide.",
"type": "string"
},
"term_months": {
"description": "For CD/share_certificate/ira_cd: filter to a specific term (savings_term_months).",
"type": "number"
}
},
"type": "object"
},
"name": "get_deposit_benchmarks",
"outputSchema": {
"additionalProperties": true,
"properties": {
"as_of": {
"description": "UTC timestamp of the underlying rate data. This is when the rates were last scraped from lender sites, not when this call ran.",
"type": [
"string",
"null"
]
},
"benchmark_balance": {
"description": "Deposit balance in dollars the rates are quoted at. Null means no balance tier was applied, so tiered rates may not be comparable."
},
"best": {
"additionalProperties": true,
"description": "The single highest-yielding offer found.",
"properties": {
"apy": {
"description": "Highest annual percentage yield in percent (4.1 = 4.10% APY). This is a yield the member earns, not a borrowing cost.",
"type": [
"number",
"null"
]
},
"lender": {
"description": "Credit union publishing the highest APY.",
"type": [
"string",
"null"
]
},
"term_months": {
"description": "Term in months of the best offer.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"count": {
"description": "Number of rows returned in `table`, capped by the caller's limit.",
"type": [
"number",
"null"
]
},
"market": {
"additionalProperties": true,
"description": "Distribution of APYs across the market for this product, for context around `best`.",
"properties": {
"count": {
"description": "Number of offers behind the market statistics. This can exceed total_credit_unions when one credit union publishes several tiers.",
"type": [
"number",
"null"
]
},
"max_apy": {
"description": "Highest APY in percent published, matching `best.apy` when the table is not filtered further.",
"type": [
"number",
"null"
]
},
"median_apy": {
"description": "Median APY in percent; the right comparison for whether an offer is good.",
"type": [
"number",
"null"
]
},
"min_apy": {
"description": "Lowest APY in percent published in this market.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"note": {
"description": "Data caveats for this response, including that APY is shown rather than APR and that history is retention-bounded.",
"type": [
"string",
"null"
]
},
"product_category": {
"description": "Deposit product benchmarked, e.g. 'cd', 'savings', 'money_market'.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
},
"table": {
"description": "Ranked deposit offers, highest APY first.",
"items": {
"additionalProperties": true,
"properties": {
"apy": {
"description": "Annual percentage yield in percent, compounding included. Do not describe it as an APR.",
"type": [
"number",
"null"
]
},
"best": {
"description": "True on the single highest-APY row in this table.",
"type": [
"boolean",
"null"
]
},
"bps_below_leader": {
"description": "How far this offer sits below the top APY, in basis points (10 = 0.10 percentage points). 0 marks the leader.",
"type": [
"number",
"null"
]
},
"lender": {
"description": "Credit union publishing this offer.",
"type": [
"string",
"null"
]
},
"position": {
"description": "Rank in this table, 1 = highest APY.",
"type": [
"number",
"null"
]
},
"savings_subtype": {
"description": "Subtype of savings product, such as a money-market or youth account. Null when the lender did not distinguish."
},
"term_months": {
"description": "Term in months for this certificate. Null for products without a fixed term.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"term_months": {
"description": "Certificate term in months these rows are scoped to. Null for non-term products like savings.",
"type": [
"number",
"null"
]
},
"total_credit_unions": {
"description": "Number of credit unions publishing this deposit product in scope — larger than `count` when the table is truncated.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Deposit beta (repricing sensitivity) = change in deposit APY per 100bps change in a benchmark/market rate — the core credit-union/bank ALM & interest-rate-risk (IRR) model input. Pass the MCP field `product` using an exact underscore value such as `money_market`; do not send `product_category`, `mma`, or `money-market`. Derived from RateAPI's retained published deposit-rate history. SHORT-WINDOW / retention-bounded: full-cycle beta needs multi-year history (roadmap) — results ship with an explicit confidence/depth caveat. Deposits quote APY, never APR. Aggregate published rates only — never member/borrower data.",
"inputSchema": {
"properties": {
"benchmark": {
"default": "cd_top_quartile",
"enum": [
"cd_top_quartile",
"treasury",
"fed_funds"
],
"type": "string"
},
"group_by": {
"default": "overall",
"enum": [
"overall",
"state",
"cu"
],
"type": "string"
},
"product": {
"description": "Required MCP product field. Use one exact underscore enum value; money market is `money_market`, never `mma` or `money-market`.",
"enum": [
"savings",
"cd",
"share_certificate",
"money_market",
"ira_cd"
],
"type": "string"
},
"state": {
"description": "2-letter US state code",
"type": "string"
},
"term_months": {
"type": "number"
},
"window": {
"default": "180d",
"enum": [
"90d",
"180d",
"365d"
],
"type": "string"
}
},
"required": [
"product"
],
"type": "object"
},
"name": "get_deposit_beta",
"outputSchema": {
"additionalProperties": true,
"properties": {
"benchmark_requested": {
"description": "The benchmark the caller asked deposit rates to be measured against, e.g. 'cd_top_quartile'.",
"type": [
"string",
"null"
]
},
"benchmark_used": {
"description": "The benchmark actually used, which can differ from benchmark_requested when the requested one lacked data.",
"type": [
"string",
"null"
]
},
"confidence": {
"description": "Qualitative reliability of the beta estimate — 'low' when the history window is short relative to a full rate cycle.",
"type": [
"string",
"null"
]
},
"data_source": {
"description": "Internal backing store that served this query ('clickhouse'); operational detail, not something to report to the user.",
"type": [
"string",
"null"
]
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"group_by": {
"description": "How results are grouped, e.g. 'cu' for one segment per credit union.",
"type": [
"string",
"null"
]
},
"history_depth_days": {
"description": "Days of retained rate history available for this calculation. 0 means no usable history, so every beta is null.",
"type": [
"number",
"null"
]
},
"note": {
"description": "Methodology caveat explaining that this is a short-window beta from retained published history, not a full-cycle beta.",
"type": [
"string",
"null"
]
},
"peer": {
"additionalProperties": true,
"description": "Distribution of beta across the peer group.",
"properties": {
"max_beta": {
"description": "Highest deposit beta among peers, as a ratio. Null when too little history exists."
},
"median_beta": {
"description": "Median deposit beta among peers, as a ratio. Null when too little history exists."
},
"min_beta": {
"description": "Lowest deposit beta among peers, as a ratio (0.3 = deposit rates moved 30% as much as the benchmark). Null when too little history exists to compute it."
}
},
"type": "object"
},
"product": {
"description": "Deposit product the beta was computed for, e.g. 'savings' or 'cd'.",
"type": [
"string",
"null"
]
},
"segments": {
"description": "One beta result per group. An empty array means the retained history was too shallow to compute any beta, not that beta is zero.",
"type": "array"
},
"state": {
"description": "Two-letter state code the analysis was scoped to. Null means nationwide."
},
"term_months": {
"description": "Certificate term in months the analysis was scoped to. Null for non-term products."
},
"window": {
"description": "Lookback period used for the comparison, expressed as a short duration string such as '4w', '90d', or '180d'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "DOCS: return the full text of one RateAPI documentation page by slug (from search_docs) or by its published URL. Documentation only — it describes the contract, not live rates. Available slugs: quickstart, authentication, rate-limits-and-pricing, coverage, freshness, evidence-and-methodology, quoting-rules, eligibility, endpoints, mcp-server, products-and-parameters, errors-and-troubleshooting, deprecation-policy.",
"inputSchema": {
"properties": {
"slug": {
"description": "The page identifier returned by search_docs.",
"enum": [
"quickstart",
"authentication",
"rate-limits-and-pricing",
"coverage",
"freshness",
"evidence-and-methodology",
"quoting-rules",
"eligibility",
"endpoints",
"mcp-server",
"products-and-parameters",
"errors-and-troubleshooting",
"deprecation-policy"
],
"type": "string"
},
"url": {
"description": "Alternatively, the canonical published URL of the page.",
"type": "string"
}
},
"type": "object"
},
"name": "get_doc",
"outputSchema": {
"additionalProperties": true,
"properties": {
"available": {
"description": "Valid slugs, returned alongside an error.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"content": {
"description": "Full page text in markdown, ending with its source URL.",
"type": [
"string",
"null"
]
},
"error": {
"description": "Present when no page matched the reference given.",
"type": [
"string",
"null"
]
},
"slug": {
"description": "The page identifier.",
"type": [
"string",
"null"
]
},
"summary": {
"description": "One-line description of the page.",
"type": [
"string",
"null"
]
},
"title": {
"description": "Page title.",
"type": [
"string",
"null"
]
},
"url": {
"description": "Canonical published URL to cite.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Read the bounded, cursor-paginated feed of currently active eligibility publication replacements since an ISO timestamp. Use it to invalidate caches keyed by credit_union_id or publication identity. It exposes aggregate publication metadata only: no personal facts, no historical verdict, and no claim that a person is eligible or ineligible.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"cursor": {
"description": "Opaque next_cursor from the prior page; do not construct or modify it.",
"maxLength": 1000,
"minLength": 1,
"type": "string"
},
"limit": {
"default": 100,
"description": "Maximum publication changes returned.",
"maximum": 200,
"minimum": 1,
"type": "integer"
},
"since": {
"description": "Exclusive ISO 8601 activation boundary with an offset.",
"format": "date-time",
"maxLength": 64,
"type": "string"
}
},
"required": [
"since"
],
"type": "object"
},
"name": "get_eligibility_changes",
"outputSchema": {
"additionalProperties": true,
"description": "Cursor-paginated active-publication replacement feed for cache invalidation.",
"properties": {
"changes": {
"description": "Active publication replacements in stable ascending order.",
"items": {
"additionalProperties": true,
"properties": {
"activated_at": {
"description": "Publication activation timestamp.",
"type": [
"string",
"null"
]
},
"change": {
"additionalProperties": true,
"description": "Prior publication id when present and aggregate current membership-kind counts.",
"type": "object"
},
"credit_union_id": {
"description": "Stable credit-union id whose active publication changed.",
"type": [
"string",
"null"
]
},
"publication_id": {
"description": "Current active publication id.",
"type": [
"number",
"null"
]
},
"ruleset_sha256": {
"description": "Immutable active ruleset digest.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"disclosure": {
"description": "Required warning that this is not a personal eligibility verdict or full history.",
"type": [
"string",
"null"
]
},
"has_more": {
"description": "Whether another page is available.",
"type": [
"boolean",
"null"
]
},
"next_cursor": {
"description": "Opaque cursor for the next page, or null.",
"type": [
"string",
"null"
]
},
"ordering": {
"description": "Stable ordering columns.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"returned": {
"description": "Number of changes in this page.",
"type": [
"number",
"null"
]
},
"semantics": {
"description": "Active-publication incremental cache-invalidation contract.",
"type": [
"string",
"null"
]
},
"since": {
"description": "Normalized exclusive activation boundary.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Enterprise RateAPI Routes coverage: how many US credit unions RateAPI holds live, verbatim-evidenced membership rules for (and what share of the active fleet that is), how the rules split by kind, how many counties, states and employers they name, verification status, and freshness. The `authority` object distinguishes exact immutable active publications from older graph and flat compatibility records; `evidence_sources` reports the public source mix. Returns a dated `headline` sentence that can be quoted verbatim. Use this BEFORE find_eligible_credit_unions or check_membership_eligibility when the user asks how complete, authoritative, or fresh the eligibility data is. Aggregate only — no institution-level rows; those come from the eligibility tools. Never reports credit data: the rule schema has no condition kind for credit score, income or debt. An institution absent from the graph is undecided, never ineligible.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "get_eligibility_coverage",
"outputSchema": {
"additionalProperties": true,
"description": "Fleet-wide membership-eligibility coverage, passed through from the Enterprise RateAPI Routes GET /v1/eligibility/coverage operation. Every count sits next to the stage it belongs to; nothing here is institution-level.",
"properties": {
"as_of": {
"description": "Most recent rule confirmation across the live graph (ISO 8601) — the moment the data last moved.",
"type": [
"string",
"null"
]
},
"authority": {
"additionalProperties": true,
"description": "Serving-authority adoption. Exact immutable publications are separated from older graph and flat compatibility records.",
"properties": {
"active_publication_rules": {
"description": "Rules declared by exact active publications.",
"type": [
"number",
"null"
]
},
"active_publications": {
"description": "Charters governed by an exact immutable active-publication pointer.",
"type": [
"number",
"null"
]
},
"flat_only_institutions": {
"description": "Active institutions represented only by the lossy flat compatibility record.",
"type": [
"number",
"null"
]
},
"latest_activation": {
"description": "Most recent immutable publication activation (ISO 8601).",
"type": [
"string",
"null"
]
},
"legacy_graph_institutions": {
"description": "Institutions with live graph rules but no immutable active-publication pointer.",
"type": [
"number",
"null"
]
},
"publications_with_proposal_coverage": {
"description": "Active publications reporting proposed, verified and withheld claim counts.",
"type": [
"number",
"null"
]
},
"selection_bound_publications": {
"description": "Active publications carrying selection-bound append-only provenance.",
"type": [
"number",
"null"
]
}
},
"type": [
"object",
"null"
]
},
"by_kind": {
"description": "Live rules and distinct institutions per rule kind, largest first.",
"items": {
"additionalProperties": true,
"properties": {
"institutions": {
"description": "Distinct institutions with at least one live rule of this kind.",
"type": [
"number",
"null"
]
},
"rule_kind": {
"description": "geography | employment | association | education | military | worship | family | household | open | deposit_or_donation | other.",
"type": [
"string",
"null"
]
},
"rules": {
"description": "Live rules of this kind.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": [
"array",
"null"
]
},
"credit_data": {
"additionalProperties": true,
"description": "Explicit statement that no rule condition references credit data.",
"properties": {
"conditions_referencing_credit": {
"description": "Always 0: the condition schema has no kind for credit score, income or debt.",
"type": [
"number",
"null"
]
},
"note": {
"description": "Plain-language statement of the above, safe to quote.",
"type": [
"string",
"null"
]
}
},
"type": [
"object",
"null"
]
},
"disclosure": {
"description": "Statement that must accompany any consumer-facing use of eligibility data.",
"type": [
"string",
"null"
]
},
"evidence_sources": {
"description": "Live rule counts by recorded evidence source class; institution counts may overlap.",
"items": {
"additionalProperties": true,
"properties": {
"institutions": {
"description": "Distinct institutions with at least one live rule from this source class.",
"type": [
"number",
"null"
]
},
"rules": {
"description": "Live rules supported by this source class.",
"type": [
"number",
"null"
]
},
"source_type": {
"description": "Recorded source class, such as membership_page, application_page, ncua or unknown.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": [
"array",
"null"
]
},
"fleet": {
"additionalProperties": true,
"description": "The denominator: active institutions and how many the graph holds live rules for.",
"properties": {
"active_institutions": {
"description": "Active US credit unions in the directory.",
"type": [
"number",
"null"
]
},
"institutions_with_live_rules": {
"description": "Distinct credit unions with at least one live (non-superseded) rule.",
"type": [
"number",
"null"
]
},
"share_with_live_rules": {
"description": "institutions_with_live_rules / active_institutions, 0–1.",
"type": [
"number",
"null"
]
}
},
"type": [
"object",
"null"
]
},
"generated_at": {
"description": "When the aggregate was computed (ISO 8601). Edge-cached for an hour.",
"type": [
"string",
"null"
]
},
"headline": {
"description": "One dated sentence carrying every headline number next to its denominator. Quote it verbatim.",
"type": [
"string",
"null"
]
},
"pipeline": {
"description": "Institutions by eligibility pipeline status — why an institution may be absent from the graph (no source found, needs review, pending).",
"items": {
"additionalProperties": true,
"properties": {
"institutions": {
"description": "Institutions currently in this status.",
"type": [
"number",
"null"
]
},
"status": {
"description": "published | no_source_found | needs_review | pending | failed.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": [
"array",
"null"
]
},
"population": {
"additionalProperties": true,
"description": "Population disclosure: graph inventory, not a personal eligibility decision or reachable-offer count.",
"properties": {
"fleet_scope": {
"description": "Institution population used for the fleet denominator.",
"type": [
"string",
"null"
]
},
"is_personal_eligibility_decision": {
"description": "False: this aggregate is never a decision about a person.",
"type": [
"boolean",
"null"
]
},
"is_reachable_offer_count": {
"description": "False: this is never a count of proven suitable offers.",
"type": [
"boolean",
"null"
]
},
"kind": {
"description": "Aggregate graph-inventory population kind.",
"type": [
"string",
"null"
]
},
"observation_time_semantics": {
"description": "Why the newest confirmation is not the age of every rule.",
"type": [
"string",
"null"
]
},
"rule_scope": {
"description": "Rule population included in the inventory.",
"type": [
"string",
"null"
]
}
},
"type": [
"object",
"null"
]
},
"reach": {
"additionalProperties": true,
"description": "How specific the rules are: distinct places and organizations named, and institutions carrying each path type.",
"properties": {
"counties_named": {
"description": "Distinct county keys in live, non-negated conditions.",
"type": [
"number",
"null"
]
},
"employers_resolved": {
"description": "Distinct canonical organizations named by employment conditions.",
"type": [
"number",
"null"
]
},
"institutions_open_to_anyone": {
"description": "Institutions with a live open_to_anyone condition (passes a two-vendor gate, so deliberately few).",
"type": [
"number",
"null"
]
},
"institutions_with_county_rules": {
"description": "Institutions with at least one live county-level condition.",
"type": [
"number",
"null"
]
},
"institutions_with_employer_rules": {
"description": "Institutions with at least one resolved employment condition.",
"type": [
"number",
"null"
]
},
"institutions_with_military_rules": {
"description": "Institutions with a live military-affiliation condition.",
"type": [
"number",
"null"
]
},
"institutions_with_school_rules": {
"description": "Institutions with a live student/alumni/school-employee condition.",
"type": [
"number",
"null"
]
},
"institutions_with_worship_rules": {
"description": "Institutions with a live place-of-worship condition.",
"type": [
"number",
"null"
]
},
"states_with_county_rules": {
"description": "Distinct states those county keys belong to.",
"type": [
"number",
"null"
]
}
},
"type": [
"object",
"null"
]
},
"rules": {
"additionalProperties": true,
"description": "Live rule counts, verification split and freshness.",
"properties": {
"auto_validated": {
"description": "Live rules machine-validated against a second independent read.",
"type": [
"number",
"null"
]
},
"confirmed_within_30d": {
"description": "Live rules confirmed within the last 30 days.",
"type": [
"number",
"null"
]
},
"human_verified": {
"description": "Live rules verified by a person or the institution.",
"type": [
"number",
"null"
]
},
"live": {
"description": "Rules not superseded.",
"type": [
"number",
"null"
]
},
"median_age_days": {
"description": "Median days since each live rule was last confirmed.",
"type": [
"number",
"null"
]
},
"with_verbatim_evidence": {
"description": "Equals live by construction: a rule cannot be stored without its evidence quote.",
"type": [
"number",
"null"
]
}
},
"type": [
"object",
"null"
]
},
"semantics": {
"description": "How to read the counts: live rules only; absence from the graph is undecided, never ineligible; where row-level verdicts live.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Get the organization's current email branding (display name, logo URL, brand color, intro, business address, reply-to).",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "get_email_branding",
"outputSchema": {
"additionalProperties": true,
"description": "The organization's email branding, wrapped in a `branding` envelope.",
"properties": {
"branding": {
"additionalProperties": true,
"description": "The stored branding row, or null when the organization has never set branding.",
"properties": {
"brand_color": {
"description": "Accent color as a #hex string.",
"type": [
"string",
"null"
]
},
"business_address": {
"description": "CAN-SPAM physical address.",
"type": [
"string",
"null"
]
},
"display_name": {
"description": "From-name and CAN-SPAM advertiser identity.",
"type": [
"string",
"null"
]
},
"intro_text": {
"description": "Default intro paragraph.",
"type": [
"string",
"null"
]
},
"logo_background_color": {
"description": "Logo backdrop as a 6-digit #hex string.",
"type": [
"string",
"null"
]
},
"logo_email_url": {
"description": "Email-optimized logo variant.",
"type": [
"string",
"null"
]
},
"logo_url": {
"description": "Public logo URL.",
"type": [
"string",
"null"
]
},
"organization_id": {
"description": "Owning organization.",
"type": "string"
},
"reply_to_email": {
"description": "Optional Reply-To address.",
"type": [
"string",
"null"
]
}
},
"type": [
"object",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Get data extraction statistics showing the scale and health of rate data collection. Use this to understand extraction volumes, product coverage, and data freshness. Supports filtering by date range and product type. Great for building transparency dashboards or monitoring data collection health.",
"inputSchema": {
"properties": {
"endTime": {
"description": "End of the time range. Supports ISO8601 or relative times. Defaults to \"now\".",
"type": "string"
},
"product_type": {
"description": "Filter statistics to a specific product type. If omitted, returns stats for all product types.",
"enum": [
"mortgage",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"personal_loan",
"heloc",
"credit_card",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"startTime": {
"description": "Start of the time range. Supports ISO8601 (e.g., \"2024-01-15T00:00:00Z\") or relative times (\"now-24h\", \"now-7d\", \"now-1m\"). Defaults to \"now-24h\".",
"type": "string"
}
},
"type": "object"
},
"name": "get_extraction_stats",
"outputSchema": {
"additionalProperties": true,
"description": "Rate-extraction activity for a time window. The handler reshapes /v1/stats: the headline counts are returned as locale-formatted STRINGS, not numbers.",
"properties": {
"coverage": {
"additionalProperties": true,
"description": "Breadth of the dataset.",
"properties": {
"activeInstitutions": {
"description": "Institutions active in the window, comma-formatted string.",
"type": "string"
},
"institutions": {
"description": "Total institutions, comma-formatted string.",
"type": "string"
},
"productTypes": {
"description": "Product types covered.",
"type": [
"number",
"array",
"null"
]
},
"states": {
"description": "States covered.",
"type": [
"number",
"array",
"null"
]
}
},
"type": "object"
},
"dataQuality": {
"additionalProperties": true,
"description": "Data-health indicators, passed through unchanged from /v1/stats.",
"type": [
"object",
"null"
]
},
"generatedAt": {
"description": "ISO-8601 time the stats were computed.",
"type": [
"string",
"null"
]
},
"hourlyTrendSample": {
"description": "First six hourly buckets of the trend series (a sample, not the full series).",
"items": {
"additionalProperties": true,
"properties": {
"hour": {
"description": "Bucket label.",
"type": [
"string",
"number",
"null"
]
},
"total": {
"description": "Rates extracted in that hour.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"products": {
"description": "Full product-type breakdown.",
"items": {
"additionalProperties": true,
"properties": {
"count": {
"description": "Rate count, comma-formatted string.",
"type": "string"
},
"name": {
"description": "Display name.",
"type": [
"string",
"null"
]
},
"percentage": {
"description": "Share of the window, e.g. '12.3%'.",
"type": "string"
},
"type": {
"description": "Machine product type.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"query": {
"additionalProperties": true,
"description": "The resolved time window and filters the stats were computed over.",
"type": [
"object",
"null"
]
},
"stats": {
"additionalProperties": true,
"description": "Headline counters. Note the string formatting.",
"properties": {
"activeInstitutions": {
"description": "Institutions that produced rates, comma-formatted.",
"type": "string"
},
"hoursInRange": {
"description": "Length of the window in hours.",
"type": [
"number",
"string",
"null"
]
},
"ratesPerHour": {
"description": "Average rates per hour, comma-formatted.",
"type": "string"
},
"totalRates": {
"description": "Rates extracted in the window, comma-formatted (e.g. '104,522').",
"type": "string"
}
},
"type": "object"
},
"summary": {
"description": "One-line headline of rates extracted, per-hour throughput, and institution count.",
"type": "string"
},
"topProducts": {
"description": "Pre-rendered 'name: count (pct%)' string for the three largest product types.",
"type": "string"
}
},
"type": "object"
}
},
{
"description": "RECOMMENDED WHEN SHOPPING: Get personalized financing recommendations for ANY loan or credit product across every major type: mortgages (30yr/15yr/20yr/10yr fixed and ARMs), auto loans (new/used/CPO, 36-84 month terms), RV/boat/motorcycle/powersports loans, HELOCs (fixed/variable), personal loans (secured/unsecured), student loans, equipment loans, and credit cards (rewards, cash_back, secured, balance_transfer, low_rate, business, platinum, student). Analyzes current market offers and returns actionable recommendations with explanations. Use this instead of looking up raw rates when the user is asking \"what rate can I get?\" and does NOT yet have an offer. IMPORTANT: if the user ALREADY has a quoted rate and is asking whether it is good/fair/competitive (\"I was quoted 6.9%, is that any good?\"), call rate_sanity_check instead — it returns a percentile verdict on their specific number, which is what that question is actually asking. Provide the user's state, intent (purchase/refinance/cash_out/balance_transfer/new_credit), and amount for personalized advice.",
"inputSchema": {
"properties": {
"amount": {
"description": "Loan amount in dollars (minimum 1000). Required.",
"type": "number"
},
"county": {
"description": "User's county for membership-eligibility matching (credit union field-of-membership). Helps flag which lenders the user can actually join.",
"type": "string"
},
"credit_score": {
"description": "Borrower's credit score (300-850). Highly recommended for accurate rate matching.",
"type": "number"
},
"current_apr": {
"description": "Current offer APR if refinancing (percentage).",
"type": "number"
},
"current_rate": {
"description": "Current offer rate if refinancing (percentage, e.g., 6.5 for 6.5%).",
"type": "number"
},
"eligible_only": {
"description": "BETA (annotation-only): eligible_only is in beta pending identity-verification thresholds; offers are annotated, not filtered. Setting true adds an eligible_only_status notice to the response — eligibility annotates and re-ranks, but no offers are dropped. When an annotation comes back unknown, that is not a no: call find_eligible_credit_unions or check_membership_eligibility and read `missing_facts` — ask those questions before concluding no offers exist. eligible_only is beta.",
"type": "boolean"
},
"employer": {
"description": "User's employer, matched against credit union employer/SEG membership lists for eligibility.",
"type": "string"
},
"include_institution_context": {
"description": "Optional: Include compact NCUA quarterly facts on each final offer (members, locations, assets, year opened, and selected relationship services).",
"type": "boolean"
},
"include_out_of_state": {
"description": "Optional: Include documented out-of-state open or multi-state credit-union candidates. Defaults to false, which preserves the requested-state candidate set.",
"type": "boolean"
},
"intent": {
"description": "The loan intent. For mortgages, use \"purchase\" or \"refinance\". For auto loans, use \"purchase\" (new/used car) or \"refinance\" (existing auto loan). Required.",
"enum": [
"purchase",
"refinance",
"cash_out",
"balance_transfer",
"new_credit"
],
"type": "string"
},
"max_providers": {
"description": "Maximum number of providers to return (1-5). Defaults to 5.",
"type": "number"
},
"military_status": {
"description": "User's military affiliation. Annotates offers with eligible_via_military where the credit union has a military field of membership.",
"enum": [
"active_duty",
"veteran",
"reservist",
"dod_civilian",
"military_family"
],
"type": "string"
},
"no_points": {
"description": "If true, prefer no-points loans only. Applies to mortgages.",
"type": "boolean"
},
"product_type": {
"description": "Type of financing product: \"mortgage\" (FIXED-rate home purchase/refinance), \"mortgage_arm\" (ADJUSTABLE-rate mortgage), \"auto_loan\" (vehicle financing), \"heloc\" (home equity line of credit), \"personal_loan\" (general purpose loans), \"credit_card\" (credit card offers), \"student_loan\" (student/education loans, incl. refinance and graduate loans), \"equipment_loan\" (farm/heavy equipment and tractor financing). Defaults to \"mortgage\". Pick \"mortgage_arm\" whenever the user says ARM, adjustable, or names a slash pair (\"5/1\", \"5/5\", \"7/1\", \"10/1\") — fixed and adjustable are ranked as SEPARATE markets, because an ARM intro rate sits structurally below a comparable fixed rate and a blended list would put every ARM on top and call it cheaper, which is true only until it resets. Within \"mortgage\", term_months selects 15- vs 30-year; it has no meaning for \"mortgage_arm\".",
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"personal_loan",
"heloc",
"credit_card",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"school": {
"description": "User's school/college/university. Supply school_relationship too; a school name alone does not affirm a typed eligibility path.",
"type": "string"
},
"school_relationship": {
"description": "How the user relates to the named school. Required with school to affirm a typed student, alumni, or school-employee path.",
"enum": [
"student",
"alumni",
"employee"
],
"type": "string"
},
"state": {
"description": "Valid 50-state/DC code (2-letter, e.g., CA, TX, NY). Required; lowercase is accepted and normalized.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"term_months": {
"description": "Loan term in months (12-480). Defaults to 360 (30-year) for mortgages, 60 (5-year) for auto loans. Common auto loan terms: 36, 48, 60, 72, 84 months. Common mortgage terms: 180 (15-year), 360 (30-year).",
"type": "number"
},
"vehicle_condition": {
"description": "AUTO LOANS ONLY: Condition of the vehicle being purchased or refinanced. Affects rate eligibility.",
"enum": [
"new",
"used",
"certified_pre_owned",
"any"
],
"type": "string"
},
"vehicle_type": {
"description": "AUTO LOANS ONLY: Type of vehicle being financed. Some lenders offer specialized rates by vehicle type.",
"enum": [
"car",
"truck",
"suv",
"motorcycle",
"rv",
"boat"
],
"type": "string"
},
"vehicle_year": {
"description": "AUTO LOANS ONLY: Model year of the vehicle (e.g., 2024, 2020). Used to determine age-based rate tiers.",
"type": "number"
},
"worship": {
"description": "User's place of worship, used to annotate offers with worship-org-affinity eligibility.",
"type": "string"
},
"zip": {
"description": "User's US 5-digit ZIP or ZIP+4. Resolves to a county server-side for membership-eligibility matching; its crosswalk state must agree with state.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
}
},
"required": [
"state",
"intent",
"amount"
],
"type": "object"
},
"name": "get_financing_decision",
"outputSchema": {
"additionalProperties": true,
"properties": {
"rate_range": {
"additionalProperties": true,
"description": "Span of rates across the offers considered, for framing how much shopping around is worth.",
"properties": {
"max": {
"description": "Highest rate found, as a percent string.",
"type": [
"string",
"null"
]
},
"min": {
"description": "Lowest rate found, as a percent string.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"recommendation": {
"additionalProperties": true,
"description": "The recommended course of action and how strongly it is held.",
"properties": {
"action": {
"description": "Recommended next move, e.g. 'shop_providers' (better rates exist elsewhere) or 'accept'.",
"type": [
"string",
"null"
]
},
"confidence": {
"description": "Confidence in the recommendation as a percentage string, e.g. '94%'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"request_id": {
"description": "Opaque identifier for this call, useful only for support or debugging; never show it to the user.",
"type": [
"string",
"null"
]
},
"resolved_county": {
"additionalProperties": true,
"description": "County the supplied ZIP was resolved to, used for eligibility and local branch matching.",
"properties": {
"county": {
"description": "County name the ZIP falls in, e.g. 'San Francisco'.",
"type": [
"string",
"null"
]
},
"fips": {
"description": "Five-digit Census county FIPS code, zero-padded (e.g. '06075').",
"type": [
"string",
"null"
]
},
"source": {
"description": "How the county was determined: 'zip' means it was derived from the supplied ZIP code.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"summary": {
"description": "Headline verdict for the user in one line, e.g. 'Shop Around - Better rates available'.",
"type": [
"string",
"null"
]
},
"top_offers": {
"description": "Best live published offers for this scenario, already sorted best-first.",
"items": {
"additionalProperties": true,
"properties": {
"apr": {
"description": "Annual percentage rate as a percent string, e.g. '6.283%'. The literal string 'not published' when the lender disclosed no APR — the API never substitutes the note rate, so do not treat `rate` as the APR.",
"type": [
"string",
"null"
]
},
"credit_union_id": {
"description": "Stable composite credit-union identifier from REST; use it to join this offer to eligibility check, search, and profile results.",
"type": [
"string",
"null"
]
},
"eligibility": {
"additionalProperties": true,
"description": "Whether the user can likely join this credit union. Open-world non-matches remain `unknown`; MCP does not expose an unattested denial.",
"properties": {
"status": {
"description": "Decision-time compatibility status. A graph-source explanation governs this projection: its safe nonnegative legacy_status is used, otherwise MCP emits conservative likely_eligible; a graph unknown remains unknown. `geo_mismatch` is reserved for wire compatibility.",
"type": [
"string",
"null"
]
},
"unknown_reason": {
"description": "Machine-readable reason for `unknown`; `fom_completeness_unaffirmed` means the published membership corpus is not attested complete.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"eligibility_explanation": {
"additionalProperties": true,
"description": "Decision-time eligibility explanation with open-world negative sanitization; exact REST publication lineage is preserved and never synthesized.",
"properties": {
"access_cost_usd": {
"description": "Known up-front cost of the exact matched graph path. Present only when source is graph and status is conditionally_eligible.",
"type": [
"number",
"null"
]
},
"conditions": {
"description": "Proven steps still required by the exact matched graph path. Present only when source is graph and status is conditionally_eligible.",
"items": {
"type": "string"
},
"type": "array"
},
"legacy_status": {
"description": "Compatibility status from the legacy evaluator. `geo_mismatch` is reserved and normalized to `unknown` by MCP.",
"type": [
"string",
"null"
]
},
"publication": {
"additionalProperties": true,
"description": "Exact immutable generation lineage, present only when REST evaluated an active graph publication.",
"properties": {
"activated_at": {
"description": "UTC timestamp when the exact publication became serving authority.",
"type": [
"string",
"null"
]
},
"publication_id": {
"description": "Database identifier of the exact active eligibility publication evaluated for this offer.",
"type": [
"number",
"null"
]
},
"ruleset_sha256": {
"description": "SHA-256 digest of the complete ordered rule set in that active publication.",
"pattern": "^[0-9a-f]{64}$",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"reason": {
"description": "Deterministic explanation safe to quote; an unattested negative is replaced with a neutral open-world explanation.",
"type": [
"string",
"null"
]
},
"source": {
"description": "Authority used for the decision-time eligibility result: graph, annotation, authority_unavailable, or absent.",
"type": [
"string",
"null"
]
},
"status": {
"description": "Decision-time eligibility outcome. The reserved `ineligible` value is normalized to `unknown` unless a future typed closed-world attestation is validated.",
"type": [
"string",
"null"
]
},
"unknown_reason": {
"description": "Machine-readable reason for an unknown decision, including `fom_completeness_unaffirmed`.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"institution_context": {
"description": "NCUA call-report facts about the institution (asset size, member count, branch count, year opened, online services) for sizing up the lender.",
"type": "object"
},
"loan_program": {
"description": "Underwriting program, e.g. 'conventional', 'va', 'fha', 'jumbo'.",
"type": [
"string",
"null"
]
},
"monthly_payment": {
"description": "Estimated principal-and-interest payment as a formatted dollar string; excludes taxes, insurance, PMI, and HOA.",
"type": [
"string",
"null"
]
},
"points": {
"description": "Discount points required to get this rate, where 1 point = 1% of the loan amount. 0 means no points.",
"type": [
"number",
"null"
]
},
"product": {
"description": "Display name of the lender's product, e.g. '30-Year Fixed'.",
"type": [
"string",
"null"
]
},
"provider": {
"description": "Name of the credit union publishing this offer.",
"type": [
"string",
"null"
]
},
"rank": {
"description": "Position in this list, 1 = best offer by the ranking used here.",
"type": [
"number",
"null"
]
},
"rate": {
"description": "Note rate as a percent string (e.g. '6%') — the rate used to compute the payment, excluding fees.",
"type": [
"string",
"null"
]
},
"rateapi_url": {
"description": "Public rateapi.dev profile page for this credit union, safe to link the user to.",
"type": [
"string",
"null"
]
},
"url": {
"description": "The credit union's own website.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"tradeoffs": {
"description": "Costs, caveats, and conditions the user should weigh before acting, such as closing costs or membership requirements.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"why": {
"description": "Ordered reasons supporting the recommendation, each already written as a user-facing sentence.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "Loan-officer competitive-landscape report: ranked roster of the top N lenders publishing a given mortgage product in a state today — per-lender rows (name, best APR/rate, product, position, bps above the leader) — plus the market min/median/max. The market median is INSTITUTION-level — one vote per lender, using each lender's best APR (basis = total_lenders, not market.count) — so a lender publishing a large rate matrix cannot pull it. Extends get_benchmarks (which returns only min/median/max + the single lowest institution) with the full ranked table.",
"inputSchema": {
"properties": {
"include_institution_context": {
"description": "Include compact NCUA member, location, asset, founding-year, and selected service facts per lender.",
"type": "boolean"
},
"limit": {
"description": "Top N lenders to return (default 10, clamped 1..50)",
"type": "number"
},
"metric": {
"description": "Rank by apr (default) or rate",
"enum": [
"apr",
"rate"
],
"type": "string"
},
"product": {
"description": "Mortgage product",
"enum": [
"30yr_fixed",
"15yr_fixed"
],
"type": "string"
},
"state": {
"description": "2-letter US state code, e.g. CA, TX, NY",
"type": "string"
}
},
"required": [
"state",
"product"
],
"type": "object"
},
"name": "get_league_table",
"outputSchema": {
"additionalProperties": true,
"properties": {
"as_of": {
"description": "UTC timestamp of the underlying rate data. This is when the rates were last scraped from lender sites, not when this call ran.",
"type": [
"string",
"null"
]
},
"count": {
"description": "Rows actually returned in `table`.",
"type": [
"number",
"null"
]
},
"limit": {
"description": "Maximum rows the caller asked for.",
"type": [
"number",
"null"
]
},
"market": {
"additionalProperties": true,
"description": "Distribution across all lenders publishing this product, including those below the table cutoff.",
"properties": {
"count": {
"description": "Number of offers behind the market statistics. It can exceed total_lenders when a lender publishes several matching products.",
"type": [
"number",
"null"
]
},
"max_apr": {
"description": "Highest APR in percent in the whole market.",
"type": [
"number",
"null"
]
},
"median_apr": {
"description": "Median APR in percent across the whole market; use this, not min_apr, as 'the going rate'.",
"type": [
"number",
"null"
]
},
"min_apr": {
"description": "Lowest APR in percent in the whole market for this product.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"metric": {
"description": "Value the ranking is sorted by — 'apr' ranks by true cost including fees, 'rate' by the note rate alone.",
"type": [
"string",
"null"
]
},
"note": {
"description": "Plain-English interpretation of the numbers above, already phrased for the user; quote it rather than re-deriving the comparison.",
"type": [
"string",
"null"
]
},
"product": {
"description": "Product key the table ranks, e.g. '30yr_fixed'.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
},
"table": {
"description": "Lenders ranked best-first by the chosen metric.",
"items": {
"additionalProperties": true,
"properties": {
"apr": {
"description": "Annual percentage rate in percent, including lender fees. NULL when the lender published no APR — the API deliberately does not substitute the note rate, so never present `rate` as an APR. Some legacy rows still carry an APR equal to the note rate; those heal on that credit union's next scrape.",
"type": [
"number",
"null"
]
},
"as_of": {
"description": "UTC timestamp when this lender's rate was last scraped.",
"type": [
"string",
"null"
]
},
"best": {
"description": "True on the single top-ranked row.",
"type": [
"boolean",
"null"
]
},
"bps_above_leader": {
"description": "How far this row's metric sits above the leader, in basis points (3 = 0.03 percentage points). 0 marks the leader.",
"type": [
"number",
"null"
]
},
"display_name": {
"description": "Normalized, human-readable product name for comparison across lenders.",
"type": [
"string",
"null"
]
},
"eligibility": {
"description": "Membership-eligibility snapshot for this lender, including status, charter type, and confidence. A great rate is unusable if the user cannot join.",
"type": "object"
},
"institution_context": {
"description": "NCUA call-report facts about the institution such as asset size, member count, branches, and year opened.",
"type": "object"
},
"lender": {
"description": "Full name of the credit union.",
"type": [
"string",
"null"
]
},
"points": {
"description": "Discount points required for this rate, where 1 point = 1% of the loan amount.",
"type": [
"number",
"null"
]
},
"position": {
"description": "Rank in the table, 1 = best on the chosen metric.",
"type": [
"number",
"null"
]
},
"product": {
"description": "Product key this row was matched on, matching the top-level `product`.",
"type": [
"string",
"null"
]
},
"product_name": {
"description": "The lender's own wording for the product, e.g. 'VA 30 Year Fixed' — note it may be a program-restricted product.",
"type": [
"string",
"null"
]
},
"rate": {
"description": "Note rate in percent, excluding fees. It can be lower than the APR on the same row.",
"type": [
"number",
"null"
]
},
"rateapi_url": {
"description": "Public rateapi.dev profile page for this lender.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"total_lenders": {
"description": "Number of lenders publishing this product in this state. `count` is the visible top slice of this larger set.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Get detailed information about a specific monitor by its ID.",
"inputSchema": {
"properties": {
"monitor_id": {
"description": "The unique identifier of the monitor. Required.",
"type": "string"
}
},
"required": [
"monitor_id"
],
"type": "object"
},
"name": "get_monitor",
"outputSchema": {
"additionalProperties": true,
"description": "One monitor in full. On a missing id the tool returns a not-found shape instead of throwing.",
"properties": {
"error": {
"description": "Present and set to 'not_found' when the monitor id does not exist.",
"type": [
"string",
"null"
]
},
"monitor": {
"additionalProperties": true,
"description": "The monitor. Absent when not found.",
"properties": {
"conditions": {
"description": "Full trigger conditions.",
"type": [
"array",
"null"
]
},
"cooldown_hours": {
"description": "Minimum hours between triggers.",
"type": [
"number",
"null"
]
},
"created_at": {
"description": "ISO-8601 creation timestamp.",
"type": [
"string",
"null"
]
},
"decision_context": {
"additionalProperties": true,
"description": "Stored loan context used when evaluating triggers.",
"type": [
"object",
"null"
]
},
"id": {
"description": "Monitor id.",
"type": "string"
},
"last_triggered_at": {
"description": "ISO-8601 last trigger, null if never.",
"type": [
"string",
"null"
]
},
"name": {
"description": "Monitor label.",
"type": "string"
},
"status": {
"description": "'active' or 'paused'.",
"type": "string"
},
"subscribed_product_types": {
"description": "Watched product types.",
"type": [
"array",
"null"
]
},
"subscribed_states": {
"description": "Watched state codes.",
"type": [
"array",
"null"
]
},
"updated_at": {
"description": "ISO-8601 last-modified timestamp.",
"type": [
"string",
"null"
]
},
"webhook_url": {
"description": "Delivery URL.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"summary": {
"description": "Monitor name and status, or a not-found message.",
"type": "string"
}
},
"type": "object"
}
},
{
"description": "Get rollup stats for the account's rate monitors: total, active, and webhooks sent. Complements list_monitors.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "get_monitor_stats",
"outputSchema": {
"additionalProperties": true,
"description": "Rollup counts for the organization's monitors.",
"properties": {
"active_monitors": {
"description": "Monitors in 'active' status.",
"type": "number"
},
"reset_date": {
"description": "When the monthly counter resets.",
"type": [
"string",
"null"
]
},
"total_monitors": {
"description": "Monitors on the account.",
"type": "number"
},
"webhooks_sent_this_month": {
"description": "Webhooks sent this month.",
"type": "number"
},
"webhooks_sent_today": {
"description": "Webhooks sent today.",
"type": "number"
}
},
"type": "object"
}
},
{
"description": "Evaluate one person across 1-19 explicit loan or deposit selectors using one exhaustive eligibility snapshot. Returns separate membership, published availability, product suitability, published pricing, underwriting, and approval layers. Lead only with reachable_now or reachable_after_action; unresolved and no_published_price are unknown, never a denial. Published APY, APR, or clearly labeled nominal rate is not a personalized quote, underwriting result, preapproval, commitment, or guarantee. Every returned published price carries source evidence and as_of.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"limit_per_product": {
"description": "Maximum detail rows for each selector, subject to the total and plan caps. Default 5.",
"maximum": 10,
"minimum": 1,
"type": "integer"
},
"person": {
"additionalProperties": false,
"description": "Explicit caller-supplied person facts. Unknown facts stay absent; do not infer them.",
"properties": {
"applicant_kind": {
"description": "What the applicant is; absence means a natural person.",
"enum": [
"person",
"trust",
"organization",
"partnership",
"corporation",
"other_legal_entity"
],
"type": "string"
},
"asserted_org_qualifiers": {
"description": "Narrow conditions the person explicitly asserted; never infer them.",
"items": {
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"association_org_ids": {
"description": "Explicit association ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"associations": {
"description": "Associations the person already belongs to.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"employer": {
"description": "Person-supplied employer name; use employer_org_ids after authoritative resolution.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"employer_org_ids": {
"description": "Explicit employer ids returned by resolve_eligibility_entities; rates-api revalidates type and active-publication authority.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"facility_city": {
"description": "Census-recognized facility city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_county": {
"description": "County where the applicant organization maintains a facility.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"facility_state": {
"description": "Valid 50-state/DC facility state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"facility_zip": {
"description": "ZIP where the applicant organization maintains a facility.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"family_relation": {
"description": "Relationship to the relative whose affiliations are supplied.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"home_city": {
"description": "Census-recognized home city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_county": {
"description": "Home county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"home_state": {
"description": "Valid 50-state/DC home state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"home_zip": {
"description": "Home ZIP; never inferred from another role.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"military_service_state": {
"description": "State tied to a state-scoped military affiliation.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"military_status": {
"description": "Person-supplied military affiliation.",
"enum": [
"active_duty",
"veteran",
"reservist",
"dod_civilian",
"military_family"
],
"type": "string"
},
"occupation": {
"description": "Person-supplied occupation.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_city": {
"description": "Census-recognized payroll-origin city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_county": {
"description": "Payroll-origin county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"payroll_state": {
"description": "Valid 50-state/DC payroll-origin state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"payroll_zip": {
"description": "Payroll-origin ZIP, separate from the worksite.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"property_city": {
"description": "Census-recognized city where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_county": {
"description": "County where the person owns real property.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"property_state": {
"description": "Valid 50-state/DC property state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"property_zip": {
"description": "ZIP where the person owns real property; never inferred from home.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"relative_association_org_ids": {
"description": "Canonical association ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_associations": {
"description": "Associations of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_employer_org_ids": {
"description": "Canonical employer ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_employers": {
"description": "Employers of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"relative_memberships": {
"description": "Confirmed relative memberships, each scoped to one exact institution.",
"items": {
"additionalProperties": false,
"properties": {
"credit_union_id": {
"description": "Exact credit-union id.",
"maxLength": 300,
"minLength": 1,
"type": "string"
},
"relation": {
"description": "Relative relationship.",
"maxLength": 60,
"minLength": 1,
"type": "string"
},
"status": {
"description": "Confirmed membership status.",
"enum": [
"current_member",
"deceased_member"
],
"type": "string"
}
},
"required": [
"credit_union_id",
"relation",
"status"
],
"type": "object"
},
"maxItems": 50,
"type": "array"
},
"relative_school_org_ids": {
"description": "Canonical school ids belonging to the named relative, not the applicant.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"relative_schools": {
"description": "Schools of the named relative, not the applicant.",
"items": {
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"maxItems": 20,
"type": "array"
},
"school": {
"description": "Person-supplied school name; school_relationship is needed for a typed positive path.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"school_org_ids": {
"description": "Explicit school ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
},
"school_relationship": {
"description": "How the person relates to the supplied school.",
"enum": [
"student",
"alumni",
"employee"
],
"type": "string"
},
"willing_to_join_association": {
"description": "Whether documented joinable-association actions may be considered.",
"type": "boolean"
},
"work_city": {
"description": "Census-recognized worksite city.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_county": {
"description": "Worksite county.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"work_state": {
"description": "Valid 50-state/DC worksite state.",
"pattern": "^(?:[Aa][Ll]|[Aa][Kk]|[Aa][Zz]|[Aa][Rr]|[Cc][Aa]|[Cc][Oo]|[Cc][Tt]|[Dd][Ee]|[Dd][Cc]|[Ff][Ll]|[Gg][Aa]|[Hh][Ii]|[Ii][Dd]|[Ii][Ll]|[Ii][Nn]|[Ii][Aa]|[Kk][Ss]|[Kk][Yy]|[Ll][Aa]|[Mm][Ee]|[Mm][Dd]|[Mm][Aa]|[Mm][Ii]|[Mm][Nn]|[Mm][Ss]|[Mm][Oo]|[Mm][Tt]|[Nn][Ee]|[Nn][Vv]|[Nn][Hh]|[Nn][Jj]|[Nn][Mm]|[Nn][Yy]|[Nn][Cc]|[Nn][Dd]|[Oo][Hh]|[Oo][Kk]|[Oo][Rr]|[Pp][Aa]|[Rr][Ii]|[Ss][Cc]|[Ss][Dd]|[Tt][Nn]|[Tt][Xx]|[Uu][Tt]|[Vv][Tt]|[Vv][Aa]|[Ww][Aa]|[Ww][Vv]|[Ww][Ii]|[Ww][Yy])$",
"type": "string"
},
"work_zip": {
"description": "Worksite ZIP, separate from home and payroll.",
"pattern": "^\\d{5}(?:-\\d{4})?$",
"type": "string"
},
"worship": {
"description": "Person-supplied place of worship.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"worship_org_ids": {
"description": "Explicit worship-organization ids returned by resolve_eligibility_entities; rates-api revalidates them.",
"items": {
"maxLength": 80,
"minLength": 1,
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"type": "string"
},
"maxItems": 20,
"type": "array",
"uniqueItems": true
}
},
"type": "object"
},
"products": {
"description": "One to nineteen unique explicit product selectors. Do not invent missing scenario facts.",
"items": {
"additionalProperties": false,
"description": "Exact product request used for both eligibility-backed rate evaluation and ranking.",
"properties": {
"amount": {
"description": "Loan or credit amount in USD.",
"exclusiveMinimum": 0,
"type": "number"
},
"audience": {
"description": "Product audience.",
"enum": [
"business",
"consumer"
],
"type": "string"
},
"balance": {
"description": "Deposit balance in USD.",
"minimum": 0,
"type": "number"
},
"intent": {
"description": "Transaction intent when relevant.",
"enum": [
"purchase",
"refinance",
"cash_out",
"balance_transfer",
"new_credit"
],
"type": "string"
},
"occupancy": {
"description": "Property occupancy.",
"enum": [
"primary",
"secondary",
"investment"
],
"type": "string"
},
"product_type": {
"description": "Exact product family.",
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan",
"credit_card",
"savings",
"cd",
"share_certificate",
"money_market",
"ira_cd",
"ira",
"share_savings"
],
"type": "string"
},
"term_months": {
"description": "Requested term in months.",
"maximum": 600,
"minimum": 1,
"type": "integer"
},
"vehicle_condition": {
"description": "Vehicle condition.",
"enum": [
"new",
"used",
"certified_pre_owned",
"any"
],
"type": "string"
}
},
"required": [
"product_type"
],
"type": "object"
},
"maxItems": 19,
"minItems": 1,
"type": "array",
"uniqueItems": true
},
"total_limit": {
"description": "Maximum detail rows across all selectors; must be at least the selector count. Default 50.",
"maximum": 100,
"minimum": 1,
"type": "integer"
}
},
"required": [
"person",
"products"
],
"type": "object"
},
"name": "get_personal_access_catalog",
"outputSchema": {
"additionalProperties": true,
"description": "One-snapshot personal access catalog across explicit loan and deposit product selectors.",
"properties": {
"catalog_version": {
"description": "Stable access-catalog response contract version.",
"type": [
"string",
"null"
]
},
"completeness": {
"additionalProperties": true,
"description": "Fleet, selector, evaluation-strategy, cap, and truncation disclosure.",
"type": "object"
},
"disclosure": {
"description": "Required separation of membership, suitability, published pricing, underwriting, and approval.",
"type": [
"string",
"null"
]
},
"products": {
"description": "One result per selector in request order.",
"items": {
"additionalProperties": true,
"properties": {
"completeness": {
"additionalProperties": true,
"description": "Exact-count, cap, returned-detail, and truncation metadata for this selector.",
"type": "object"
},
"counts": {
"additionalProperties": true,
"description": "Exact pre-cap counts for each reachability bucket.",
"type": "object"
},
"no_published_price": {
"description": "Graph-positive institutions with no matching fresh evidenced price; never an unavailability claim.",
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
"questions": {
"description": "Product-aware questions that may clarify reachability.",
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
"ranking": {
"additionalProperties": true,
"description": "Explicit declaration that underwriting and approval were not evaluated.",
"type": "object"
},
"ranking_basis": {
"description": "Published-price ordering used for this product.",
"type": [
"string",
"null"
]
},
"reachable_after_action": {
"description": "Rows requiring a source-proven membership action before access.",
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
"reachable_now": {
"description": "Rows with proven current membership access, satisfied published constraints, and evidenced pricing.",
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
"request": {
"additionalProperties": true,
"description": "Exact explicit product selector evaluated.",
"type": "object"
},
"unresolved": {
"description": "Rows whose membership proof or product suitability remains unresolved; never denials.",
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
}
},
"type": "object"
},
"type": "array"
},
"questions": {
"additionalProperties": true,
"description": "Membership questions shared across selectors.",
"type": "object"
},
"semantics": {
"description": "Positive-evidence-only interpretation contract; unknown never means ineligible.",
"type": [
"string",
"null"
]
},
"snapshot": {
"additionalProperties": true,
"description": "Eligibility generation, rules clock, returned-price observation range, and generation time.",
"type": "object"
}
},
"type": "object"
}
},
{
"description": "Get non-personal, evidence-bound membership-access metadata for up to 50 exact deposit product references. Returns active-publication path kinds and documented joinable-association actions alongside the current evidenced product rate. This does NOT decide whether a person is eligible, easy to qualify, approved, or within a published balance/audience constraint; unavailable evidence stays unavailable.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"products": {
"description": "Exact deposit product references; no fuzzy product matching is performed.",
"items": {
"additionalProperties": false,
"properties": {
"audience": {
"description": "Optional requested audience.",
"enum": [
"consumer",
"business"
],
"type": "string"
},
"balance": {
"description": "Optional balance used only to report fit with published bounds.",
"minimum": 0,
"type": "number"
},
"credit_union_id": {
"description": "Exact credit-union id.",
"maxLength": 240,
"minLength": 1,
"type": "string"
},
"product_name": {
"description": "Verbatim stable product name.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"product_type": {
"description": "Exact deposit product family.",
"enum": [
"savings",
"cd",
"share_certificate",
"money_market",
"ira_cd",
"ira",
"share_savings"
],
"type": "string"
},
"term_months": {
"description": "Exact term when applicable.",
"maximum": 600,
"minimum": 1,
"type": "integer"
}
},
"required": [
"credit_union_id",
"product_type",
"product_name"
],
"type": "object"
},
"maxItems": 50,
"minItems": 1,
"type": "array"
}
},
"required": [
"products"
],
"type": "object"
},
"name": "get_product_access_envelopes",
"outputSchema": {
"additionalProperties": true,
"description": "Non-personal published membership and product-rate access metadata for exact deposit products.",
"properties": {
"counts": {
"additionalProperties": true,
"description": "Requested product and distinct institution counts.",
"type": "object"
},
"disclosure": {
"description": "Required warning against interpreting access metadata as personal eligibility or approval.",
"type": [
"string",
"null"
]
},
"envelopes": {
"description": "One access envelope per input in stable order.",
"items": {
"additionalProperties": true,
"properties": {
"input_index": {
"description": "Zero-based position of the exact requested product.",
"type": [
"number",
"null"
]
},
"membership_access": {
"additionalProperties": true,
"description": "Active-publication path kinds and documented actions; never a personal verdict.",
"type": "object"
},
"product_rate": {
"additionalProperties": true,
"description": "Current exact evidenced product row and explicit suitability facts, or an unavailable reason.",
"type": "object"
},
"product_ref": {
"additionalProperties": true,
"description": "Exact product reference supplied by the caller.",
"type": "object"
},
"stable_product_identity": {
"description": "Stable composite identity for this exact product reference.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"semantics": {
"description": "Non-personal, positive-documented-paths-only contract.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Compare the LIVE market rate distribution now vs ~1/2/4 weeks ago for a product and state. Returns now/then min, median, max, count plus the median and min delta and a direction (down/up/flat). Bounded by data retention — if no comparable historical snapshot exists, then is null with an explanatory note. Use this to show how rates have moved recently.",
"inputSchema": {
"properties": {
"product_type": {
"description": "Type of financing product. Required.",
"enum": [
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"mortgage",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"since": {
"description": "How far back to compare against. Defaults to \"1w\".",
"enum": [
"1w",
"2w",
"4w"
],
"type": "string"
},
"state": {
"description": "US state code (2-letter, e.g., CA, TX). Required.",
"type": "string"
}
},
"required": [
"product_type",
"state"
],
"type": "object"
},
"name": "get_rate_delta",
"outputSchema": {
"additionalProperties": true,
"properties": {
"change": {
"additionalProperties": true,
"description": "Movement from `then` to `now`.",
"properties": {
"direction": {
"description": "Direction of the median move: 'up', 'down', or 'flat'.",
"type": [
"string",
"null"
]
},
"median_delta_pct": {
"description": "Change in median APR, in percentage points (0.023 = about 2 basis points). Negative means rates fell.",
"type": [
"number",
"null"
]
},
"min_delta": {
"description": "Change in the lowest published APR, in percentage points. This can move very differently from the median.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"data_source": {
"description": "Internal backing store that served this query ('clickhouse'); operational detail, not something to report to the user.",
"type": [
"string",
"null"
]
},
"note": {
"description": "Plain-English interpretation of the numbers above, already phrased for the user; quote it rather than re-deriving the comparison.",
"type": [
"string",
"null"
]
},
"now": {
"additionalProperties": true,
"description": "Current market snapshot for this product and state.",
"properties": {
"as_of": {
"description": "Timestamp of the most recent rate in the current snapshot.",
"type": [
"string",
"null"
]
},
"count": {
"description": "Number of live offers behind the current snapshot.",
"type": [
"number",
"null"
]
},
"max": {
"description": "Highest APR in percent currently published.",
"type": [
"number",
"null"
]
},
"median": {
"description": "Median APR in percent currently published; the right number for 'what rates are today'.",
"type": [
"number",
"null"
]
},
"min": {
"description": "Lowest APR in percent currently published — a single best deal, not a typical rate.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"product_type": {
"description": "Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
},
"then": {
"additionalProperties": true,
"description": "Snapshot at the start of the window, for comparison against `now`.",
"properties": {
"as_of": {
"description": "Timestamp of the earlier snapshot.",
"type": [
"string",
"null"
]
},
"count": {
"description": "Number of offers behind the earlier snapshot. This is often far smaller than now.count because history is retention-bounded, so treat the comparison as indicative.",
"type": [
"number",
"null"
]
},
"max": {
"description": "Highest APR in percent at the start of the window.",
"type": [
"number",
"null"
]
},
"median": {
"description": "Median APR in percent at the start of the window.",
"type": [
"number",
"null"
]
},
"min": {
"description": "Lowest APR in percent at the start of the window.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"window": {
"description": "Lookback period used for the comparison, expressed as a short duration string such as '4w', '90d', or '180d'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Historical rate time-series: a date-ranged array of {date, min/median/max APR, count} points per product/state for dashboards, charts, backtests, and timing confidence — bounded by data retention. Differs from get_rate_delta (a single now-vs-then comparison): this returns the full series. Boats, RVs, motorcycles, and powersports are first-class product types; auto_loan means cars. Calls the /v1/rate-history public API (single source of truth).",
"inputSchema": {
"properties": {
"interval": {
"description": "Bucket granularity per point. Default \"week\".",
"enum": [
"day",
"week"
],
"type": "string"
},
"product_type": {
"description": "Type of financing product. Required.",
"enum": [
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"mortgage",
"heloc",
"personal_loan",
"credit_card",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"state": {
"description": "US state code (2-letter, e.g., CA, TX). Required.",
"type": "string"
},
"vehicle_condition": {
"description": "auto_loan only; selects the benchmark bucket. Default \"new\".",
"enum": [
"new",
"used",
"cpo"
],
"type": "string"
},
"window": {
"description": "Lookback window. Default \"90d\". Bounded by data retention.",
"enum": [
"30d",
"60d",
"90d",
"180d",
"365d"
],
"type": "string"
}
},
"required": [
"product_type",
"state"
],
"type": "object"
},
"name": "get_rate_history",
"outputSchema": {
"additionalProperties": true,
"properties": {
"data_source": {
"description": "Internal backing store that served this query ('clickhouse'); operational detail, not something to report to the user.",
"type": [
"string",
"null"
]
},
"interval": {
"description": "Bucket size the series is aggregated into, e.g. 'week', 'day', or 'month'. Each entry in `series` covers one of these.",
"type": [
"string",
"null"
]
},
"note": {
"description": "Coverage caveat for this series, notably how many buckets are empty because history is retention-bounded. Do not describe empty buckets as rates falling to zero.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.",
"type": [
"string",
"null"
]
},
"series": {
"description": "One bucket per interval across the window, oldest first. Buckets with no scrapes are present with null statistics.",
"items": {
"additionalProperties": true,
"properties": {
"count": {
"description": "Number of rate observations in this bucket. 0 means the bucket is empty and its statistics are null.",
"type": [
"number",
"null"
]
},
"date": {
"description": "Start date of this bucket (ISO date). For weekly intervals this is the week's first day.",
"type": [
"string",
"null"
]
},
"max": {
"description": "Highest APR in percent observed in this bucket. Null when the bucket has no observations."
},
"median": {
"description": "Median APR in percent for this bucket, the value to plot as the trend line. Null when the bucket has no observations."
},
"min": {
"description": "Lowest APR in percent observed in this bucket. Null when no rates were captured in the bucket — a data gap, not a rate of zero."
}
},
"type": "object"
},
"type": "array"
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
},
"summary": {
"additionalProperties": true,
"description": "Start-to-end comparison across the populated portion of the series.",
"properties": {
"as_of": {
"description": "Timestamp of the most recent underlying rate observation.",
"type": [
"string",
"null"
]
},
"direction": {
"description": "Direction of the move across the window: 'up', 'down', or 'flat'.",
"type": [
"string",
"null"
]
},
"first": {
"description": "Earliest populated bucket, with its date and median APR in percent.",
"type": "object"
},
"last": {
"description": "Most recent populated bucket, with its date and median APR in percent.",
"type": "object"
},
"median_delta_pct": {
"description": "Change in median APR from first to last populated bucket, in percentage points (0.215 = 21.5 basis points). Negative means rates fell.",
"type": [
"number",
"null"
]
},
"points": {
"description": "Number of populated buckets the summary is based on; a handful of points is a weak trend.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"window": {
"description": "Lookback period used for the comparison, expressed as a short duration string such as '4w', '90d', or '180d'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Get a single saved scenario by id (inputs + stored comparison).",
"inputSchema": {
"properties": {
"id": {
"description": "Scenario id",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "get_scenario",
"outputSchema": {
"additionalProperties": true,
"description": "One saved client scenario.",
"properties": {
"clientName": {
"description": "Client label.",
"type": "string"
},
"createdAt": {
"description": "ISO-8601 creation timestamp.",
"type": [
"string",
"null"
]
},
"error": {
"description": "Present when the scenario was not found.",
"type": [
"string",
"null"
]
},
"id": {
"description": "Scenario id.",
"type": "string"
},
"input": {
"additionalProperties": true,
"description": "The decision inputs that produced the snapshot.",
"type": [
"object",
"null"
]
},
"resultSnapshot": {
"description": "The decision result captured at save time; ranked offers live at actions[0].offers[]."
}
},
"type": "object"
}
},
{
"description": "Check the calling account's API usage and remaining quota for this month (tier, used, remaining, limit, reset date). Use BEFORE running many calls to avoid hitting rate limits.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "get_usage",
"outputSchema": {
"additionalProperties": true,
"description": "API request usage and plan limit for the organization behind the API key.",
"properties": {
"limit": {
"description": "Monthly request allowance for the org's tier.",
"type": [
"number",
"null"
]
},
"remaining": {
"description": "Requests left this month. Null on an unlimited plan.",
"type": [
"number",
"null"
]
},
"requests_this_month": {
"description": "Requests since the start of the current month — the number metered against the limit.",
"type": "number"
},
"requests_today": {
"description": "Requests since midnight.",
"type": "number"
},
"reset_date": {
"description": "When the monthly counter resets.",
"type": [
"string",
"null"
]
},
"total_requests": {
"description": "All-time request count across the org's keys.",
"type": "number"
}
},
"type": "object"
}
},
{
"description": "List saved cohorts for the account (newest first). Returns id, name, member count, and last scan time. Keeps the payload small — use get_cohort for full member detail.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "list_cohorts",
"outputSchema": {
"additionalProperties": true,
"properties": {
"cohorts": {
"description": "The cohorts visible to the API key making the call. Empty when the org has none; the MCP layer wraps the upstream array so the result is always an object.",
"items": {
"additionalProperties": true,
"description": "A saved cohort: a named set of borrower records the org can re-scan for savings.",
"type": "object"
},
"type": "array"
},
"count": {
"description": "Number of items in the array above. There is no pagination on this route — this is the complete set for the org, not a page.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Reference tool: Discover credit unions by state or nearest to a 5-digit ZIP. State listings include rate availability, member count, and reported location count. ZIP discovery ranks NCUA-reported branches by estimated straight-line miles from the ZIP center. For personalized rate recommendations, use get_financing_decision instead.",
"inputSchema": {
"properties": {
"state": {
"description": "Optional: Filter to a specific state (2-letter code). If not provided, returns all states.",
"type": "string"
},
"zip": {
"description": "Optional: Find the closest credit unions by NCUA-reported branch location. Distances are ZIP-centroid straight-line estimates. When supplied, ZIP discovery takes precedence over state listing.",
"pattern": "^[0-9]{5}$",
"type": "string"
}
},
"type": "object"
},
"name": "list_credit_unions",
"outputSchema": {
"additionalProperties": true,
"properties": {
"credit_unions": {
"description": "The credit unions in this state, alphabetical by name.",
"items": {
"additionalProperties": true,
"properties": {
"city": {
"description": "Headquarters city, lower-cased as stored.",
"type": [
"string",
"null"
]
},
"has_rates": {
"description": "True when this credit union has published rates on file; false means it is known but nothing is currently quotable.",
"type": [
"boolean",
"null"
]
},
"last_verified": {
"description": "UTC timestamp when rates were last successfully scraped. Null means never successfully scraped.",
"type": [
"string",
"null"
]
},
"location_count": {
"description": "Number of NCUA-reported branch locations. 0 can mean genuinely branchless or simply not reported.",
"type": [
"number",
"null"
]
},
"members": {
"description": "Member count from the NCUA quarterly call report. Null when no NCUA profile is linked.",
"type": [
"number",
"null"
]
},
"name": {
"description": "Credit union name as displayed, usually without the words 'Credit Union'.",
"type": [
"string",
"null"
]
},
"product_count": {
"description": "Number of distinct rate products currently on file. 0 when has_rates is false.",
"type": [
"number",
"null"
]
},
"slug": {
"description": "URL-safe identifier used in rateapi.dev links and as the `slug` argument to get_credit_union.",
"type": [
"string",
"null"
]
},
"url": {
"description": "The credit union's own website.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"state": {
"description": "Lower-cased two-letter state code the listing is scoped to.",
"type": [
"string",
"null"
]
},
"state_name": {
"description": "Full state name, e.g. 'California'.",
"type": [
"string",
"null"
]
},
"summary": {
"description": "One-sentence plain-English summary of this result, safe to quote directly to the user.",
"type": [
"string",
"null"
]
},
"total_credit_unions": {
"description": "Number of credit unions known in this state, including those with no published rates.",
"type": [
"number",
"null"
]
},
"verified_last_7_days": {
"description": "How many have had their rates re-scraped and confirmed in the past 7 days; the rest may be staler.",
"type": [
"number",
"null"
]
},
"with_rates": {
"description": "How many of those credit unions currently have published rate data — always smaller than total_credit_unions.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Recall past financing decisions made on this account (audit log). Filter by request_id to look up a specific prior decision, or paginate with limit/offset.",
"inputSchema": {
"properties": {
"limit": {
"description": "Max rows (default 20, max 100)",
"type": "number"
},
"offset": {
"description": "Pagination offset",
"type": "number"
},
"request_id": {
"description": "Optional: look up a specific decision by its request_id",
"type": "string"
}
},
"type": "object"
},
"name": "list_decision_logs",
"outputSchema": {
"additionalProperties": true,
"description": "Audit rows for past /v1/decisions calls made by this organization's keys.",
"properties": {
"has_more": {
"description": "True when further pages exist.",
"type": "boolean"
},
"logs": {
"description": "Audit rows, newest first.",
"items": {
"additionalProperties": true,
"properties": {
"api_key_id": {
"description": "Key that made the call.",
"type": "string"
},
"id": {
"description": "Audit row id.",
"type": "number"
},
"request_id": {
"description": "Caller-supplied request id — the handle for recalling one decision.",
"type": "string"
},
"status_code": {
"description": "HTTP status the decision call returned.",
"type": "number"
},
"timestamp": {
"description": "When the decision was made.",
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"total": {
"description": "Total matching rows across all pages.",
"type": "number"
}
},
"type": "object"
}
},
{
"description": "List the account's scheduled digests (cohort, email, cadence, enabled, last run).",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "list_digests",
"outputSchema": {
"additionalProperties": true,
"properties": {
"count": {
"description": "Number of items in the array above. There is no pagination on this route — this is the complete set for the org, not a page.",
"type": [
"number",
"null"
]
},
"digests": {
"description": "The digests visible to the API key making the call. Empty when the org has none; the MCP layer wraps the upstream array so the result is always an object.",
"items": {
"additionalProperties": true,
"description": "A scheduled email digest for a cohort, with its cadence and last run time.",
"type": "object"
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "List the organization's branded rate-email campaigns (name, criteria, cadence, status, last run).",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "list_email_campaigns",
"outputSchema": {
"additionalProperties": true,
"properties": {
"campaigns": {
"description": "The campaigns visible to the API key making the call. Empty when the org has none; the MCP layer wraps the upstream array so the result is always an object.",
"items": {
"additionalProperties": true,
"description": "A branded email campaign, with its products, recipients and send state.",
"type": "object"
},
"type": "array"
},
"count": {
"description": "Number of items in the array above. There is no pagination on this route — this is the complete set for the org, not a page.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
{
"description": "List all monitors associated with your API key. Supports pagination and filtering by status.",
"inputSchema": {
"properties": {
"limit": {
"description": "Maximum number of monitors to return (1-100). Defaults to 20.",
"type": "number"
},
"offset": {
"description": "Number of monitors to skip for pagination. Defaults to 0.",
"type": "number"
},
"status": {
"description": "Filter monitors by status.",
"enum": [
"active",
"paused",
"disabled"
],
"type": "string"
}
},
"type": "object"
},
"name": "list_monitors",
"outputSchema": {
"additionalProperties": true,
"description": "A page of the account's rate monitors, with counts.",
"properties": {
"monitors": {
"description": "The monitors on this page (a condensed view — call get_monitor for full conditions).",
"items": {
"additionalProperties": true,
"properties": {
"conditions_count": {
"description": "How many trigger conditions the monitor has.",
"type": "number"
},
"cooldown_hours": {
"description": "Minimum hours between triggers.",
"type": [
"number",
"null"
]
},
"created_at": {
"description": "ISO-8601 creation timestamp.",
"type": [
"string",
"null"
]
},
"id": {
"description": "Monitor id.",
"type": "string"
},
"last_triggered_at": {
"description": "ISO-8601 timestamp of the last trigger, null if never.",
"type": [
"string",
"null"
]
},
"name": {
"description": "Monitor label.",
"type": "string"
},
"status": {
"description": "'active' or 'paused'.",
"type": "string"
},
"webhook_url": {
"description": "Delivery URL.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"pagination": {
"additionalProperties": true,
"description": "Page position.",
"properties": {
"has_more": {
"description": "True when further pages exist.",
"type": "boolean"
},
"limit": {
"description": "Page size used.",
"type": "number"
},
"offset": {
"description": "Zero-based offset of this page.",
"type": "number"
},
"total": {
"description": "Total monitors on the account.",
"type": "number"
}
},
"type": "object"
},
"summary": {
"description": "Human-readable count of total, active, and paused monitors.",
"type": "string"
}
},
"type": "object"
}
},
{
"description": "List the rate alerts subscribed for a given email (status, product, state, intent, target, last notified).",
"inputSchema": {
"properties": {
"email": {
"description": "The email whose alerts to list. Required.",
"type": "string"
}
},
"required": [
"email"
],
"type": "object"
},
"name": "list_rate_alerts",
"outputSchema": {
"additionalProperties": true,
"description": "A borrower's rate alerts, looked up by email. Unsubscribed alerts are excluded.",
"properties": {
"alerts": {
"description": "The borrower's alerts, newest first.",
"items": {
"additionalProperties": true,
"properties": {
"alert_id": {
"description": "Alert id.",
"type": "string"
},
"created_at": {
"description": "When the alert was created.",
"type": [
"string",
"number",
"null"
]
},
"intent": {
"description": "Borrower intent, e.g. 'purchase' or 'refinance'.",
"type": [
"string",
"null"
]
},
"last_notified_at": {
"description": "When the borrower was last emailed, null if never.",
"type": [
"string",
"number",
"null"
]
},
"product_type": {
"description": "Product the alert watches.",
"type": [
"string",
"null"
]
},
"region_preset": {
"description": "Region preset key, or null.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Legacy scalar state — first entry of `states`.",
"type": [
"string",
"null"
]
},
"states": {
"description": "Full list of watched state codes.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"status": {
"description": "'pending', 'active', 'unsubscribed', or 'bounced'.",
"type": "string"
},
"target": {
"additionalProperties": true,
"description": "The threshold that fires the alert.",
"properties": {
"field": {
"description": "Watched field.",
"type": [
"string",
"null"
]
},
"operator": {
"description": "Comparison operator.",
"type": [
"string",
"null"
]
},
"value": {
"description": "Threshold value.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
"type": "object"
},
"type": "array"
},
"count": {
"description": "Number of alerts returned.",
"type": "number"
}
},
"type": "object"
}
},
{
"description": "List and filter raw rate rows (the core data primitive) by product, state, lender, and term with limit/offset pagination. Boats, RVs, motorcycles, and powersports are first-class product types; auto_loan means cars.",
"inputSchema": {
"properties": {
"audience": {
"description": "WHO the product is for, orthogonal to product type: 'business' returns business-audience products across every category (DSCR mortgages, business deposits, SBA loans); 'consumer' excludes them.",
"enum": [
"business",
"consumer"
],
"type": "string"
},
"lender": {
"description": "Filter by credit-union name (substring, case-insensitive)",
"type": "string"
},
"limit": {
"description": "1-500, default 50",
"type": "number"
},
"loan_program": {
"type": "string"
},
"max_apr": {
"type": "number"
},
"min_apr": {
"type": "number"
},
"offset": {
"description": "Pagination offset, default 0",
"type": "number"
},
"product_type": {
"enum": [
"mortgage",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"credit_card",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"sort": {
"description": "Default apr_asc",
"enum": [
"apr_asc",
"apr_desc",
"rate_asc",
"rate_desc",
"updated_desc"
],
"type": "string"
},
"state": {
"description": "2-letter US state code; omit for all states",
"type": "string"
},
"term_months": {
"type": "number"
}
},
"type": "object"
},
"name": "list_rates",
"outputSchema": {
"additionalProperties": true,
"properties": {
"as_of": {
"description": "UTC timestamp of the newest rate in this result set; the whole page is at least this stale.",
"type": [
"string",
"null"
]
},
"filters": {
"additionalProperties": true,
"description": "The filters that were applied to produce these rows; null members were not constrained.",
"properties": {
"audience": {
"description": "Borrower-audience filter, e.g. first-time buyer programs. Null means unrestricted."
},
"lender": {
"description": "Lender name filter applied. Null means all lenders."
},
"loan_program": {
"description": "Loan program filter such as 'conventional' or 'va'. Null means all programs."
},
"max_apr": {
"description": "Upper APR bound applied, in percent. Null means no ceiling."
},
"min_apr": {
"description": "Lower APR bound applied, in percent. Null means no floor."
},
"occupancy": {
"description": "Occupancy filter such as primary residence or investment property. Null means unrestricted."
},
"product_type": {
"description": "Product category filter applied, e.g. 'mortgage'. Null means all categories.",
"type": [
"string",
"null"
]
},
"sort": {
"description": "Ordering applied to the rows, e.g. 'apr_asc' (cheapest APR first).",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter state filter applied. Null means nationwide.",
"type": [
"string",
"null"
]
},
"term_months": {
"description": "Term filter in months. Null means all terms were included, so rows may mix 15- and 30-year products."
}
},
"type": "object"
},
"pagination": {
"additionalProperties": true,
"description": "Where this page sits within the full result set.",
"properties": {
"has_more": {
"description": "True when further pages of matching rows remain beyond this one.",
"type": [
"boolean",
"null"
]
},
"limit": {
"description": "Maximum rows requested for this page.",
"type": [
"number",
"null"
]
},
"offset": {
"description": "Number of rows skipped before this page.",
"type": [
"number",
"null"
]
},
"returned": {
"description": "Rows actually included in this response.",
"type": [
"number",
"null"
]
},
"total": {
"description": "Total rows matching the filters across all pages — usually far larger than `returned`. Use this when telling the user how many offers exist.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"rates": {
"description": "The matching rate rows for this page, in the order given by filters.sort.",
"items": {
"additionalProperties": true,
"properties": {
"apr": {
"description": "Annual percentage rate in percent, including lender fees. NULL when the lender published no APR — the API deliberately does not substitute the note rate, so never present `rate` as an APR. Some legacy rows still carry an APR equal to the note rate; those heal on that credit union's next scrape.",
"type": [
"number",
"null"
]
},
"as_of": {
"description": "UTC timestamp when this individual rate was last scraped from the lender.",
"type": [
"string",
"null"
]
},
"display_name": {
"description": "Normalized, human-readable product name for comparison across lenders.",
"type": [
"string",
"null"
]
},
"eligibility": {
"description": "Membership-eligibility snapshot for this lender, including status, charter type, and confidence; 'unknown' status means it could not be evaluated for this user.",
"type": "object"
},
"lender": {
"description": "Full name of the credit union publishing this rate.",
"type": [
"string",
"null"
]
},
"loan_program": {
"description": "Underwriting program, e.g. 'conventional', 'va', 'fha', 'jumbo'.",
"type": [
"string",
"null"
]
},
"loan_purpose": {
"description": "Purpose the rate applies to, e.g. 'purchase' or 'refinance'. Null means the lender did not distinguish.",
"type": [
"string",
"null"
]
},
"points": {
"description": "Discount points required for this rate, where 1 point = 1% of the loan amount.",
"type": [
"number",
"null"
]
},
"product_key": {
"description": "Internal pipe-delimited product fingerprint used for deduplication; never show it to the user.",
"type": [
"string",
"null"
]
},
"product_name": {
"description": "The lender's own wording for the product, e.g. 'Home Purchases/Refinances 7 & 1 Year ARM'.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Normalized product category, e.g. '30-year-fixed', 'arm', '10-year-fixed'.",
"type": [
"string",
"null"
]
},
"rate": {
"description": "Note rate in percent (6.125 = 6.125%), excluding fees. On an ARM this is only the initial rate.",
"type": [
"number",
"null"
]
},
"rate_phase": {
"description": "Which phase of the rate this row describes: 'standard' for the ordinary rate, versus an introductory or teaser phase on ARMs and promotional products.",
"type": [
"string",
"null"
]
},
"rateapi_url": {
"description": "Public rateapi.dev profile page for this lender.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter state code of the lender.",
"type": [
"string",
"null"
]
},
"term_months": {
"description": "Term in months for this product. Null when the lender did not publish a term, common for ARMs and lines of credit."
},
"vehicle_condition": {
"description": "For auto loans, whether the rate applies to a new or used vehicle. Null for non-auto products."
},
"vehicle_type": {
"description": "For vehicle loans, the vehicle class (car, RV, boat, motorcycle). Null on non-vehicle products; null on an auto loan means a car."
}
},
"type": "object"
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "List saved client scenarios for the account, newest first.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "list_scenarios",
"outputSchema": {
"additionalProperties": true,
"properties": {
"count": {
"description": "Number of items in the array above. There is no pagination on this route — this is the complete set for the org, not a page.",
"type": [
"number",
"null"
]
},
"scenarios": {
"description": "The scenarios visible to the API key making the call. Empty when the org has none; the MCP layer wraps the upstream array so the result is always an object.",
"items": {
"additionalProperties": true,
"description": "A saved scenario: a stored decision input plus the result snapshot captured when it was saved.",
"type": "object"
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "List all hosted shareable report links for the account, newest first. Returns token, scenario_id, client_name, views, last_viewed_at, revoked, created_at, and url for each share. Use this to see view analytics and manage which links are still live.",
"inputSchema": {
"properties": {},
"type": "object"
},
"name": "list_shares",
"outputSchema": {
"additionalProperties": true,
"properties": {
"count": {
"description": "Number of items in the array above. There is no pagination on this route — this is the complete set for the org, not a page.",
"type": [
"number",
"null"
]
},
"shares": {
"description": "The shares visible to the API key making the call. Empty when the org has none; the MCP layer wraps the upstream array so the result is always an object.",
"items": {
"additionalProperties": true,
"description": "A share link issued for a scenario, with its view count and revocation state.",
"type": "object"
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "Org-scoped webhook delivery observability for the authenticated API key. Lists the per-event webhook delivery log for your monitors — each row shows status (delivered/failed/pending), HTTP response code, error, response time, the destination URL, and timestamp — with a roll-up summary (total/delivered/failed/pending). Use this to surface SILENT webhook failures (a delivery that never reached your endpoint). Filter by monitor_id and/or status. To replay a failed (or any) delivery, set redeliver_id to that row's id; the original payload is re-sent verbatim and the replay is itself audited. Distinct from deliver_test_webhook, which sends a brand-new simulated event.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"limit": {
"default": 50,
"maximum": 100,
"minimum": 1,
"type": "integer"
},
"monitor_id": {
"description": "Filter to one monitor.",
"type": "string"
},
"offset": {
"default": 0,
"minimum": 0,
"type": "integer"
},
"redeliver_id": {
"description": "If set, replay the delivery with this audit-log id instead of listing (maps to action:redeliver, delivery_id).",
"type": "integer"
},
"status": {
"description": "Filter by delivery outcome.",
"enum": [
"delivered",
"failed",
"pending"
],
"type": "string"
}
},
"type": "object"
},
"name": "list_webhook_deliveries",
"outputSchema": {
"additionalProperties": true,
"description": "Webhook delivery audit rows, or the outcome of a redelivery when redeliver_id was supplied. The handler wraps the API response in a self-orchestrating envelope, so the raw payload lives under structuredContent.",
"properties": {
"content": {
"description": "MCP content blocks carrying a one-line human summary of the deliveries or the redelivery.",
"items": {
"additionalProperties": true,
"properties": {
"text": {
"description": "The summary line.",
"type": "string"
},
"type": {
"description": "Content block type, always 'text' here.",
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"disclosures": {
"description": "Scoping and replay-semantics caveats.",
"items": {
"type": "string"
},
"type": "array"
},
"next_actions": {
"description": "Suggested follow-up tool names.",
"items": {
"type": "string"
},
"type": "array"
},
"structuredContent": {
"additionalProperties": true,
"description": "The raw /v1/webhook-deliveries payload. In list mode: deliveries, summary, limit, offset. In redelivery mode: redelivered, delivery_id, new_status, delivery_status_code, response_time_ms, error.",
"properties": {
"deliveries": {
"description": "Audit rows, newest last. List mode only.",
"items": {
"additionalProperties": true,
"properties": {
"delivery_error": {
"description": "Failure reason, null on success.",
"type": [
"string",
"null"
]
},
"delivery_status_code": {
"description": "HTTP status from the endpoint, null when no response.",
"type": [
"number",
"null"
]
},
"event_id": {
"description": "Id of the triggering event.",
"type": "string"
},
"event_type": {
"description": "Event type carried in the payload.",
"type": "string"
},
"id": {
"description": "Delivery row id — pass as redeliver_id to replay it.",
"type": "number"
},
"is_simulation": {
"description": "True when the delivery came from a test/simulate call.",
"type": "boolean"
},
"monitor_id": {
"description": "Monitor that produced the delivery.",
"type": "string"
},
"response_time_ms": {
"description": "Endpoint response time in milliseconds.",
"type": [
"number",
"null"
]
},
"status": {
"description": "Derived status: 'delivered', 'failed', or 'pending'.",
"type": "string"
},
"timestamp": {
"description": "ISO-8601 time of the delivery attempt.",
"type": "string"
},
"trigger_type": {
"description": "What caused the fire (e.g. a rate change or a simulation).",
"type": "string"
},
"webhook_url": {
"description": "Destination URL.",
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"delivery_id": {
"description": "The delivery row that was replayed. Redelivery mode only.",
"type": "number"
},
"error": {
"description": "Failure reason for the replay, null on success.",
"type": [
"string",
"null"
]
},
"limit": {
"description": "Page size used. List mode only.",
"type": "number"
},
"new_status": {
"description": "Status of the replay attempt. Redelivery mode only.",
"type": "string"
},
"offset": {
"description": "Zero-based page offset. List mode only.",
"type": "number"
},
"redelivered": {
"description": "True when a stored payload was replayed. Redelivery mode only.",
"type": "boolean"
},
"summary": {
"additionalProperties": true,
"description": "Counts across the same filter as the rows. List mode only.",
"properties": {
"delivered": {
"description": "Successful deliveries.",
"type": "number"
},
"failed": {
"description": "Failed deliveries.",
"type": "number"
},
"pending": {
"description": "Not yet attempted or unresolved.",
"type": "number"
},
"total": {
"description": "Matching deliveries.",
"type": "number"
}
},
"type": "object"
}
},
"type": "object"
}
},
"type": "object"
}
},
{
"description": "Estimate the largest loan a borrower can afford from income and a target debt-to-income (DTI) ratio. Returns max monthly payment, max loan amount, and the rate used. If no rate is supplied, the current best market rate for the product/state is used.",
"inputSchema": {
"properties": {
"dti": {
"description": "Target debt-to-income ratio as a decimal, e.g. 0.36",
"type": "number"
},
"existing_monthly_debt": {
"description": "Optional existing monthly debt payments to subtract",
"type": "number"
},
"income_annual": {
"description": "Gross annual income in dollars",
"type": "number"
},
"product_type": {
"description": "Product for the market-rate lookup, default mortgage",
"type": "string"
},
"rate": {
"description": "Optional annual interest rate, e.g. 6.5. If omitted, best market rate is used.",
"type": "number"
},
"state": {
"description": "US state code (used to look up a market rate when rate is omitted)",
"type": "string"
},
"term_months": {
"description": "Loan term in months (e.g. 360)",
"type": "number"
}
},
"required": [
"income_annual",
"dti",
"term_months"
],
"type": "object"
},
"name": "max_loan",
"outputSchema": {
"additionalProperties": true,
"properties": {
"assumptions": {
"additionalProperties": true,
"description": "The inputs the calculation rests on; state them alongside the number.",
"properties": {
"existing_monthly_debt": {
"description": "Existing monthly debt payments in dollars deducted from the DTI budget.",
"type": [
"number",
"null"
]
},
"target_dti": {
"description": "Debt-to-income ratio targeted, as a decimal (0.43 = 43%).",
"type": [
"number",
"null"
]
},
"term_months": {
"description": "Loan term in months used to convert the payment into a principal.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"max_loan_amount": {
"description": "Largest loan principal in dollars that payment supports at the rate and term used. This is a loan amount, not a home price.",
"type": [
"string",
"null"
]
},
"max_monthly_payment": {
"description": "Largest monthly payment in dollars the income supports at the target DTI, after subtracting existing debts.",
"type": [
"string",
"null"
]
},
"note": {
"description": "Required caveat that this uses income and DTI only; lenders also weigh credit, down payment, and reserves.",
"type": [
"string",
"null"
]
},
"rate_source": {
"description": "Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.",
"type": [
"string",
"null"
]
},
"rate_used": {
"description": "Interest rate, in percent, used for every calculation in this result. Check rate_source to see whether it came from the caller or from live market data.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Given a discount-points / lender-credit tradeoff menu for a candidate loan, returns break-even months, lifetime savings, and the optimal point-spend. The points analog of refinance_break_even.",
"inputSchema": {
"properties": {
"base_rate": {
"description": "The no-points (par) interest rate, percent, e.g. 6.75.",
"type": "number"
},
"hold_months": {
"description": "Expected time-in-loan horizon for lifetime savings; defaults to term_months.",
"type": "number"
},
"loan_amount": {
"description": "Loan principal in dollars (>0).",
"type": "number"
},
"options": {
"description": "Points/lender-credit tradeoff menu to evaluate.",
"items": {
"properties": {
"points": {
"description": "Discount points as % of loan (positive) or lender credit (negative); 1 = 1% of loan.",
"type": "number"
},
"rate": {
"description": "Resulting interest rate at that point spend, percent.",
"type": "number"
}
},
"required": [
"points",
"rate"
],
"type": "object"
},
"maxItems": 25,
"minItems": 1,
"type": "array"
},
"state": {
"description": "Optional 2-letter state (validated only if supplied).",
"type": "string"
},
"term_months": {
"default": 360,
"description": "Loan term in months, e.g. 360.",
"type": "number"
}
},
"required": [
"loan_amount",
"term_months",
"base_rate",
"options"
],
"type": "object"
},
"name": "optimize_buydown",
"outputSchema": {
"additionalProperties": true,
"properties": {
"assumed_defaults": {
"additionalProperties": true,
"description": "Inputs filled in because the caller did not supply them, notably the holding period that decides the winner.",
"properties": {
"hold_months": {
"description": "Holding period in months assumed because the caller did not supply one.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"base_monthly_payment": {
"description": "Monthly principal-and-interest payment in dollars at the base rate.",
"type": [
"string",
"null"
]
},
"base_rate": {
"description": "The no-points starting rate as a percent string, the baseline every option is measured against.",
"type": [
"string",
"null"
]
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"hold_months": {
"description": "How long the borrower is assumed to keep the loan. Buying points only wins if this exceeds the option's break-even.",
"type": [
"number",
"null"
]
},
"loan_amount": {
"description": "Loan amount in dollars as a formatted string; point costs are a percentage of this.",
"type": [
"string",
"null"
]
},
"next_actions": {
"description": "Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.",
"items": {
"additionalProperties": true,
"properties": {
"tool": {
"description": "Name of the follow-up MCP tool to call next.",
"type": [
"string",
"null"
]
},
"why": {
"description": "One-line reason this follow-up tool would be useful given the current result.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"optimal": {
"additionalProperties": true,
"description": "The option that maximizes net savings over the assumed holding period.",
"properties": {
"break_even_months": {
"description": "Months to recover the winning option's point cost.",
"type": [
"number",
"null"
]
},
"point_cost": {
"description": "Upfront cost in dollars of the winning option.",
"type": [
"string",
"null"
]
},
"points": {
"description": "Points bought in the winning option.",
"type": [
"number",
"null"
]
},
"rate": {
"description": "Rate as a percent string in the winning option.",
"type": [
"string",
"null"
]
},
"savings_over_hold": {
"description": "Net dollars the winning option saves over the assumed holding period.",
"type": [
"string",
"null"
]
},
"why": {
"description": "One-sentence justification of the winning option, safe to quote.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"options": {
"description": "Each points/rate combination modeled, including negative points (lender credits) where supplied.",
"items": {
"additionalProperties": true,
"properties": {
"break_even_months": {
"description": "Months for the monthly savings to repay the point cost. 0 on the baseline option, since nothing was spent.",
"type": [
"number",
"null"
]
},
"lifetime_interest": {
"description": "Total interest in dollars over the full term at this rate, ignoring the hold period.",
"type": [
"string",
"null"
]
},
"monthly_payment": {
"description": "Monthly principal-and-interest payment in dollars at this option's rate.",
"type": [
"string",
"null"
]
},
"monthly_savings": {
"description": "Dollars per month saved versus the base rate; $0 on the baseline option.",
"type": [
"string",
"null"
]
},
"point_cost": {
"description": "Upfront cost in dollars for these points, as a formatted string.",
"type": [
"string",
"null"
]
},
"points": {
"description": "Points bought, where 1 point = 1% of the loan amount. Negative values are lender credits that raise the rate in exchange for cash at closing.",
"type": [
"number",
"null"
]
},
"rate": {
"description": "Note rate as a percent string after this buydown.",
"type": [
"string",
"null"
]
},
"savings_over_hold": {
"description": "Net dollars saved over hold_months after paying for the points; this is the figure to compare across options.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"reason": {
"description": "Why no buydown option was recommended, present only in that case — e.g. 'No option produces positive net savings over the hold horizon; paying par (no points) is best.'",
"type": [
"string",
"null"
]
},
"recommendation": {
"description": "The action implied by the analysis, e.g. 'buy_points', 'no_points', or 'take_credit'.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
},
"term_months": {
"description": "Loan term in months (360 = 30 years, 180 = 15 years, 60 = 5 years).",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
{
"description": "For low-down-payment borrowers (LTV > 80%): projects when private mortgage insurance (PMI) drops off, the total PMI paid until then, and how much extra monthly principal cancels PMI sooner. Reuses the same amortization + PMI logic as estimate_monthly_cost. If no rate is supplied, the current best market rate for the state is used. Use for 'when does my PMI go away / how do I get rid of PMI faster?' questions.",
"inputSchema": {
"properties": {
"credit_score": {
"description": "Optional, for market-rate lookup.",
"type": "number"
},
"down_payment": {
"description": "Cash down, dollars. Default 0.",
"type": "number"
},
"extra_monthly_payment": {
"description": "Optional extra principal/month to model faster cancel. Default 0.",
"type": "number"
},
"home_price": {
"description": "Purchase/appraised price. Required unless loan_amount given.",
"type": "number"
},
"loan_amount": {
"description": "Optional explicit loan; overrides home_price - down_payment.",
"type": "number"
},
"pmi_rate": {
"description": "Annual PMI as % of loan balance. Default 0.5.",
"type": "number"
},
"rate": {
"description": "Annual rate %, e.g. 6.5. Omit -> best market rate for state.",
"type": "number"
},
"state": {
"description": "2-letter code for market-rate lookup. Default CA.",
"type": "string"
},
"term_months": {
"description": "Loan term in months. Default 360.",
"type": "number"
}
},
"required": [],
"type": "object"
},
"name": "project_pmi_removal",
"outputSchema": {
"additionalProperties": true,
"properties": {
"assumed_defaults": {
"additionalProperties": true,
"description": "Inputs the caller did not supply that were filled in with defaults. State these explicitly to the user, since they drive the numbers.",
"properties": {
"ltv_basis": {
"description": "LTV basis assumed, e.g. 'original_value' (purchase price) rather than a current appraisal.",
"type": [
"string",
"null"
]
},
"pmi_rate": {
"description": "PMI rate assumed, as a percent string. Note this field carries a formatting quirk: it renders the annual PMI rate as a whole-number percent, so read it as the annual PMI rate and prefer monthly_pmi_initial for the actual dollar cost.",
"type": [
"string",
"null"
]
},
"state": {
"description": "State code assumed for market-rate lookups because the caller did not supply one.",
"type": [
"string",
"null"
]
},
"term_months": {
"description": "Loan term in months assumed because the caller did not supply one.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"down_payment": {
"description": "Cash in dollars put down at closing.",
"type": [
"string",
"null"
]
},
"extra_needed": {
"description": "How much extra principal per month would be required to hit 80% LTV by various target dates.",
"items": {
"additionalProperties": true,
"properties": {
"extra_monthly": {
"description": "Extra principal in dollars per month required to hit that target — often far beyond what a borrower can sustain.",
"type": [
"string",
"null"
]
},
"reach_80_in_months": {
"description": "Target number of months to reach 80% LTV.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"home_price": {
"description": "Purchase price in dollars, as a formatted string.",
"type": [
"string",
"null"
]
},
"loan_amount": {
"description": "Amount borrowed in dollars.",
"type": [
"string",
"null"
]
},
"monthly_pi": {
"description": "Monthly principal-and-interest payment in dollars, excluding PMI.",
"type": [
"string",
"null"
]
},
"monthly_pmi_initial": {
"description": "Monthly PMI premium in dollars at the start, before the balance amortizes down.",
"type": [
"string",
"null"
]
},
"next_actions": {
"description": "Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.",
"items": {
"additionalProperties": true,
"properties": {
"tool": {
"description": "Name of the follow-up MCP tool to call next.",
"type": [
"string",
"null"
]
},
"why": {
"description": "One-line reason this follow-up tool would be useful given the current result.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"pmi_applies": {
"description": "True when PMI is required at origination; false means the rest of this projection is moot.",
"type": [
"boolean",
"null"
]
},
"pmi_drop": {
"additionalProperties": true,
"description": "The two dates PMI can come off: the earlier one the borrower must request, the later one is automatic.",
"properties": {
"auto_terminate_78": {
"description": "When the balance reaches 78% LTV and the servicer must drop PMI automatically. Later, and more expensive, than requesting at 80%.",
"type": "object"
},
"ltv_basis": {
"description": "What LTV is measured against: 'original_value' means the purchase price, so appreciation does not accelerate the drop unless the borrower pays for a new appraisal.",
"type": [
"string",
"null"
]
},
"request_cancel_80": {
"description": "When the balance reaches 80% LTV — the borrower must actively request cancellation at this point; it does not happen on its own.",
"type": "object"
}
},
"type": "object"
},
"rate_source": {
"description": "Where rate_used came from: 'provided' means the caller supplied it, 'market' means it was resolved from the best live published rate for this state and product.",
"type": [
"string",
"null"
]
},
"rate_used": {
"description": "Interest rate, in percent, used for every calculation in this result. Check rate_source to see whether it came from the caller or from live market data.",
"type": [
"string",
"null"
]
},
"starting_ltv": {
"description": "Loan-to-value at origination as a percent string. PMI applies above 80%.",
"type": [
"string",
"null"
]
},
"total_pmi_paid": {
"description": "Total PMI in dollars paid before it drops off, on the scheduled payments alone.",
"type": [
"string",
"null"
]
},
"with_extra_payment": {
"additionalProperties": true,
"description": "How the caller's extra monthly principal payment accelerates PMI removal.",
"properties": {
"extra_monthly": {
"description": "Extra principal in dollars paid each month in this scenario.",
"type": [
"string",
"null"
]
},
"months_saved": {
"description": "Months earlier PMI drops off thanks to the extra payments.",
"type": [
"number",
"null"
]
},
"new_drop_date": {
"description": "Calendar year-month when PMI now drops off.",
"type": [
"string",
"null"
]
},
"new_drop_month": {
"description": "Payment number when PMI now drops off, counting from the first payment.",
"type": [
"number",
"null"
]
},
"pmi_saved": {
"description": "PMI dollars avoided by paying down faster.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
"type": "object"
}
},
{
"description": "RECOMMENDED WHEN THE USER ALREADY HAS A QUOTE: answers \"is this rate any good?\" for a specific number a borrower was offered. Use this whenever someone says they were quoted / offered / approved at a rate and wants to know if it is fair, good, competitive, high, or a rip-off — e.g. \"I got offered 6.9% on a 30-year in Ohio, is that fair?\", \"my dealer quoted 8.4% on a used car loan\", \"is 7.1% high for a HELOC in TX?\". Given a product_type, state, and rate (and optional apr/fees/amount/term_months), returns the percentile of the quote within the live market distribution, a verdict (market_leading, plausible, suspicious_low, overpriced), whether it falls below the known product rate floor, and the market min/median/max with an as_of date. Prefer this over get_financing_decision for quote-in-hand questions: the user wants a verdict on THEIR number, not a list of other offers. Set include_better_offers=true to get named statewide lenders beating the quote. When the user provides a ZIP, set include_nearby_offers=true to pair product-matched rates with the closest credit unions by NCUA-reported branch location; distances are straight-line ZIP-center estimates, never driving distance. Every response also returns `share_url` — a link to this same check on rateapi.dev that the borrower can send to their lender or broker. Surface it whenever the user might act on the result; it re-runs against live rates when opened, so it never goes stale. NOTE: this is the BORROWER-side tool; check_competitive_position is the lender-side equivalent for benchmarking a lender's own published pricing. If the quote is an ADJUSTABLE-rate mortgage (the user says ARM / adjustable / \"5/1\" / \"5/5\" / \"7/1\"), pass product_type=mortgage_arm rather than mortgage — ARMs are scored against their own market. Caveat to surface to the user: the comparison does not currently segment by credit score, LTV, or points, and quoted fees are not folded into the APR comparison.",
"inputSchema": {
"properties": {
"amount": {
"description": "Loan amount in dollars. Optional — also sharpens better-offer payment math.",
"type": "number"
},
"apr": {
"description": "The quoted APR as a percentage. Optional — falls back to rate if omitted.",
"type": "number"
},
"credit_score": {
"description": "Borrower's credit score (300-850). Optional; improves better-offer matching.",
"type": "number"
},
"fees": {
"description": "Quoted fees in dollars. Optional, used only for the note.",
"type": "number"
},
"include_better_offers": {
"description": "Set TRUE for negotiation questions. Adds `better_offers`: named lenders currently beating the quote, each with the APR gap in basis points, estimated monthly savings, and `can_you_join` (yes / likely / unknown) so you only cite alternatives the borrower can realistically obtain. This is what turns a percentile into something the user can act on — prefer it whenever the user asks whether their rate is fair or what to do about it.",
"type": "boolean"
},
"include_nearby_offers": {
"description": "Set true with zip to return product-matched rates from credit unions ranked by the closest NCUA-reported branch. Results include approximate straight-line miles, branch details, and the basis-point difference versus the quote.",
"type": "boolean"
},
"max_offers": {
"description": "How many better offers to return (1-5, default 3). Only applies with include_better_offers.",
"type": "number"
},
"product_type": {
"description": "Type of financing product the quote is for. Pick `mortgage_arm` — NOT `mortgage` — whenever the user names an adjustable-rate mortgage: \"ARM\", \"adjustable\", or a slash pair like \"5/1\", \"5/5\", \"7/1\", \"10/1\". ARM intro rates run structurally BELOW fixed rates, so scoring an ARM against the fixed market makes an ordinary quote look market-leading, which is the exact error this tool exists to prevent. All initial fixed periods share one ARM market. Use `mortgage` for fixed-rate mortgages and set term_months to pick 15- vs 30-year.",
"enum": [
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"mortgage",
"mortgage_arm",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"rate": {
"description": "The quoted interest rate as a percentage (e.g., 4.25). Required.",
"type": "number"
},
"state": {
"description": "US state code (2-letter, e.g., CA, TX). Required.",
"type": "string"
},
"term_months": {
"description": "Loan term in months. For MORTGAGES this selects which market the quote is scored against: pass 180 for a 15-year and 360 for a 30-year. 15-year rates run structurally lower, so omitting it on a 15-year quote compares it to 30-year offers and makes an ordinary rate look market-leading. Defaults to 30-year. Also sharpens better-offer payment math for every product.",
"type": "number"
},
"zip": {
"description": "Borrower ZIP code. Optional; sharpens membership eligibility and enables include_nearby_offers.",
"pattern": "^[0-9]{5}$",
"type": "string"
}
},
"required": [
"product_type",
"state",
"rate"
],
"type": "object"
},
"name": "rate_sanity_check",
"outputSchema": {
"additionalProperties": true,
"properties": {
"below_product_floor": {
"description": "True when the quote is implausibly low for this product, suggesting a teaser, a promotional tier, or a misread number rather than a real offer.",
"type": [
"boolean",
"null"
]
},
"better_offers": {
"description": "Statewide published offers that beat the quote, best first. Empty means nothing tracked beats it.",
"items": {
"additionalProperties": true,
"properties": {
"apr": {
"description": "APR of this offer in percent, including fees where published.",
"type": [
"number",
"null"
]
},
"apr_delta_bps": {
"description": "How much cheaper this offer is than the quote, in basis points (105 = 1.05 percentage points better).",
"type": [
"number",
"null"
]
},
"can_you_join": {
"description": "Whether the borrower appears able to join this credit union: 'unknown' means membership could not be evaluated, not that they are excluded.",
"type": [
"string",
"null"
]
},
"credit_union_id": {
"description": "Internal composite identifier 'name|city|STATE' of the lender.",
"type": [
"string",
"null"
]
},
"credit_union_name": {
"description": "Credit union publishing this better offer.",
"type": [
"string",
"null"
]
},
"credit_union_url": {
"description": "The credit union's own website.",
"type": [
"string",
"null"
]
},
"display_name": {
"description": "Normalized product name for comparison against the borrower's quote.",
"type": [
"string",
"null"
]
},
"eligibility": {
"description": "Membership-eligibility snapshot for this lender, including status, charter type, and confidence.",
"type": "object"
},
"estimated_monthly_savings": {
"description": "Dollars per month saved versus the quoted rate, at the assumed loan amount and term.",
"type": [
"number",
"null"
]
},
"estimated_total_savings": {
"description": "Dollars saved over the full assumed term versus the quoted rate — a whole-term figure, not annual.",
"type": [
"number",
"null"
]
},
"last_updated": {
"description": "UTC timestamp when this offer was last scraped from the lender.",
"type": [
"string",
"null"
]
},
"monthly_payment": {
"description": "Estimated principal-and-interest payment in dollars at this rate for the assumed amount and term.",
"type": [
"number",
"null"
]
},
"points": {
"description": "Discount points required for this rate, where 1 point = 1% of the loan amount.",
"type": [
"number",
"null"
]
},
"product_name": {
"description": "The lender's own wording for the product.",
"type": [
"string",
"null"
]
},
"rate": {
"description": "Note rate of this offer in percent, excluding fees.",
"type": [
"number",
"null"
]
},
"rateapi_url": {
"description": "Public rateapi.dev profile page for this credit union.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter state code of the lender.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"better_offers_meta": {
"additionalProperties": true,
"description": "The assumptions used to compute the savings figures on the better offers.",
"properties": {
"assumptions": {
"description": "Loan amount, term in months, and intent used for the payment math, plus `assumed` — true when these were defaulted rather than supplied by the caller.",
"type": "object"
}
},
"type": "object"
},
"classification": {
"description": "Verdict on the quote: 'market_leading', 'plausible', 'suspicious_low', 'overpriced', or 'unknown' when there is too little data to judge.",
"type": [
"string",
"null"
]
},
"compared_against": {
"description": "The market segment the quote was matched to, e.g. 'mortgage_30yr'. If this is not the borrower's actual product, the verdict does not apply.",
"type": [
"string",
"null"
]
},
"market": {
"additionalProperties": true,
"description": "Live market distribution the quote was scored against.",
"properties": {
"as_of": {
"description": "UTC timestamp of the newest rate in the market comparison set.",
"type": [
"string",
"null"
]
},
"count": {
"description": "Number of live published offers the min/median/max were computed from. Small counts make the median unreliable.",
"type": [
"number",
"null"
]
},
"max": {
"description": "Highest APR, in percent, among the live offers in this segment.",
"type": [
"number",
"null"
]
},
"median": {
"description": "Median APR, in percent, across the live offers in this segment; the fairest single number to describe 'the market'.",
"type": [
"number",
"null"
]
},
"min": {
"description": "Lowest APR, in percent, among the live offers in this market segment — the single best published deal, not a typical one.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"nearby_offers": {
"description": "Product-matched offers from credit unions with branches near the supplied ZIP, closest first. Included only when the caller asked for nearby offers.",
"items": {
"additionalProperties": true,
"properties": {
"apr": {
"description": "APR in percent, including fees where published.",
"type": [
"number",
"null"
]
},
"apr_delta_bps": {
"description": "Difference from the borrower's quoted APR in basis points; read `comparison` for the direction.",
"type": [
"number",
"null"
]
},
"branch": {
"description": "The nearest branch (name and street address) the distance was measured to.",
"type": "object"
},
"comparison": {
"description": "Whether this nearby offer is 'lower', 'higher', or the same as the borrower's quote.",
"type": [
"string",
"null"
]
},
"credit_union_id": {
"description": "Internal composite identifier 'name|city|STATE' of the lender.",
"type": [
"string",
"null"
]
},
"credit_union_name": {
"description": "Credit union publishing this nearby offer.",
"type": [
"string",
"null"
]
},
"display_name": {
"description": "Normalized product name for comparison across lenders.",
"type": [
"string",
"null"
]
},
"distance_method": {
"description": "Precision of the distance: 'branch_coordinate' (exact branch geocode) or 'zip_centroid' (coarser).",
"type": [
"string",
"null"
]
},
"distance_miles": {
"description": "Straight-line miles from the ZIP centroid to the nearest branch, not driving distance. Null when no branch geocode is available.",
"type": [
"number",
"null"
]
},
"last_updated": {
"description": "UTC timestamp when this offer was last scraped.",
"type": [
"string",
"null"
]
},
"points": {
"description": "Discount points required for this rate, where 1 point = 1% of the loan amount.",
"type": [
"number",
"null"
]
},
"product_name": {
"description": "The lender's own wording for the product; check it, since a jumbo or program-restricted product may not fit the borrower.",
"type": [
"string",
"null"
]
},
"proximity": {
"description": "How the lender qualified as nearby: 'same_zip' or 'distance'.",
"type": [
"string",
"null"
]
},
"rate": {
"description": "Note rate in percent, excluding fees.",
"type": [
"number",
"null"
]
},
"rateapi_url": {
"description": "Public rateapi.dev profile page for this credit union.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"nearby_offers_meta": {
"additionalProperties": true,
"description": "Context and caveats for the nearby-offer list.",
"properties": {
"disclosure": {
"description": "Required caveat that distances are straight-line estimates from ZIP centers and NCUA-reported branch locations.",
"type": [
"string",
"null"
]
},
"nearby_credit_union_count": {
"description": "How many credit unions were found near the ZIP before filtering to those publishing this product.",
"type": [
"number",
"null"
]
},
"precision": {
"description": "Precision of the distance estimates, e.g. 'ZIP-centroid straight-line estimate'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"note": {
"description": "Ready-to-quote sentence explaining the verdict in the borrower's terms.",
"type": [
"string",
"null"
]
},
"percentile": {
"description": "Where the quote sits in the live market distribution, 0-100, lower being cheaper. 100 means every tracked offer is cheaper than this quote.",
"type": [
"number",
"null"
]
},
"product_floor": {
"description": "Lowest rate in percent considered plausible for this product; quotes under it trip below_product_floor.",
"type": [
"number",
"null"
]
},
"product_type": {
"description": "Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.",
"type": [
"string",
"null"
]
},
"quote": {
"additionalProperties": true,
"description": "The rate the borrower was quoted, echoed back as supplied.",
"properties": {
"apr": {
"description": "Quoted APR in percent, including fees; this is the number scored against the market.",
"type": [
"number",
"null"
]
},
"rate": {
"description": "Quoted note rate in percent, excluding fees.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"share_url": {
"description": "Link to this same check on rateapi.dev that the borrower can send to a lender or broker; it re-runs against live rates when opened, so it never goes stale.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Tell a borrower whether refinancing is worth it. Compares their current rate against the best real market offer and returns monthly savings, lifetime savings, and break-even months. Use for 'should I refinance?' questions.",
"inputSchema": {
"properties": {
"balance": {
"description": "Current loan balance in dollars",
"type": "number"
},
"closing_costs": {
"description": "Lender fees / closing costs in dollars (default 0)",
"type": "number"
},
"credit_score": {
"description": "Optional borrower credit score",
"type": "number"
},
"current_rate": {
"description": "Borrower's current interest rate, e.g. 7.25",
"type": "number"
},
"product_type": {
"description": "mortgage | auto | heloc | personal_loan | student_loan",
"type": "string"
},
"state": {
"description": "US state code",
"type": "string"
},
"term_months": {
"description": "Remaining or new term in months",
"type": "number"
}
},
"required": [
"state",
"product_type",
"balance",
"term_months",
"current_rate"
],
"type": "object"
},
"name": "refinance_break_even",
"outputSchema": {
"additionalProperties": true,
"properties": {
"assumed_defaults": {
"additionalProperties": true,
"description": "Inputs filled in because the caller did not supply them; the break-even is only as good as these.",
"properties": {
"closing_costs": {
"description": "Closing costs in dollars assumed because the caller did not supply them.",
"type": [
"number",
"null"
]
},
"term_months": {
"description": "Loan term in months assumed because the caller did not supply one.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"best_lender": {
"description": "Credit union publishing that best market rate.",
"type": [
"string",
"null"
]
},
"best_market_rate": {
"description": "Best live published rate available for this product and state, as a percent string.",
"type": [
"string",
"null"
]
},
"break_even_months": {
"description": "Months of savings needed to repay the closing costs. Refinancing only pays off if the borrower keeps the loan longer than this.",
"type": [
"number",
"null"
]
},
"closing_costs": {
"description": "Assumed cost in dollars to close the refinance, as a formatted string.",
"type": [
"string",
"null"
]
},
"current_monthly_payment": {
"description": "Principal-and-interest payment in dollars on the existing loan, as a formatted string.",
"type": [
"string",
"null"
]
},
"current_rate": {
"description": "The borrower's existing rate as a percent string.",
"type": [
"string",
"null"
]
},
"disclosures": {
"description": "Caveats and assumptions that must accompany any answer built from this result; surface them rather than dropping them.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
},
"lifetime_savings": {
"description": "Total interest saved in dollars over the full term, before subtracting closing costs.",
"type": [
"string",
"null"
]
},
"monthly_savings": {
"description": "Reduction in the monthly payment in dollars; the difference between the two payments above.",
"type": [
"string",
"null"
]
},
"net_lifetime_savings": {
"description": "Lifetime savings after subtracting closing costs — the honest headline number.",
"type": [
"string",
"null"
]
},
"new_monthly_payment": {
"description": "Principal-and-interest payment in dollars after refinancing at the best market rate.",
"type": [
"string",
"null"
]
},
"next_actions": {
"description": "Suggested follow-up tools that would deepen this answer; offer them as next steps, not as results.",
"items": {
"additionalProperties": true,
"properties": {
"tool": {
"description": "Name of the follow-up MCP tool to call next.",
"type": [
"string",
"null"
]
},
"why": {
"description": "One-line reason this follow-up tool would be useful given the current result.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"product_type": {
"description": "Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.",
"type": [
"string",
"null"
]
},
"reason": {
"description": "Why refinancing is not worth it, present only when `refinance_worth_it` is false — e.g. 'No qualifying market offer beats the current rate.' Its absence means a viable refinance was found.",
"type": [
"string",
"null"
]
},
"refinance_worth_it": {
"description": "True when the refinance clears its costs on the assumptions shown; it does not account for how long the borrower actually plans to stay.",
"type": [
"boolean",
"null"
]
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Remove one recipient from a campaign by recipient id.",
"inputSchema": {
"properties": {
"id": {
"description": "Campaign id. Required.",
"type": "string"
},
"recipient_id": {
"description": "Recipient id. Required.",
"type": "string"
}
},
"required": [
"id",
"recipient_id"
],
"type": "object"
},
"name": "remove_campaign_recipient",
"outputSchema": {
"additionalProperties": true,
"description": "Removal acknowledgement. The route replies 204 with no body, which the client renders as a bare success flag. It is idempotent — an unknown recipient id still succeeds.",
"properties": {
"success": {
"description": "True when the request completed.",
"type": "boolean"
}
},
"type": "object"
}
},
{
"description": "Resolve up to 50 typed organization names for canonical eligibility input. Only one exact normalized active-publication match with confidence of at least 0.8 is authoritative (`resolved`); a lower-confidence exact match remains `unresolved`, multiple exact matches are `ambiguous`, and prefix candidates are suggestions only. Never convert an unresolved, ambiguous, or suggested candidate into a person fact. Resolution identifies an organization and never establishes eligibility.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"candidate_limit": {
"default": 5,
"description": "Maximum exact matches or prefix suggestions returned per input.",
"maximum": 10,
"minimum": 1,
"type": "integer"
},
"inputs": {
"description": "Typed values to resolve in stable input order.",
"items": {
"additionalProperties": false,
"properties": {
"entity_type": {
"description": "Asserted exact organization type.",
"enum": [
"employer",
"association",
"school",
"worship"
],
"type": "string"
},
"value": {
"description": "Organization name as supplied by the user.",
"maxLength": 120,
"minLength": 2,
"type": "string"
}
},
"required": [
"value",
"entity_type"
],
"type": "object"
},
"maxItems": 50,
"minItems": 1,
"type": "array"
}
},
"required": [
"inputs"
],
"type": "object"
},
"name": "resolve_eligibility_entities",
"outputSchema": {
"additionalProperties": true,
"description": "Stable-order exact normalized canonical organization resolution.",
"properties": {
"disclosure": {
"description": "Required warning that resolution does not prove eligibility.",
"type": [
"string",
"null"
]
},
"prefix_candidates_are_suggestions": {
"description": "True: prefix results must never be silently promoted to facts.",
"type": [
"boolean",
"null"
]
},
"resolution_method": {
"description": "Authority rule: one normalized-exact match with confidence of at least 0.8.",
"type": [
"string",
"null"
]
},
"results": {
"description": "One resolution result per input in the same order.",
"items": {
"additionalProperties": true,
"properties": {
"candidates": {
"description": "Exact ambiguity choices or non-authoritative prefix suggestions.",
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
"candidates_truncated": {
"description": "Whether more candidates existed for this input.",
"type": [
"boolean",
"null"
]
},
"entity": {
"additionalProperties": true,
"description": "Authoritative entity only when exactly one normalized exact match exists with confidence of at least 0.8.",
"type": "object"
},
"input": {
"additionalProperties": true,
"description": "Original typed value plus its normalized representation.",
"type": "object"
},
"input_index": {
"description": "Zero-based position of the corresponding input.",
"type": [
"number",
"null"
]
},
"status": {
"description": "resolved, ambiguous, or unresolved.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"semantics": {
"description": "Machine-readable organization-resolution-not-eligibility contract.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Revoke a hosted shareable report link by its token. Once revoked, the public URL returns a 404 and no longer exposes the report. This action cannot be undone.",
"inputSchema": {
"properties": {
"token": {
"description": "The share token to revoke. Required.",
"type": "string"
}
},
"required": [
"token"
],
"type": "object"
},
"name": "revoke_share",
"outputSchema": {
"additionalProperties": true,
"description": "Revocation acknowledgement. The route replies 204 with no body, which the client renders as a bare success flag.",
"properties": {
"success": {
"description": "True when the share was revoked.",
"type": "boolean"
}
},
"type": "object"
}
},
{
"description": "Save a named cohort (\"book of business\") — a list of borrower scenarios you want to track and re-scan over time. Each member has a label and a scenario (product_type, state, intent, amount, term_months, optional credit_score and current_offer). Returns the created cohort. Use scan_portfolio later to re-price every member against the live market.",
"inputSchema": {
"properties": {
"members": {
"description": "List of cohort members (max ~50).",
"items": {
"properties": {
"label": {
"description": "Member label, e.g. \"Smith — $400k purchase\".",
"type": "string"
},
"scenario": {
"description": "A financing scenario: { product_type, state, intent, amount, term_months, credit_score?, current_offer?:{rate,apr,amount,term_months} }.",
"type": "object"
}
},
"required": [
"label",
"scenario"
],
"type": "object"
},
"type": "array"
},
"name": {
"description": "Cohort name, e.g. \"Q2 refi prospects\". Required.",
"type": "string"
}
},
"required": [
"name",
"members"
],
"type": "object"
},
"name": "save_cohort",
"outputSchema": {
"additionalProperties": true,
"description": "The saved cohort (book of business), as stored. Capped at 50 members.",
"properties": {
"createdAt": {
"description": "ISO-8601 creation timestamp.",
"type": [
"string",
"null"
]
},
"id": {
"description": "Cohort id — pass to scan_portfolio, get_cohort, schedule_digest.",
"type": "string"
},
"lastScan": {
"additionalProperties": true,
"description": "Previous scan snapshot. Null on a newly created cohort.",
"type": [
"object",
"null"
]
},
"members": {
"description": "The cohort members as supplied.",
"items": {
"additionalProperties": true,
"properties": {
"label": {
"description": "Member label, e.g. the client's name.",
"type": "string"
},
"scenario": {
"additionalProperties": true,
"description": "The decision inputs for this member.",
"type": "object"
}
},
"type": "object"
},
"type": "array"
},
"name": {
"description": "Cohort label.",
"type": "string"
},
"updatedAt": {
"description": "ISO-8601 last-modified timestamp.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Save a rate comparison for a named client so it can be recalled later (a lightweight CRM for loan officers). Pass the client label and the inputs/results you want to keep.",
"inputSchema": {
"properties": {
"client_name": {
"description": "Client/scenario label, e.g. \"Smith — $400k purchase, CA\"",
"type": "string"
},
"input": {
"description": "The scenario inputs (product, amount, state, term, etc.)",
"type": "object"
},
"result_snapshot": {
"description": "The comparison result to store (object from get_financing_decision/compare_products)"
}
},
"required": [
"client_name",
"input",
"result_snapshot"
],
"type": "object"
},
"name": "save_scenario",
"outputSchema": {
"additionalProperties": true,
"description": "The saved client scenario, as stored.",
"properties": {
"clientName": {
"description": "Client label for the scenario.",
"type": "string"
},
"createdAt": {
"description": "ISO-8601 creation timestamp.",
"type": [
"string",
"null"
]
},
"id": {
"description": "Scenario id — pass to get_scenario, generate_share_link, or generate_client_report.",
"type": "string"
},
"input": {
"additionalProperties": true,
"description": "The decision inputs that produced the snapshot (product, amount, state, term).",
"type": [
"object",
"null"
]
},
"resultSnapshot": {
"description": "The decision result captured at save time. Shape mirrors a /v1/decisions response."
}
},
"type": "object"
}
},
{
"description": "Re-scan every member of a saved cohort against the live decision engine to find each member's current best offer. Returns a triage list (label, best lender, best APR, monthly payment, optional savings vs current) and a diff vs the previous scan (who's new, whose best lender changed, APR deltas). Persists the new snapshot. Use this to refresh a book of business and surface what changed.",
"inputSchema": {
"properties": {
"id": {
"description": "Cohort id to scan. Required.",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "scan_portfolio",
"outputSchema": {
"additionalProperties": true,
"description": "Live re-scan of every cohort member against the decision engine, diffed against the previous snapshot. The new snapshot is persisted.",
"properties": {
"changed": {
"description": "Members whose best offer moved since the previous scan.",
"items": {
"additionalProperties": true,
"properties": {
"apr_delta": {
"description": "Change in APR in percentage points.",
"type": [
"number",
"null"
]
},
"change": {
"description": "'new', 'best_lender_changed', or 'apr_changed'.",
"type": "string"
},
"from": {
"additionalProperties": true,
"description": "Prior best_lender and best_apr. Absent for a new member.",
"type": [
"object",
"null"
]
},
"label": {
"description": "Member label.",
"type": "string"
},
"to": {
"additionalProperties": true,
"description": "Current best_lender and best_apr.",
"type": "object"
}
},
"type": "object"
},
"type": "array"
},
"scanned": {
"description": "Members evaluated (capped at 50).",
"type": "number"
},
"triage": {
"description": "Every member's current best offer.",
"items": {
"additionalProperties": true,
"properties": {
"best_apr": {
"description": "Best APR percent.",
"type": [
"number",
"null"
]
},
"best_lender": {
"description": "Institution with the best offer.",
"type": [
"string",
"null"
]
},
"label": {
"description": "Member label.",
"type": "string"
},
"monthly_payment": {
"description": "Monthly payment on the best offer.",
"type": [
"number",
"null"
]
},
"savings_vs_current": {
"description": "Monthly saving against the member's stated current rate, when supplied.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "Scan a list of existing debts and find, for EACH debt, the best qualifying market refinance offer. Returns a ranked \"savings stack\" with monthly and lifetime savings (net of typical closing costs) per debt plus whether refinancing is worth it, and overall totals. Use this to find refinance opportunities across a borrower's whole debt portfolio.",
"inputSchema": {
"properties": {
"credit_score": {
"description": "Borrower's credit score (300-850). Recommended for accurate matching.",
"type": "number"
},
"debts": {
"description": "List of existing debts to evaluate for refinancing.",
"items": {
"properties": {
"balance": {
"description": "Outstanding balance in dollars.",
"type": "number"
},
"current_rate": {
"description": "Current interest rate as a percentage (e.g., 7.9).",
"type": "number"
},
"product_type": {
"description": "Type of the existing debt.",
"enum": [
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"mortgage",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"term_months": {
"description": "Remaining term in months.",
"type": "number"
}
},
"required": [
"product_type",
"balance",
"current_rate",
"term_months"
],
"type": "object"
},
"type": "array"
},
"state": {
"description": "US state code (2-letter, e.g., TX). Required.",
"type": "string"
}
},
"required": [
"state",
"debts"
],
"type": "object"
},
"name": "scan_savings",
"outputSchema": {
"additionalProperties": true,
"properties": {
"stack": {
"description": "The user's debts ordered by refinancing opportunity, biggest saving first.",
"items": {
"additionalProperties": true,
"properties": {
"balance": {
"description": "Outstanding balance in dollars on this debt.",
"type": [
"number",
"null"
]
},
"best_offer": {
"description": "Best live published replacement offer, with lender, APR and rate in percent, points, and monthly payment in dollars.",
"type": "object"
},
"current_monthly_payment": {
"description": "What the user pays each month in dollars on this debt today.",
"type": [
"number",
"null"
]
},
"current_rate": {
"description": "Rate in percent the user currently pays on this debt.",
"type": [
"number",
"null"
]
},
"lifetime_savings": {
"description": "Total dollars saved over the remaining term, before any refinancing or closing costs.",
"type": [
"number",
"null"
]
},
"monthly_savings": {
"description": "Dollars per month saved by moving to the best offer at the same balance and remaining term.",
"type": [
"number",
"null"
]
},
"product_type": {
"description": "Category of the existing debt, e.g. 'mortgage', 'auto_loan'.",
"type": [
"string",
"null"
]
},
"rank": {
"description": "Priority of this debt for refinancing, 1 = largest opportunity.",
"type": [
"number",
"null"
]
},
"worth_it": {
"description": "True when the saving is large enough to be worth acting on; it does not account for closing costs specific to the user.",
"type": [
"boolean",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
},
"totals": {
"additionalProperties": true,
"description": "Combined opportunity across every debt in the stack.",
"properties": {
"debts_worth_refinancing": {
"description": "How many of the submitted debts cleared the worth-it bar.",
"type": [
"number",
"null"
]
},
"total_lifetime_savings": {
"description": "Sum of the lifetime savings in dollars across all debts, dominated by the longest-term debt.",
"type": [
"number",
"null"
]
},
"total_monthly_savings": {
"description": "Sum of the monthly savings in dollars across all debts worth refinancing.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
"type": "object"
}
},
{
"description": "Set up a recurring digest: on a cadence (default weekly), automatically re-scan a saved cohort and EMAIL the loan officer a triage of which clients have a new opportunity (best lender changed, crossed a threshold). Turns a one-time portfolio scan into a standing operation. Requires a cohort_id (from save_cohort/list_cohorts) and a delivery email.",
"inputSchema": {
"properties": {
"cadence": {
"description": "weekly (default) or daily.",
"type": "string"
},
"cohort_id": {
"description": "The cohort to scan on a schedule (from list_cohorts).",
"type": "string"
},
"email": {
"description": "Where to send the digest.",
"type": "string"
}
},
"required": [
"cohort_id",
"email"
],
"type": "object"
},
"name": "schedule_digest",
"outputSchema": {
"additionalProperties": true,
"description": "The scheduled digest that was created — a standing instruction to scan a cohort on a cadence and email the result.",
"properties": {
"cadence": {
"description": "'daily' or 'weekly'. Anything other than 'daily' is stored as 'weekly'.",
"type": "string"
},
"cohort_id": {
"description": "Cohort the digest scans.",
"type": "string"
},
"created_at": {
"description": "ISO-8601 creation timestamp.",
"type": [
"string",
"null"
]
},
"email": {
"description": "Recipient address.",
"type": "string"
},
"enabled": {
"description": "True on creation.",
"type": "boolean"
},
"id": {
"description": "Digest id — pass to delete_digest.",
"type": "string"
}
},
"type": "object"
}
},
{
"description": "DOCS: search the RateAPI documentation (authentication, rate limits and pricing, coverage, freshness, methodology, eligibility, endpoint map, product parameters, errors, the MCP server itself, and the rules for quoting the data). Use this whenever the question is about the API rather than about a rate — \"how do I authenticate?\", \"what does rate_phase mean?\", \"which endpoint gives deposit APYs?\", \"how fresh is this?\", \"what does it cost?\" — instead of guessing at parameters or inventing endpoints. Returns ranked pages with an excerpt; call get_doc for the full text. This tool NEVER returns rates.",
"inputSchema": {
"properties": {
"limit": {
"description": "Maximum pages to return (1-12). Defaults to 5.",
"type": "number"
},
"query": {
"description": "What you want to know about the API, in plain words (e.g. \"oauth\", \"how fresh are rates\", \"429 error\").",
"type": "string"
}
},
"required": [
"query"
],
"type": "object"
},
"name": "search_docs",
"outputSchema": {
"additionalProperties": true,
"properties": {
"count": {
"description": "Number of pages returned.",
"type": [
"number",
"null"
]
},
"note": {
"description": "Guidance on what to do with these results.",
"type": [
"string",
"null"
]
},
"query": {
"description": "The query as received.",
"type": [
"string",
"null"
]
},
"results": {
"description": "Matching documentation pages, best match first.",
"items": {
"additionalProperties": true,
"properties": {
"excerpt": {
"description": "The first matching paragraph of the page.",
"type": [
"string",
"null"
]
},
"score": {
"description": "Relevance score; comparable within one result set only.",
"type": [
"number",
"null"
]
},
"slug": {
"description": "Identifier to pass to get_doc.",
"type": [
"string",
"null"
]
},
"summary": {
"description": "One-line description of the page.",
"type": [
"string",
"null"
]
},
"title": {
"description": "Page title.",
"type": [
"string",
"null"
]
},
"url": {
"description": "Canonical published URL to cite.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": [
"array",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Browse or search canonical employers, associations, schools, or worship organizations that appear in positive conditions in current active eligibility publications. Omit query to browse by active-publication graph connectivity; that order is NOT popularity, quality, or a recommendation. With query, normalized exact matches rank before bounded prefix matches. A returned organization is a selectable fact, NOT proof that this person can join any credit union; use resolve_eligibility_entities for authoritative selection, then pass the returned org_id in the matching *_org_ids field to an eligibility tool. This authenticated discovery never loads a client-side corpus and accepts no personal profile.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"limit": {
"default": 10,
"description": "Maximum results; the response discloses truncation.",
"maximum": 10,
"minimum": 1,
"type": "integer"
},
"query": {
"description": "Optional organization name or prefix, 2-120 characters. Omit to browse by active-publication connectivity.",
"maxLength": 120,
"minLength": 2,
"type": "string"
},
"types": {
"description": "Exact public organization types to search. Omit for all four types.",
"items": {
"enum": [
"employer",
"association",
"school",
"worship"
],
"type": "string"
},
"maxItems": 4,
"minItems": 1,
"type": "array",
"uniqueItems": true
}
},
"required": [],
"type": "object"
},
"name": "search_eligibility_entities",
"outputSchema": {
"additionalProperties": true,
"description": "Bounded canonical organization discovery backed only by positive conditions in active publications.",
"properties": {
"disclosure": {
"description": "Required warning that organization discovery does not prove eligibility.",
"type": [
"string",
"null"
]
},
"normalized_query": {
"description": "Canonical normalized text used for indexed exact and prefix matching.",
"type": [
"string",
"null"
]
},
"query": {
"description": "Trimmed search text supplied by the caller.",
"type": [
"string",
"null"
]
},
"query_truncated": {
"description": "Whether the accepted query text was truncated; currently always false because oversized input is rejected.",
"type": [
"boolean",
"null"
]
},
"result_limit": {
"description": "Requested result cap.",
"type": [
"number",
"null"
]
},
"result_mode": {
"description": "search for text-ranked results or most_connected for query-less graph-connectivity browse; neither is an eligibility verdict.",
"type": [
"string",
"null"
]
},
"results": {
"description": "Deterministically ranked canonical entity matches; these do not imply personal eligibility.",
"items": {
"additionalProperties": true,
"properties": {
"active_institution_count": {
"description": "Active institutions whose publications positively reference this entity.",
"type": [
"number",
"null"
]
},
"active_rule_count": {
"description": "Current active-publication positive rules referencing this entity.",
"type": [
"number",
"null"
]
},
"canonical_name": {
"description": "Canonical public organization name.",
"type": [
"string",
"null"
]
},
"entity_id": {
"description": "Stable canonical entity identifier.",
"type": [
"string",
"null"
]
},
"entity_type": {
"description": "Exact public organization type.",
"type": [
"string",
"null"
]
},
"last_confirmed_at": {
"description": "Latest derivable publication-bound confirmation timestamp, or null.",
"type": [
"string",
"null"
]
},
"match_confidence": {
"description": "Alias and method confidence from 0 to 1; not eligibility confidence.",
"type": [
"number",
"null"
]
},
"match_method": {
"description": "normalized_exact, normalized_prefix, or canonical_id for query-less browse.",
"type": [
"string",
"null"
]
},
"matched_alias": {
"description": "Stored alias that produced this match.",
"type": [
"string",
"null"
]
},
"org_id": {
"description": "Stable canonical organization identifier; identical to entity_id.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"results_truncated": {
"description": "True when more authorized matches existed than were returned.",
"type": [
"boolean",
"null"
]
},
"semantics": {
"description": "Machine-readable organization-discovery-not-eligibility contract.",
"type": [
"string",
"null"
]
},
"types": {
"description": "Exact public entity types included in the search.",
"items": {
"type": [
"string",
"null"
]
},
"type": "array"
}
},
"type": "object"
}
},
{
"description": "Send a campaign to ALL of its recipients immediately (one full send, the same path the daily cron uses). The campaign must be active. Honors suppressions and the per-org daily cap, resets the cadence clock (the next scheduled send counts from now), and is guarded against double-fires. Returns { run_id, sent, suppressed, failed }.",
"inputSchema": {
"properties": {
"id": {
"description": "Campaign id. Required.",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "send_campaign_now",
"outputSchema": {
"additionalProperties": true,
"description": "Result of an immediate full send to the campaign's recipients, using the same path as the scheduled cron. Only an 'active' campaign can be sent.",
"properties": {
"failed": {
"description": "Recipients the provider rejected.",
"type": "number"
},
"run_id": {
"description": "Id of the campaign run, for correlating with send history.",
"type": [
"string",
"number",
"null"
]
},
"sent": {
"description": "Emails handed to the provider.",
"type": "number"
},
"suppressed": {
"description": "Recipients skipped because they had unsubscribed or were otherwise suppressed.",
"type": "number"
}
},
"type": "object"
}
},
{
"description": "Send a one-off test render of a campaign (with live rates and the org's branding) to the organization owner's email. Does not affect the campaign schedule.",
"inputSchema": {
"properties": {
"id": {
"description": "Campaign id. Required.",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "send_test_campaign",
"outputSchema": {
"additionalProperties": true,
"description": "Result of a single test send. The email goes to the organization OWNER's address, not to campaign recipients, and is capped at 3 per day per address.",
"properties": {
"message": {
"description": "Confirmation naming the address the test was sent to.",
"type": "string"
},
"ok": {
"description": "True when the test email was accepted by the email provider.",
"type": "boolean"
}
},
"type": "object"
}
},
{
"description": "Set the organization's white-label email branding: display name (used as the From name and CAN-SPAM advertiser identity), brand color (#hex), default intro text, business_address (CAN-SPAM physical address — required before a campaign can be activated), and reply_to_email. Requires a Pro plan. (Logo upload is app-only — not available over MCP.)",
"inputSchema": {
"properties": {
"brand_color": {
"description": "Accent color as a #hex string (e.g. #00b368).",
"type": "string"
},
"business_address": {
"description": "Physical mailing address of the advertiser (CAN-SPAM).",
"type": "string"
},
"display_name": {
"description": "The lender/brand name shown as the email sender and advertiser.",
"type": "string"
},
"intro_text": {
"description": "Default intro paragraph for campaign emails.",
"type": "string"
},
"logo_background_color": {
"description": "Solid backdrop behind the logo in the email header, as a 6-digit #hex (e.g. #0d1b2a). Useful when the logo is white. Omit or null for the white default.",
"type": "string"
},
"reply_to_email": {
"description": "Optional Reply-To address for campaign emails.",
"type": "string"
}
},
"type": "object"
},
"name": "set_email_branding",
"outputSchema": {
"additionalProperties": true,
"description": "The organization's email branding after the update, wrapped in a `branding` envelope.",
"properties": {
"branding": {
"additionalProperties": true,
"description": "The stored branding row.",
"properties": {
"brand_color": {
"description": "Accent color as a #hex string.",
"type": [
"string",
"null"
]
},
"business_address": {
"description": "CAN-SPAM physical address. Required before a campaign can be activated or sent.",
"type": [
"string",
"null"
]
},
"display_name": {
"description": "From-name and CAN-SPAM advertiser identity. Required before a campaign can be activated.",
"type": [
"string",
"null"
]
},
"intro_text": {
"description": "Default intro paragraph for campaign emails.",
"type": [
"string",
"null"
]
},
"logo_background_color": {
"description": "Logo backdrop as a 6-digit #hex string.",
"type": [
"string",
"null"
]
},
"logo_email_url": {
"description": "Email-optimized logo variant.",
"type": [
"string",
"null"
]
},
"logo_url": {
"description": "Public logo URL.",
"type": [
"string",
"null"
]
},
"organization_id": {
"description": "Owning organization.",
"type": "string"
},
"reply_to_email": {
"description": "Optional Reply-To address.",
"type": [
"string",
"null"
]
}
},
"type": [
"object",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Run a what-if sweep over a financing decision. Holds a scenario fixed while sweeping one input (credit_score, down_payment_percent, or rate_shift_bps) across a from/to/step range, returning a grid of best_lender / best_apr / monthly_payment at each value plus any flip_points where the winning lender changes. Use this to show how rate eligibility or affordability changes with credit score, down payment, or a market rate shift.",
"inputSchema": {
"properties": {
"scenario": {
"description": "The fixed financing scenario.",
"properties": {
"amount": {
"description": "Loan amount in dollars.",
"type": "number"
},
"credit_score": {
"description": "Baseline credit score (used unless swept).",
"type": "number"
},
"down_payment_percent": {
"description": "Baseline down payment percent (used unless swept).",
"type": "number"
},
"intent": {
"description": "The loan intent.",
"enum": [
"purchase",
"refinance",
"cash_out",
"balance_transfer",
"new_credit"
],
"type": "string"
},
"product_type": {
"description": "Type of financing product.",
"enum": [
"mortgage",
"mortgage_arm",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"personal_loan",
"heloc",
"credit_card",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"state": {
"description": "US state code (2-letter).",
"type": "string"
},
"term_months": {
"description": "Loan term in months.",
"type": "number"
}
},
"required": [
"product_type",
"state",
"intent",
"amount"
],
"type": "object"
},
"sweep": {
"description": "The input to sweep and its range.",
"properties": {
"field": {
"description": "Which input to vary across the grid.",
"enum": [
"credit_score",
"down_payment_percent",
"rate_shift_bps"
],
"type": "string"
},
"from": {
"description": "Start value (inclusive).",
"type": "number"
},
"step": {
"description": "Increment between values.",
"type": "number"
},
"to": {
"description": "End value (inclusive).",
"type": "number"
}
},
"required": [
"field",
"from",
"to",
"step"
],
"type": "object"
}
},
"required": [
"scenario",
"sweep"
],
"type": "object"
},
"name": "simulate_decision",
"outputSchema": {
"additionalProperties": true,
"properties": {
"flip_points": {
"description": "Values of the swept input where the winning lender or recommended action changes. Empty means the outcome is stable across the whole sweep.",
"type": "array"
},
"grid": {
"description": "One row per swept value, showing how the outcome changes.",
"items": {
"additionalProperties": true,
"properties": {
"best_apr": {
"description": "Best published APR in percent at this swept value, taken as published without any score adjustment.",
"type": [
"number",
"null"
]
},
"best_lender": {
"description": "Best lender at this swept value. It often does not change, because published credit-union rates are rarely tiered by score.",
"type": [
"string",
"null"
]
},
"estimated_tier_apr": {
"description": "APR in percent after applying a modeled credit-tier adjustment — an estimate of what this borrower would actually be offered, not a published rate.",
"type": [
"number",
"null"
]
},
"estimated_tier_monthly_payment": {
"description": "Monthly payment in dollars at the tier-adjusted APR; this is the realistic figure to quote a borrower at this credit score.",
"type": [
"number",
"null"
]
},
"monthly_payment": {
"description": "Monthly payment in dollars at best_apr.",
"type": [
"number",
"null"
]
},
"value": {
"description": "The swept input's value for this row, e.g. a credit score of 700.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"type": "array"
},
"product_type": {
"description": "Loan or deposit category this result covers, e.g. 'mortgage', 'auto_loan', 'heloc', 'savings'.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter US state code the result is scoped to (e.g. 'CA'). Null means the result was not filtered by state.",
"type": [
"string",
"null"
]
},
"sweep_field": {
"description": "The input that was varied across the grid, e.g. 'credit_score'.",
"type": [
"string",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Test a monitor with a simulated rate change to see if it would trigger. No webhook is sent. It is not a pure dry run: the simulation IS recorded, as a monitor_evaluations row (and a webhook audit row) flagged is_simulation = 1, so it appears in the monitor's history clearly marked as a simulation. It does not touch the monitor's cooldown or last_triggered_at. Use deliver_test_webhook to actually send a test webhook.",
"inputSchema": {
"properties": {
"monitor_id": {
"description": "The unique identifier of the monitor to simulate. Required.",
"type": "string"
},
"rate_change": {
"description": "The simulated rate change event. Required.",
"properties": {
"new_rate": {
"description": "The new rate value. Required.",
"type": "number"
},
"previous_rate": {
"description": "The previous rate value. Required.",
"type": "number"
},
"product_type": {
"description": "The product type that changed (e.g., \"30yr_fixed\"). Required.",
"type": "string"
},
"state": {
"description": "US state code where the rate changed. Required.",
"type": "string"
}
},
"required": [
"state",
"product_type",
"previous_rate",
"new_rate"
],
"type": "object"
}
},
"required": [
"monitor_id",
"rate_change"
],
"type": "object"
},
"name": "simulate_monitor",
"outputSchema": {
"additionalProperties": true,
"description": "Dry-run evaluation of a monitor against a hypothetical rate change. No webhook is sent and the cooldown is ignored. On a missing id the tool returns a not-found shape instead of throwing.",
"properties": {
"error": {
"description": "Present and set to 'not_found' when the monitor id does not exist.",
"type": [
"string",
"null"
]
},
"evaluation": {
"additionalProperties": true,
"description": "Why the monitor did or did not fire.",
"properties": {
"conditions_met": {
"description": "Whether the trigger conditions were satisfied.",
"type": [
"boolean",
"array",
"null"
]
},
"conditions_summary": {
"description": "Per-condition explanation of the evaluation.",
"type": [
"string",
"array",
"null"
]
}
},
"type": "object"
},
"rate_change": {
"additionalProperties": true,
"description": "The simulated change, echoed back with rates pre-formatted as percent strings.",
"properties": {
"change_pct": {
"description": "Signed change, formatted as a percent string such as '+0.25%'.",
"type": [
"string",
"null"
]
},
"new_rate": {
"description": "New rate, formatted as a percent string.",
"type": [
"string",
"null"
]
},
"previous_rate": {
"description": "Prior rate, formatted as a percent string such as '6.5%'.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Product type of the simulated change.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Two-letter state code.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"summary": {
"description": "Plain-language verdict on whether the monitor would fire, or a not-found message.",
"type": "string"
},
"would_trigger": {
"description": "Whether the monitor's conditions are satisfied by the supplied change.",
"type": "boolean"
}
},
"type": "object"
}
},
{
"description": "Subscribe a consumer to an EMAIL rate alert: notify them when the live market meets their target (rate/apr/monthly_payment crossing a threshold). Consent-first — sends a double-opt-in confirmation email; the alert only activates after the recipient confirms. One-click unsubscribe in every email (CAN-SPAM). Stores only email + alert criteria. Provide exactly one of state, states, or region.",
"inputSchema": {
"properties": {
"amount": {
"description": "Loan amount in dollars. Optional.",
"type": "number"
},
"credit_score": {
"description": "Credit score (300-850). Optional.",
"type": "number"
},
"email": {
"description": "Consumer email address to send the alert to. Required.",
"type": "string"
},
"intent": {
"description": "The loan intent. Required.",
"enum": [
"purchase",
"refinance",
"cash_out",
"balance_transfer",
"new_credit"
],
"type": "string"
},
"product_type": {
"description": "Type of loan product. Required.",
"enum": [
"mortgage",
"auto_loan",
"rv",
"boat",
"motorcycle",
"powersports",
"heloc",
"personal_loan",
"student_loan",
"equipment_loan"
],
"type": "string"
},
"region": {
"description": "Named region preset (e.g. east_coast); expands server-side to its member states.",
"enum": [
"east_coast",
"west_coast",
"midwest",
"south",
"northeast",
"southeast",
"southwest",
"mountain_west",
"new_england",
"mid_atlantic",
"pacific_northwest"
],
"type": "string"
},
"state": {
"description": "Legacy single US state code (2-letter, e.g., CA, TX, NY). Prefer states or region for multi-state alerts.",
"type": "string"
},
"states": {
"description": "2-letter US state codes (up to 25) — best rates are ranked ACROSS all of them, not per state.",
"items": {
"type": "string"
},
"maxItems": 25,
"type": "array"
},
"target": {
"description": "The condition that triggers the alert. Required.",
"properties": {
"field": {
"description": "The field to watch.",
"enum": [
"rate",
"apr",
"monthly_payment"
],
"type": "string"
},
"operator": {
"description": "Comparison operator (lte=at or below, gte=at or above).",
"enum": [
"lte",
"gte"
],
"type": "string"
},
"value": {
"description": "The threshold value to compare against.",
"type": "number"
}
},
"required": [
"field",
"operator",
"value"
],
"type": "object"
},
"term_months": {
"description": "Loan term in months (12-480). Optional.",
"type": "number"
}
},
"required": [
"email",
"product_type",
"intent",
"target"
],
"type": "object"
},
"name": "subscribe_rate_alert",
"outputSchema": {
"additionalProperties": true,
"description": "Result of a double-opt-in rate-alert subscription. The alert is created in 'pending' status and only becomes active once the borrower clicks the confirmation email.",
"properties": {
"alert_id": {
"description": "Id of the created alert.",
"type": "string"
},
"assumed_defaults": {
"additionalProperties": true,
"description": "Loan assumptions recorded with the alert; null where the caller supplied none.",
"properties": {
"amount": {
"description": "Loan amount used when evaluating the threshold.",
"type": [
"number",
"null"
]
},
"term_months": {
"description": "Term in months.",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"disclosures": {
"description": "Consent and CAN-SPAM disclosures for the subscription.",
"items": {
"type": "string"
},
"type": "array"
},
"email": {
"description": "Subscriber address.",
"type": "string"
},
"message": {
"description": "Human-readable next step ('Check your inbox to confirm').",
"type": "string"
},
"next_actions": {
"description": "Suggested follow-up tool names.",
"items": {
"type": "string"
},
"type": "array"
},
"region_preset": {
"description": "Region preset key when one was used, else null.",
"type": [
"string",
"null"
]
},
"state": {
"description": "Legacy scalar state — the first entry of `states`.",
"type": [
"string",
"null"
]
},
"states": {
"description": "Full list of watched state codes. Regions are expanded to a fixed snapshot at subscribe time.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"status": {
"description": "Typically 'pending_confirmation'.",
"type": "string"
},
"target": {
"additionalProperties": true,
"description": "The threshold that fires the alert.",
"properties": {
"field": {
"description": "Field watched, e.g. 'rate', 'apr', or 'monthly_payment'.",
"type": [
"string",
"null"
]
},
"operator": {
"description": "Comparison operator, e.g. 'lte' or 'gte'.",
"type": [
"string",
"null"
]
},
"value": {
"description": "Threshold value.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
"type": "object"
}
},
{
"description": "One-click unsubscribe via the per-alert token embedded in every email.",
"inputSchema": {
"properties": {
"token": {
"description": "The unsubscribe token from the email. Required.",
"type": "string"
}
},
"required": [
"token"
],
"type": "object"
},
"name": "unsubscribe_rate_alert",
"outputSchema": {
"additionalProperties": true,
"description": "Result of a one-click unsubscribe. Replaying a token on an already-unsubscribed alert is treated as not-found and surfaces as an error rather than this shape.",
"properties": {
"alert_id": {
"description": "The alert that was unsubscribed.",
"type": "string"
},
"status": {
"description": "'unsubscribed' on success.",
"type": "string"
}
},
"type": "object"
}
},
{
"description": "Update a campaign's name, geography, cadence, intro override, products, or status. products (if given) is the full replacement set (1-5, same union as create_email_campaign). Any geography field replaces the campaign's whole state selection. Set status 'active' to start sending (requires branding display_name + business_address) or 'paused' to stop. Provide exactly one of state_code, state_codes, or region.",
"inputSchema": {
"properties": {
"cadence": {
"enum": [
"daily",
"weekly",
"monthly"
],
"type": "string"
},
"id": {
"description": "Campaign id. Required.",
"type": "string"
},
"intro_text_override": {
"type": "string"
},
"name": {
"type": "string"
},
"products": {
"description": "Full replacement product set (1-5, no duplicates); same shapes as create_email_campaign.",
"items": {
"type": "object"
},
"type": "array"
},
"region": {
"description": "Named region preset (e.g. east_coast); expands server-side to its member states.",
"enum": [
"east_coast",
"west_coast",
"midwest",
"south",
"northeast",
"southeast",
"southwest",
"mountain_west",
"new_england",
"mid_atlantic",
"pacific_northwest"
],
"type": "string"
},
"state_code": {
"description": "Legacy single 2-letter US state code. Prefer state_codes or region.",
"type": "string"
},
"state_codes": {
"description": "2-letter US state codes (up to 25) — best rates are ranked ACROSS all of them, not per state.",
"items": {
"type": "string"
},
"maxItems": 25,
"type": "array"
},
"status": {
"enum": [
"active",
"paused"
],
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "update_email_campaign",
"outputSchema": {
"additionalProperties": true,
"description": "The campaign after the patch. Activating a campaign requires a display name and business address on the org branding.",
"properties": {
"cadence": {
"description": "'daily', 'weekly', or 'monthly'.",
"type": [
"string",
"null"
]
},
"created_at": {
"description": "Epoch-ms creation time.",
"type": [
"number",
"null"
]
},
"id": {
"description": "Campaign id.",
"type": "string"
},
"intro_text_override": {
"description": "Per-campaign intro override.",
"type": [
"string",
"null"
]
},
"last_run_at": {
"description": "Epoch-ms of the last send.",
"type": [
"number",
"null"
]
},
"name": {
"description": "Campaign label.",
"type": "string"
},
"organization_id": {
"description": "Owning organization.",
"type": "string"
},
"product_category": {
"description": "Product family.",
"type": [
"string",
"null"
]
},
"product_type": {
"description": "Primary product type.",
"type": [
"string",
"null"
]
},
"products": {
"description": "Parsed list of products the email covers.",
"type": [
"array",
"null"
]
},
"region_preset": {
"description": "Region preset key, or null.",
"type": [
"string",
"null"
]
},
"state_code": {
"description": "Legacy scalar state — first entry of state_codes.",
"type": [
"string",
"null"
]
},
"state_codes": {
"description": "Full list of covered state codes.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"status": {
"description": "'draft', 'active', or 'paused'.",
"type": [
"string",
"null"
]
},
"updated_at": {
"description": "Epoch-ms last-modified time.",
"type": [
"number",
"null"
]
}
},
"type": "object"
}
},
{
"description": "Update an existing monitor. Only provided fields will be updated.",
"inputSchema": {
"properties": {
"conditions": {
"description": "New array of conditions.",
"items": {
"properties": {
"field": {
"enum": [
"rate",
"apr",
"monthly_payment"
],
"type": "string"
},
"operator": {
"enum": [
"lt",
"lte",
"gt",
"gte",
"eq",
"change_pct"
],
"type": "string"
},
"value": {
"type": "number"
}
},
"required": [
"field",
"operator",
"value"
],
"type": "object"
},
"type": "array"
},
"cooldown_hours": {
"description": "New cooldown period in hours (1-168).",
"type": "number"
},
"monitor_id": {
"description": "The unique identifier of the monitor to update. Required.",
"type": "string"
},
"name": {
"description": "New name for the monitor.",
"type": "string"
},
"status": {
"description": "New status for the monitor.",
"enum": [
"active",
"paused",
"disabled"
],
"type": "string"
},
"webhook_url": {
"description": "New webhook URL.",
"type": "string"
}
},
"required": [
"monitor_id"
],
"type": "object"
},
"name": "update_monitor",
"outputSchema": {
"additionalProperties": true,
"description": "Result of patching a monitor. On a missing id the tool returns a not-found shape instead of throwing.",
"properties": {
"error": {
"description": "Present and set to 'not_found' when the monitor id does not exist.",
"type": [
"string",
"null"
]
},
"monitor": {
"additionalProperties": true,
"description": "The monitor after the update. Absent when not found.",
"properties": {
"conditions": {
"description": "Trigger conditions after the update.",
"type": [
"array",
"null"
]
},
"cooldown_hours": {
"description": "Minimum hours between triggers.",
"type": [
"number",
"null"
]
},
"id": {
"description": "Monitor id.",
"type": "string"
},
"name": {
"description": "Monitor label.",
"type": "string"
},
"status": {
"description": "'active' or 'paused'.",
"type": "string"
},
"updated_at": {
"description": "ISO-8601 last-modified timestamp.",
"type": [
"string",
"null"
]
},
"webhook_url": {
"description": "Delivery URL.",
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"summary": {
"description": "Confirmation naming the monitor and which fields changed, or a not-found message.",
"type": "string"
}
},
"type": "object"
}
}
]
}Verify it yourself
curl -s https://api.teppi.xyz/v1/evidence/sha256:f67055e3e42d2b4ca7ecc9bc20e75c23576da7ecc86f4962135d62c0f9e6fa8e | sha256sum