addedInput schema / properties / cards
Added value: +{
+ "description": "Credit cards to pay off, 1 to 20. Required: omitting the field answers contract_error MISSING_REQUIRED_FIELD, while an explicit JSON null answers parse_error (\"cards is required and must be an array.\"); the two are not the same rejection. Every card may carry segments[]. Max 100 segments total across all cards in the request. Per-card, per-type caps: 1 purchase, 1 cash_advance, 5 balance_transfer, 1 promotional, 10 installment_plan.",
+ "items": {
+ "properties": {
+ "annual_fee": {
+ "description": "Annual fee in dollars, $0 to $1,000,000,000. Optional; defaults to 0. Charged at month 1 and every twelfth month after, while the card carries a balance.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "cash_advance_apr_pct": {
+ "description": "Cash advance APR as a percentage, greater than 0 and up to 100. Required when cash_advance_balance is greater than 0: cash advances have no promotional 0% product, so a 0% rate on a real advance balance is a data-entry error.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "cash_advance_balance": {
+ "description": "Cash advance balance in dollars, $0 to $1,000,000,000. Optional; defaults to 0 when omitted. A POSITIVE value alongside a non-empty segments[] is rejected, the same way purchase_balance is. An explicit 0 is accepted.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "minimum_payment": {
+ "description": "Minimum payment in dollars, $0 to $1,000,000,000 (optional, omit or set 0 to auto-calculate). Where it binds, the card is locked at max(minimum_payment, that card's issuer minimum computed at month 1), and that locked amount is paid every month. On calculate_cc_payoff it binds ONLY when fixed_payments = true; on the DEFAULT path (fixed_payments = false) it is NOT used, because the plan recomputes each card's issuer minimum from its current balance every month, and the response discloses that as MINIMUM_PAYMENT_NOT_BINDING. On compare_strategies there is no fixed_payments parameter and supplying one is rejected: the avalanche and snowball arms ALWAYS run locked, so the value DOES bind and moves both arms, while the minimum-payments-only baseline always recomputes and ignores it, disclosed as MINIMUM_PAYMENT_NOT_BINDING_IN_BASELINE.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "monthly_spend": {
+ "description": "Recurring monthly purchase amount charged to this card's purchase balance before interest accrues, $0 to $50,000 per month. Optional; defaults to 0. Use the segment-level monthly_spend instead when supplying segments[].",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "name": {
+ "description": "Card label, e.g. 'Chase Sapphire', 120 characters or fewer. Optional; a card without a name is auto-numbered ('Card 1', 'Card 2', and so on). Echoed into per-card results and warning text. A name over the cap is replaced in error field paths by a key built from its zero-based card index, written as '#0 (name over cap)', '#1 (name over cap)' and so on.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "plan_fees_monthly": {
+ "description": "Recurring monthly card fee in dollars, $0 to $1,000,000,000, e.g. a pay-over-time plan fee. Optional; defaults to 0. Charged every month while the card carries a balance.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "purchase_apr_pct": {
+ "description": "Purchase APR as a percentage, 0 to 100, e.g. 24.99 not 0.2499. Required when purchase_balance is greater than 0: an omitted APR would silently compute $0 interest.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "purchase_balance": {
+ "description": "Purchase balance in dollars, $0 to $1,000,000,000. Required unless segments[] carries at least one segment: an omitted purchase_balance would silently report a $0, 0-month payoff. Supplying a POSITIVE value alongside a non-empty segments[] is rejected, since the two would be competing sources for the same balance. An explicit 0 is accepted.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "segments": {
+ "description": "Per-segment breakdown of this card's balances. Optional; when it carries at least one segment it SUPERSEDES purchase_balance and cash_advance_balance, and a POSITIVE value in either of those is rejected. An empty segments[] is treated as absent, so purchase_balance is then required. At most 100 segments across the whole request. Per card, per type: 1 purchase, 1 cash_advance, 5 balance_transfer, 1 promotional, 10 installment_plan. Each item carries its own type, balance, rate and payment priority; see the type field on the item for the per-type field matrix.",
+ "items": {
+ "properties": {
+ "apr_pct": {
+ "default": null,
+ "description": "Annual percentage rate for this segment, 0 to 100, e.g. 24.99 not 0.2499. Required when balance is greater than 0 on purchase, cash_advance, balance_transfer and promotional. On cash_advance it must be greater than 0 whenever a balance is carried. Must be 0 on installment_plan, which uses monthly_fee instead, so omitting it there is the correct shape.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "balance": {
+ "description": "Segment balance in dollars, $0 to $1,000,000,000. REQUIRED on every segment type: an omitted balance would silently report a $0, 0-month payoff, so it is rejected instead. An explicit 0 is valid, for example a paid-off balance_transfer segment kept for schedule continuity.",
+ "type": "number"
+ },
+ "extra_payment_order": {
+ "default": null,
+ "description": "Extra-payment tie-break priority, 0 or more, where 0 means this segment never receives extra payment. Optional on every type, and the default for installment_plan. Only breaks a tie between segments sharing the exact same current APR, since the Credit CARD Act (TILA §164(b), 15 U.S.C. §1666c(b)) / 12 CFR 1026.53(a) always pays the highest-current-APR segment first regardless of this value.",
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "merchant_name": {
+ "default": null,
+ "description": "Label for an installment plan's merchant, 120 characters or fewer. Optional on installment_plan, ignored on every other type.",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "min_payment_order": {
+ "default": null,
+ "description": "Minimum-payment tie-break priority, 1 or more. Optional on every type. The minimum first pays any installment_plan's locked plan_payment_due in full, then the lowest-current-APR segment; this value only breaks a tie between segments sharing both the same current APR and the same installment-plan status.",
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "monthly_fee": {
+ "default": null,
+ "description": "Fixed fee charged each month while an installment plan's term is active, $0 or more and no greater than plan_payment_due. Optional on installment_plan. On every other type a positive value is rejected with FIELD_NOT_ALLOWED_HERE, while 0 and a negative value are accepted and dropped.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "monthly_spend": {
+ "default": null,
+ "description": "Recurring monthly purchase amount posted to this segment before interest accrues, $0 to $50,000 per month. Optional on purchase. A negative value is rejected as NEGATIVE_BALANCE on every type. On every type other than purchase a positive value is rejected with FIELD_NOT_ALLOWED_HERE, since those balances do not accept new purchases; an explicit 0 is accepted.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "plan_payment_due": {
+ "default": null,
+ "description": "Locked monthly payment for an installment plan, principal plus monthly_fee. Required on installment_plan, greater than $0, at least monthly_fee, and no more than $1,000,000,000. On every other type a positive value is rejected with FIELD_NOT_ALLOWED_HERE, while 0 and a negative value are accepted and dropped.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "promo_expires_month": {
+ "default": null,
+ "description": "Month at which apr_pct flips to revert_apr_pct, 1 to 480. Required on balance_transfer and promotional. Ignored on purchase, cash_advance and installment_plan.",
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "remaining_payments": {
+ "default": null,
+ "description": "Payments left in an installment plan's stated term, 0 or more. Optional on installment_plan, ignored on every other type. 0 means the term has ALREADY ended and is valid with any balance, including a positive residual. From 1 up, the balance must be clearable within the stated term and must not be clearable a month early.",
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "revert_apr_pct": {
+ "default": null,
+ "description": "Rate this segment reverts to once its promo expires, 0 to 100, and at least apr_pct. Required on balance_transfer and promotional. Ignored on purchase and cash_advance. Rejected on installment_plan with FIELD_NOT_ALLOWED_HERE: an expired plan's residual keeps its existing rate rather than repricing.",
+ "type": [
+ "number",
+ "null"
+ ]
+ },
+ "stop_spend_month": {
+ "default": null,
+ "description": "Month index at which recurring spend stops, 0 or more. Read on purchase only, and range checked on every type. Omit to spend for the whole projection.",
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "type": {
+ "description": "Segment type. REQUIRED on every segment: omitting it is rejected. Per-type field matrix. Every field below is classified for every segment type: REQUIRED (omitting it is rejected), OPTIONAL (accepted either way and read), IGNORED (accepted and never read for this type, though a value can still fail the field's own range check), or REJECTED (supplying a disallowed value is an error; the field's own rule below says exactly which values are disallowed). Value rules are stated separately from applicability, because a field can be accepted on a type and still be restricted there. The validators are the authority; this matrix describes them.\n- type: REQUIRED on every type. Values: one of purchase, cash_advance, balance_transfer, promotional, installment_plan.\n- balance: REQUIRED on every type. Values: $0 to $1,000,000,000; above $50,000 returns a HIGH_CARD_BALANCE warning, not an error.\n- apr_pct: REQUIRED on purchase, cash_advance, balance_transfer, promotional; OPTIONAL on installment_plan. Values: 0 to 100 as a percentage, e.g. 24.99 not 0.2499. The REQUIRED classification above applies when balance is greater than 0; a zero-balance segment may omit it. Must be greater than 0 on cash_advance carrying a balance. Must equal 0 on installment_plan, where omitting it is the correct shape.\n- revert_apr_pct: REQUIRED on balance_transfer, promotional; IGNORED on purchase, cash_advance; REJECTED on installment_plan. Values: 0 to 100, and at least apr_pct. Rejected on installment_plan with FIELD_NOT_ALLOWED_HERE: an expired plan's residual keeps its existing rate.\n- promo_expires_month: REQUIRED on balance_transfer, promotional; IGNORED on purchase, cash_advance, installment_plan. Values: 1 to 480.\n- monthly_fee: OPTIONAL on installment_plan; REJECTED on purchase, cash_advance, balance_transfer, promotional. Values: $0 or more, and no greater than plan_payment_due, on installment_plan. On every other type a POSITIVE value is rejected with FIELD_NOT_ALLOWED_HERE; 0 and a negative value are accepted and dropped there.\n- plan_payment_due: REQUIRED on installment_plan; REJECTED on purchase, cash_advance, balance_transfer, promotional. Values: greater than $0, at least monthly_fee, and no more than $1,000,000,000, on installment_plan. On every other type a POSITIVE value is rejected with FIELD_NOT_ALLOWED_HERE; 0 and a negative value are accepted and dropped there.\n- remaining_payments: OPTIONAL on installment_plan; IGNORED on purchase, cash_advance, balance_transfer, promotional. Values: 0 or more. 0 means the stated term has ALREADY ended and is valid with any balance. From 1 up, balance must be clearable within the stated term.\n- min_payment_order: OPTIONAL on every type. Values: 1 or more; breaks a tie only between segments sharing both the same current APR and the same installment-plan status.\n- extra_payment_order: OPTIONAL on every type. Values: 0 or more; 0 means skip. Breaks a tie only between segments sharing the exact same current APR.\n- merchant_name: OPTIONAL on installment_plan; IGNORED on purchase, cash_advance, balance_transfer, promotional. Values: 120 characters or fewer.\n- monthly_spend: OPTIONAL on purchase; REJECTED on cash_advance, balance_transfer, promotional, installment_plan. Values: $0 to $50,000 per month. A negative value is rejected as NEGATIVE_BALANCE on every type, purchase included. On every type other than purchase a POSITIVE value is rejected with FIELD_NOT_ALLOWED_HERE; an explicit 0 is accepted.\n- stop_spend_month: OPTIONAL on purchase; IGNORED on cash_advance, balance_transfer, promotional, installment_plan. Values: 0 or more; range checked on every type, read only on purchase.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "type",
+ "balance"
+ ],
+ "type": "object"
+ },
+ "type": [
+ "array",
+ "null"
+ ]
+ },
+ "stop_spend_month": {
+ "description": "Month index at which this card's recurring spend stops, 0 or more. Optional; omit to spend for the whole projection.",
+ "type": [
+ "integer",
+ "null"
+ ]
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+}
removedInput schema / properties / toolArguments
Removed value: -{
- "description": "JSON object with these parameters:\n\ncards (REQUIRED array, max 20):\n - name: string (optional, auto-generated if omitted)\n - purchase_balance: decimal >= 0 (REQUIRED unless segments[] is supplied)\n - purchase_apr_pct: decimal 0-100 as percentage, e.g. 24.99 not 0.2499 (REQUIRED unless segments[] is supplied)\n - cash_advance_balance: decimal >= 0 (optional, default 0)\n - cash_advance_apr_pct: decimal > 0, <= 100 (required only if cash_advance_balance > 0)\n - minimum_payment: decimal >= 0 (optional, omit or set 0 to auto-calculate). Binds ONLY when fixed_payments = true: the card is then locked at max(minimum_payment, that card's issuer minimum computed at month 1), and that locked amount is paid every month. On the DEFAULT path (fixed_payments = false), this value is NOT used: the plan recomputes each card's issuer minimum from its current balance every month, so the monthly budget is the sum of those recomputed minimums plus extra_monthly_payment. To hold a stated payment instead, set fixed_payments = true.\n - annual_fee: decimal >= 0 (optional, default 0). Charged at month 1 and every 12th month thereafter while the card has a balance.\n - plan_fees_monthly: decimal >= 0 (optional, default 0). Charged every month while the card has a balance (e.g. pay-over-time plan fee).\n - segments: array (OPTIONAL; when present, supersedes purchase_balance / cash_advance_balance). Max 100 segments total across all cards in the request. Per-card, per-type caps: 1 purchase, 1 cash_advance, 5 balance_transfer, 1 promotional, 10 installment_plan. Each item:\n - type: 'purchase' | 'cash_advance' | 'balance_transfer' | 'promotional' | 'installment_plan' (REQUIRED). Use 'promotional' for a balance whose 0% (or below-market) intro APR reverts to a standard rate later and is NOT a balance transfer, e.g. a 0% intro purchase APR; it validates and reverts identically to balance_transfer.\n - balance: decimal >= 0 (REQUIRED)\n - apr_pct: decimal 0-100 (REQUIRED for purchase / cash_advance / balance_transfer / promotional; must be 0 for installment_plan; for cash_advance, must be > 0 when balance > 0, since cash advances have no promotional 0% product)\n - revert_apr_pct: decimal 0-100 (REQUIRED for balance_transfer / promotional; APR after promo expires; not applicable to purchase / cash_advance (silently ignored); REJECTED on installment_plan (FIELD_NOT_ALLOWED_HERE) since installment_plan has no post-term-rate concept: an expired plan's residual keeps its existing rate)\n - promo_expires_month: int >= 1 (REQUIRED for balance_transfer / promotional; month at which apr_pct flips to revert_apr_pct)\n - monthly_fee: decimal >= 0 (REQUIRED for installment_plan; fixed fee charged each month while the plan's term is active; stops accruing once the term elapses)\n - plan_payment_due: decimal > 0 (REQUIRED for installment_plan; locked monthly payment, principal + monthly_fee; keeps being charged every month even after the term elapses, until the balance clears)\n - remaining_payments: int >= 0 (optional, installment_plan only). 0 means the plan's stated term has ALREADY ended: this is the correct, valid way to model an already-expired plan carrying a residual balance, and it is accepted regardless of balance (an expired plan's residual is a real state, not a data-entry error). When remaining_payments >= 1, it must be consistent with balance / plan_payment_due / monthly_fee: net = plan_payment_due - monthly_fee must be positive, or the plan could never amortize (rejected as INSTALLMENT_PLAN_NET_NOT_POSITIVE); balance must be <= remaining_payments * net (the plan must be able to clear within its stated term) and balance must be > (remaining_payments - 1) * net (the term must not be overstated), either violation rejected as INSTALLMENT_PLAN_TERM_MISMATCH. If a plan has already ended, enter remaining_payments as 0 rather than a positive count that cannot clear the balance. An expired plan (remaining_payments reaches 0 with a positive balance still owed, whether supplied that way or reached by simulation) does not freeze and is never repriced: it keeps receiving its locked plan_payment_due every month at its existing rate until the balance clears. One aggregated PLAN_TERM_ELAPSED_WITH_BALANCE warning fires per card (never one per segment), naming every affected plan on that card and its residual, plus the card total.\n - merchant_name: string (optional, installment_plan only)\n - min_payment_order: int >= 1 (optional; the minimum first pays any installment_plan segment's locked plan_payment_due in full, structurally, regardless of APR or this value; among the remaining (revolving) segments it then pays down the lowest-current-APR segment first, issuer practice, not statutorily regulated; this value only breaks a tie between segments that share both the exact same current APR AND the same installment-plan status, in which case the higher-balance segment wins; two segments on the same card sharing a value emit a DUPLICATE_PAYMENT_ORDER warning; a supplied value with no APR-tie partner to ever decide emits PAYMENT_ORDER_NOT_DECISIVE)\n - extra_payment_order: int >= 0 (optional; 0 = SKIP -- this segment never receives extra payment, the default for installment_plan; a positive value only breaks a tie between segments that share the exact same current APR, since the Credit CARD Act (TILA §164(b), 15 U.S.C. §1666c(b)) / 12 CFR §1026.53(a) always pays the highest-current-APR segment first regardless of this value; two segments on the same card sharing a positive value emit a DUPLICATE_PAYMENT_ORDER warning, duplicate 0s never warn; a supplied value with no APR-tie partner to ever decide emits PAYMENT_ORDER_NOT_DECISIVE -- this hits installment_plan hardest, since it is pinned at 0% APR (apr_pct is not read for this segment type), so a positive override on it can win the tie-break only against another segment also at exactly 0%; whenever any positive-APR segment shares the card, the plan stays ELIGIBLE and sorts LAST behind every positive-APR segment, receiving extra only once those higher-APR balances clear)\n Response gains per-card interest_saving_balance (sum of APR-bearing segments) and installment_balance_locked (sum of installment_plan segments) when segments[] is supplied.\n\nextra_monthly_payment: decimal >= 0 (optional, default 0)\nstrategy: 'avalanche' | 'snowball' (optional, default 'avalanche')\nfixed_payments: bool (optional, default false). When true, each card's payment is locked at max(cards[].minimum_payment, that card's issuer minimum computed at month 1), and the total monthly budget (sum of those locked amounts plus extra_monthly_payment) is held constant for the whole payoff, so once a card is paid off its freed-up payment rolls forward onto the remaining cards. This is the ONLY mode in which cards[].minimum_payment affects the result; see the minimum_payment field above for what happens on the default path.\napply_rate_cap: bool (optional, default false)\nfull_schedule: bool (optional, default false). The per-card monthly_schedule is capped at 1000 rows total (cards x months); on a long multi-card payoff later months are omitted from monthly_schedule. The portfolio-level monthly_totals series is always complete, so read monthly_totals for the full timeline.\nper_segment: bool (optional, default true)\ninclude_card_timeline: bool (optional, default false)\n\nwindfalls: array of one-time principal payments (optional, default empty, max 12 items). Each item:\n - month: int >= 0 (REQUIRED). 0 means applied before month 1's interest (same as reducing starting principal). N >= 1 applies at the END of calendar month N, so month N+1's interest is calculated on the post-windfall balance.\n - amount: decimal > 0 (REQUIRED).\n - label: string (optional). e.g. 'Tax refund', 'Year-end bonus'.\nWhen any windfalls are present the response gains: baseline, with_windfalls, months_saved_vs_baseline, interest_saved_vs_baseline, windfalls_applied[], windfalls_unused[]. Empty windfalls yields the same response shape as before.\n\nMin-payments-only baseline (v1.7, gap #593): when extra_monthly_payment > 0, windfalls are present, or fixed_payments = true, the response also gains:\n - min_payments_only: { months, interest_cost, amount_paid, payoff_date } - what happens paying minimums only\n - interest_saved_vs_min_payments: decimal - total interest saved vs paying minimums only (always >= 0)\n - months_saved_vs_min_payments: int - months saved vs paying minimums only (when minimums never pay off, capped at MaxMonths minus with-plan months)\nTrivial minimums-only calls (no extra, no windfalls, not fixed) keep their current response shape unchanged.\n\nMinimums-only baseline series (v1.9, B2; bucketed v2.5, #1108): under the same plan-exists condition as min_payments_only above, the response also gains minimums_only_baseline: { months, granularity, buckets[], payoff_date } - the minimums-only balance trajectory bucketed through the same shared aggregator as analysis.buckets[] (same bucket row shape: bucket_index, label, plus the 17 money fields), with granularity auto-selected from THIS series' own term, the same standard rule analysis.granularity itself uses. minimums_only_baseline.granularity is NOT guaranteed to equal analysis.granularity: each series auto-selects independently from its own term, so read each series' own granularity rather than assuming they match. Equal bucket-array length is NOT a valid signal that the two granularities match either: a 24-month primary run (monthly, 24 buckets) and a 24-year minimums-only baseline (yearly, 24 buckets) land on the SAME buckets[].length with DIFFERENT granularities. granularity is the only valid mismatch signal; length is not. Computed from the SAME gated simulation as min_payments_only, so months/payoff_date agree between the two blocks. Absent under the identical trivial-call condition as min_payments_only.\n\nchart_title: string (optional) override for the chart title. Must not contain em-dashes or en-dashes. Max 120 characters.\noutput: 'summary' | 'inline' | 'capture' (optional, default 'summary')\n 'capture' is available on the local stdio transport only; the hosted HTTP transport rejects it with a structured error naming 'summary' and 'inline' as the valid alternatives."
-}