openapi: 3.0.3
info:
  title: MavenFin / Fincalc REST API
  description: |
    **One request. Full plan.**

    Deterministic, API-first financial planning. Backed by the production
    fincalc/AT3 retirement-planning engine at `app.techmaven.us` (proxied via Caddy).

    ## Authentication
    OAuth2 **password grant**. Click `Authorize` → enter
    `username=marbach` / `password=r3t1r3` (demo credentials),
    `client_id=app1`, `client_secret=4d1b3c8e-07a0-457d-8f70-09b354e8e5a9`.
    A Bearer token will be auto-injected on every Try-It call.

    ## Sandbox
    Data is **dummy** — feel free to test write operations. Resets nightly.

    ## Versioning
    Current major: **v4.19**. Endpoints are versioned via path (`/api/v1/...`)
    and the integration namespace (`isrestapi19`). Breaking changes ship under
    a new namespace; non-breaking additions are documented in the changelog.
  version: "4.19"
  contact:
    name: MavenFin Engineering
    email: info@mavenfin.tech
    url: https://docs.techmaven.us/
  license:
    name: Commercial — contact for terms
servers:
  - url: https://app.techmaven.us
    description: Production legacy backend (via Caddy reverse-proxy)
  - url: http://localhost:8080
    description: Direct Tomcat (same-host only)
security:
  - oauth2_password: []

tags:
  - name: Auth
    description: OAuth2 token issue & refresh
  - name: Households
    description: Top-level client record (client, spouse, children, contact, inputs)
  - name: Plans
    description: Plans / scenarios within a household (what-if analysis)
  - name: Projections
    description: Deterministic month-by-month forward simulation
  - name: Monte Carlo
    description: Stochastic projections with percentile fan
  - name: Roth
    description: Roth conversion optimization
  - name: Social Security
    description: PIA, FRA, claim-strategy analysis
  - name: Tax
    description: Federal + state + FICA + IRMAA tax engine

paths:
  /isauthorize19/oauth/token:
    post:
      tags: [Auth]
      summary: Issue OAuth2 token (password grant)
      description: |
        Returns an access token and refresh token. The access token expires in
        ~12 hours (`expires_in: 43199`). Use the refresh token with
        `grant_type=refresh_token` to mint a new access token without re-auth.
      security: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [grant_type, username, password, client_id, client_secret]
              properties:
                grant_type:    { type: string, example: password }
                username:      { type: string, example: marbach }
                password:      { type: string, example: r3t1r3 }
                client_id:     { type: string, example: app1 }
                client_secret: { type: string, example: 4d1b3c8e-07a0-457d-8f70-09b354e8e5a9 }
      responses:
        '200':
          description: Token issued
          content:
            application/json:
              schema:
                type: object
                properties:
                  access_token:  { type: string }
                  refresh_token: { type: string }
                  token_type:    { type: string, example: bearer }
                  expires_in:    { type: integer, example: 43199 }
                  scope:         { type: string, example: read write }
        '400': { description: Invalid grant }

  /isrestapi19/api/v1/households:
    get:
      tags: [Households]
      summary: List all households (paginated)
      parameters:
        - in: query
          name: page
          schema: { type: integer, default: 0 }
        - in: query
          name: size
          schema: { type: integer, default: 25 }
      responses:
        '200': { description: Households array }
        '401': { description: Missing or invalid Bearer token }
    post:
      tags: [Households]
      summary: Create a new household
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                clientFirstName: { type: string }
                clientLastName:  { type: string }
                spouseFirstName: { type: string }
                spouseLastName:  { type: string }
                state:           { type: string, example: IL }
      responses:
        '201': { description: Created }

  /isrestapi19/api/v1/households/{id}:
    get:
      tags: [Households]
      summary: Get household by id
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
      responses:
        '200': { description: Household detail }
        '404': { description: Not found }

  /isrestapi19/api/v1/households/{id}/contact:
    get:
      tags: [Households]
      summary: Get household contact info
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
      responses:
        '200': { description: Contact info }
    put:
      tags: [Households]
      summary: Update household contact info
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email: { type: string }
                phone: { type: string }
                addressLine1: { type: string }
                city: { type: string }
                state: { type: string }
                zip: { type: string }
      responses:
        '200': { description: Updated contact }

  /isrestapi19/api/v1/households/{id}/inputs:
    get:
      tags: [Households]
      summary: Full Inputs object (accounts, persons, scenarios, AAS, etc.)
      description: |
        The complete inputs payload — persons, accounts, asset-allocation strategies,
        spending goals, income streams, tax assumptions. Mutating any field here
        deterministically changes downstream projection results.
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
      responses:
        '200': { description: Full inputs }

  /isrestapi19/api/v1/households/{id}/plans:
    get:
      tags: [Plans]
      summary: List all plans (scenarios) for a household
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
      responses:
        '200': { description: Array of plan summaries }
    post:
      tags: [Plans]
      summary: Create a new plan (clone of base inputs)
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:         { type: string, example: "Retire @ 65" }
                description:  { type: string }
      responses:
        '201': { description: Plan created }

  /isrestapi19/api/v1/households/{id}/plans/{planId}/projection:
    get:
      tags: [Projections]
      summary: Run deterministic month-by-month projection for a plan
      description: |
        Returns a complete forward simulation: monthly cash-flow, account
        balances, tax events, withdrawals, RMDs, Social Security and pension
        cash, capital gains realization, and net portfolio value through
        end of plan (typically age 95).
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
        - in: path
          name: planId
          required: true
          schema: { type: integer }
        - in: query
          name: granularity
          schema:
            type: string
            enum: [monthly, yearly]
            default: yearly
      responses:
        '200':
          description: Projection rows
          content:
            application/json:
              schema:
                type: object
                properties:
                  rows:
                    type: array
                    items:
                      type: object
                      properties:
                        year:          { type: integer }
                        month:         { type: integer }
                        age:           { type: integer }
                        wages:         { type: number }
                        socialSecurity:{ type: number }
                        taxableBalance:{ type: number }
                        traditionalBalance: { type: number }
                        rothBalance:   { type: number }
                        federalTax:    { type: number }
                        stateTax:      { type: number }
                        netPortfolio:  { type: number }

  /isrestapi19/api/v1/households/{id}/plans/{planId}/montecarlo:
    post:
      tags: [Monte Carlo]
      summary: Run Monte Carlo simulation
      description: |
        Deterministic-seed stochastic projection. Returns percentile fan
        (P10 / P25 / P50 / P75 / P90) of terminal portfolio value, plus the
        success-rate (% of paths where portfolio sustains spending to plan end).
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
        - in: path
          name: planId
          required: true
          schema: { type: integer }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                runs:        { type: integer, example: 1000 }
                seed:        { type: integer, example: 42 }
                equityReturn: { type: number, example: 0.07 }
                equityVol:   { type: number, example: 0.18 }
                bondReturn:  { type: number, example: 0.03 }
                bondVol:     { type: number, example: 0.05 }
      responses:
        '200':
          description: Monte Carlo summary
          content:
            application/json:
              schema:
                type: object
                properties:
                  successRate: { type: number, example: 0.87 }
                  p10:         { type: number }
                  p25:         { type: number }
                  p50:         { type: number }
                  p75:         { type: number }
                  p90:         { type: number }

  /isrestapi19/api/v1/households/{id}/plans/{planId}/roth-optimize:
    post:
      tags: [Roth]
      summary: Optimize Roth conversion schedule
      description: |
        Computes a year-by-year Roth conversion schedule under one of three
        strategies. Returns recommended conversion amounts, projected lifetime
        tax savings, and the comparison curve vs. no-conversion baseline.
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
        - in: path
          name: planId
          required: true
          schema: { type: integer }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                strategy:
                  type: string
                  enum: [thresholdRoth, bracketFill, dynamic]
                  example: bracketFill
                targetBracket:
                  type: integer
                  description: "Marginal bracket to fill (e.g. 22 = fill to top of 22% bracket)"
                  example: 22
                startYear: { type: integer, example: 2026 }
                endYear:   { type: integer, example: 2034 }
      responses:
        '200':
          description: Conversion schedule + savings
          content:
            application/json:
              schema:
                type: object
                properties:
                  totalLifetimeTaxSavings: { type: number }
                  schedule:
                    type: array
                    items:
                      type: object
                      properties:
                        year:             { type: integer }
                        conversionAmount: { type: number }
                        marginalBracket:  { type: integer }

  /isrestapi19/api/v1/households/{id}/plans/{planId}/social-security:
    get:
      tags: [Social Security]
      summary: Social Security claim-strategy analysis
      description: |
        Returns PIA, FRA, and lifetime-benefit curves across claim ages
        62 through 70 for client and spouse. Applies WEP/GPO reductions and
        family-maximum cap where applicable.
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
        - in: path
          name: planId
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: SS analysis
          content:
            application/json:
              schema:
                type: object
                properties:
                  clientPIA:     { type: number }
                  clientFRA:     { type: string, example: "67y 0m" }
                  spousePIA:     { type: number }
                  optimalStrategy:
                    type: object
                    properties:
                      clientClaimAge: { type: integer, example: 70 }
                      spouseClaimAge: { type: integer, example: 66 }
                      lifetimeBenefit:{ type: number }

  /isrestapi19/api/v1/households/{id}/plans/{planId}/tax:
    get:
      tags: [Tax]
      summary: Full tax computation for a given year
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
        - in: path
          name: planId
          required: true
          schema: { type: integer }
        - in: query
          name: year
          required: true
          schema: { type: integer, example: 2026 }
      responses:
        '200':
          description: Tax breakdown
          content:
            application/json:
              schema:
                type: object
                properties:
                  agi:               { type: number }
                  taxableIncome:     { type: number }
                  federalTax:        { type: number }
                  stateTax:          { type: number }
                  fica:              { type: number }
                  medicarePremium:   { type: number }
                  irmaaTier:         { type: integer }
                  capitalGainsTax:   { type: number }
                  qbiDeduction:      { type: number }
                  amt:               { type: number }
                  effectiveRate:     { type: number }
                  marginalBracket:   { type: integer }

components:
  securitySchemes:
    oauth2_password:
      type: oauth2
      flows:
        password:
          tokenUrl: https://app.techmaven.us/isauthorize19/oauth/token
          scopes: {}
