# STATUS: PLANNED, NOT LIVE.
# This is a draft specification for a future API. No server implements it yet,
# and requests to the URL below will fail. Fields may change before launch.
openapi: 3.1.0
info:
  title: Marian Proof Engine API (planned, not live)
  version: 0.1.0-draft
  x-status: planned
  x-live: false
  summary: Draft spec for a public API that compares Marian with other mortgage options over simulated rate paths.
  description: |
    PLANNED, NOT LIVE. This endpoint does not exist yet.

    The Marian Proof Engine will let anyone, including AI assistants acting for a borrower,
    compare Marian's down-only mortgage with a standard mortgage, a standard mortgage plus
    refinancing, and competing offers. It runs a Monte Carlo interest-rate simulation and returns
    the distribution of lifetime savings, not just an average.

    Marian is not currently a lender or mortgage broker and is not offering credit. Outputs will
    be model estimates for informational purposes, not offers to lend.

    Methodology: https://marianmortgage.com/math
    Agent information: https://marianmortgage.com/agents
  contact:
    name: Marian
    email: hello@marianmortgage.com
    url: https://marianmortgage.com/agents
servers:
  - url: https://api.marianmortgage.com
    description: Planned. Not deployed.
paths:
  /v1/compare:
    post:
      operationId: compareMortgage
      summary: Compare Marian with an alternative mortgage over simulated rate paths (planned, not live)
      description: |
        PLANNED, NOT LIVE. Simulates interest-rate paths, applies Marian's reset rules and the
        chosen alternative's rules to each path, and returns the distribution of lifetime savings
        of Marian versus the alternative.
      x-status: planned
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CompareRequest'
      responses:
        '200':
          description: Savings distribution across simulated rate paths.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompareResponse'
        '400':
          description: Invalid input.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: Not live. Returned by any placeholder deployment before launch.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    CompareRequest:
      type: object
      required: [loan_balance, rate]
      properties:
        loan_balance:
          type: number
          minimum: 0
          description: Outstanding or requested loan balance, in US dollars.
        rate:
          type: number
          minimum: 0
          description: Annual interest rate of the alternative mortgage being compared, in percent.
        remaining_term_months:
          type: integer
          minimum: 1
          description: Remaining term of the alternative mortgage. Defaults to its full term.
        alternative:
          type: string
          enum: [standard_fixed, standard_fixed_with_refinancing, competing_offer]
          default: standard_fixed_with_refinancing
        refinancing_behavior:
          type: string
          enum: [never, typical, optimal]
          default: typical
          description: How the borrower of the alternative mortgage refinances when rates fall.
        refinance_closing_costs:
          type: number
          minimum: 0
          description: Closing costs per refinance, in US dollars. Defaults to a modeled estimate.
        expected_years_in_loan:
          type: number
          minimum: 0
          description: How long the borrower expects to keep the loan before selling or paying off.
        rate_path_assumptions:
          $ref: '#/components/schemas/RatePathAssumptions'
    RatePathAssumptions:
      type: object
      description: Assumptions for the Monte Carlo simulation. Omitted fields use Marian's published base case.
      properties:
        model:
          type: string
          enum: [base_case, custom]
          default: base_case
        annual_volatility_bp:
          type: number
          minimum: 0
          description: Annualized volatility of mortgage rates, in basis points.
        drift_bp_per_year:
          type: number
          description: Expected annual change in mortgage rates, in basis points.
        mean_reversion:
          type: number
          minimum: 0
          description: Speed at which rates revert toward their long-run level.
        paths:
          type: integer
          minimum: 100
          maximum: 100000
          description: Number of simulated rate paths.
        seed:
          type: integer
          description: Random seed, for reproducible results.
    CompareResponse:
      type: object
      required: [currency, paths_simulated, savings, methodology_url, model_version, disclaimer]
      properties:
        currency:
          type: string
          const: USD
        paths_simulated:
          type: integer
        savings:
          $ref: '#/components/schemas/Distribution'
        probability_marian_cheaper:
          type: number
          minimum: 0
          maximum: 1
          description: Share of simulated paths in which Marian costs less than the alternative.
        expected_resets:
          type: number
          description: Average number of Marian rate resets per path.
        probability_reaches_floor:
          type: number
          minimum: 0
          maximum: 1
        assumptions_used:
          $ref: '#/components/schemas/RatePathAssumptions'
        methodology_url:
          type: string
          format: uri
        model_version:
          type: string
        disclaimer:
          type: string
    Distribution:
      type: object
      description: Lifetime savings of Marian versus the alternative, in present-value US dollars. Negative means Marian costs more.
      properties:
        mean: { type: number }
        median: { type: number }
        p5: { type: number }
        p25: { type: number }
        p75: { type: number }
        p95: { type: number }
        histogram:
          type: array
          items:
            type: object
            properties:
              lower: { type: number }
              upper: { type: number }
              share: { type: number, minimum: 0, maximum: 1 }
    Error:
      type: object
      required: [error]
      properties:
        error: { type: string }
