riskmodels-app Fundamentals API

The Fundamentals API from riskmodels-app — 1 operation(s) for fundamentals.

Operations 1

GET /fundamentals/{ticker} Point-in-time quarterly fundamentals (derived analytics + SEC-sourced raw) #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/riskmodels-app:riskmodels-app-fundamentals-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

riskmodels-app-fundamentals-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: RiskModels Fundamentals API
  version: 3.0.0-agent
  description: 'POST /decompose returns variance shares and ETF hedge ratios for any US equity, separating factor exposure from the residual bet so you can hedge what you don''t want. Daily history to 2000 across ~3,000 US equities.

    Precision equity risk intelligence platform with AI agent integration.


    **New in v3.0.0-agent:**

    - OAuth2 client credentials flow for machine-to-machine auth

    - Plaid Investments integration for live portfolio sync

    - MCP (Model Context Protocol) server for AI agent tools

    - Compliance manifests for AI marketplace integration

    - Per-key rate limiting and scoped access control


    **Data**: Universe `uni_mc_3000` (top ~3,000 US stocks by market cap), date range 2000 to present (deep panel; stock-specific skill series from ~2001 after warmup), updated daily end-of-day. Model outputs are computed by the ERM3 regression system (Huber/Ridge), with Zarr v2 archives on Google Cloud Storage for research pipelines. The live API reads primarily from Supabase **V3** tables: long-form `security_history` (returns, volatility, L1/L2/L3 hedge ratios and explained-risk metrics), wide latest rows in `security_history_latest`, identity in `symbols`, plus supporting surfaces such as `trading_calendar`, `erm3_landing_chart_cache`, and `macro_factors`. Cross-sectional **rankings** (`GET /rankings/*`) are served from precomputed rank metric keys in `security_history`, not a separate `erm3_rankings` table. Hedge ratios (`*_hr`) are **dollar_ratio** ETF notionals per $1 stock and are distinct from regression **betas** (`l1_mkt_beta`, `l2_sec_beta`, `l3_sub_beta`), which are dimensionless coefficients from the hierarchical L1/L2/L3 regression. Both are exposed under `MetricsV3` and on `security_history_latest`. See `SEMANTIC_ALIASES.md` for the full HR-vs-beta convention.


    **Authentication Methods:**

    1. Session cookies (web app)

    2. API Key/Secret via Bearer token (external integrations)

    3. OAuth2 client credentials (AI agents, npm package)


    **Security Features:**

    - GCP KMS envelope encryption for portfolio data

    - Cryptographic shredding on key deletion

    - HMAC-SHA256 webhook verification

    - Row-level security (RLS) via Supabase


    **Pricing**: Per-request billing with prepaid balance. Cached responses are free. Many metered responses include `_agent.cost_usd` in the JSON body; others bill silently — always check the `X-API-Cost-USD` response header when present. Metered operations also expose `x-pricing` (OpenAPI extension) with `capability_id`, `tier` (`baseline` | `premium`), `model`, `cost_usd`, `billing_code`, and optional `min_charge` / per-token fields — aligned with `GET /pricing` and `lib/agent/capabilities.ts`.

    **Lineage**: JSON data responses include `_metadata` (model version, data_as_of, factor set) and headers `X-Risk-Model-Version`, `X-Data-As-Of`, `X-Factor-Set-Id`, `X-Universe-Size`. Parquet and CSV bodies omit `_metadata`; use the same `X-Risk-*` headers on the HTTP response.

    **Tabular exports (Parquet / CSV):** For bulk historical loads, time-series endpoints accept `format=parquet` or `format=csv`, or (when `format` is omitted) `Accept: application/vnd.apache.parquet` or `Accept: text/csv`. Successful responses use `Content-Type: application/vnd.apache.parquet` or `text/csv; charset=utf-8` and `Content-Disposition: attachment` with a descriptive filename. Each export is a single flat table; column names and types match the per-operation schemas referenced in the response media type descriptions (aligned with JSON row objects or zipped parallel arrays). Parquet is produced via schema inference from the first row (UTF8 strings, DOUBLE floats, INT64 integers, BOOLEAN, TIMESTAMP_MILLIS for JavaScript Date values). CSV uses a header row, comma separators, UTF-8, and RFC 4180-style quoting when needed. Prefer Parquet for typed columnar stacks (pandas, Polars, Arrow); use CSV for spreadsheets and lightweight scripting.'
  contact:
    name: RiskModels Support
    email: service@riskmodels.app
    url: https://riskmodels.app
  termsOfService: https://riskmodels.app/legal
  license:
    name: Commercial
    url: https://riskmodels.app/legal
servers:
- url: https://riskmodels.app/api
  description: Production — all metered endpoints (`/metrics`, `/snapshot`, `/decompose`, `/batch/analyze`, `/portfolio/*`, etc.).
- url: https://riskmodels.app
  description: Discovery origin — `/.well-known/*` manifests (`mcp.json`, `ai-plugin.json`, `agentic-disclosure.json`) live at the site origin without the `/api` prefix. Generated clients that hard-code the first server entry must strip `/api` before requesting these paths.
security:
- BearerAuth: []
tags:
- name: Fundamentals
paths:
  /fundamentals/{ticker}:
    get:
      summary: Point-in-time quarterly fundamentals (derived analytics + SEC-sourced raw)
      description: 'Quarterly fundamentals for a single ticker, point-in-time filtered: a row is visible if and only if its `filed_date` is on or before `as_of` (never "latest"). `filed_date_source` is `exact` (vendor filing date) or `approx` (period_end + 45 days, the 10-Q deadline, when the vendor date is missing).


        **Derived analytics + per-cell raw SEC exposure.** Rows carry TTM profitability ratios (`roe_ttm`, `roa_ttm`, `fcf_margin`), capital-return ratios (`payout_ratio`, `retention_ratio`, `buyback_ratio`, `total_payout_ratio`, `sustainable_growth`), `leverage_ratio`, long-window ERM3 valuation betas with provenance, the cost-of-capital layer (`cost_of_equity`, strict `cost_of_debt` / `wacc`, parallel `cost_of_debt_imputed` / `wacc_imputed`, and `economic_profit`), and the equity-bridge residual + inputs mask. `sec_facts` carries RAW line items for the cells whose serving value is SEC XBRL (public); vendor-sourced cells are not included there.


        Numeric line items are stored at ~7 significant figures (float32) — suitable for analysis, not cent-level reconciliation. `gross_margin` and `operating_margin` are currently always null (inputs not yet in the store). `market_cap` is a current snapshot, not point-in-time per quarter.


        **Disclosures (also returned in every response body):**

        - Realized historical data only. No forecasts, no analyst targets, no buy/sell

        signals.


        - Coverage starts ~2009 for most filers; pre-2009 and small-cap or

        recently-IPO''d names are thin. Missing fields are null.


        - `beta_market` is the long-window valuation beta used by the CAPM layer,

        not the short-half-life hedging beta on the daily risk surface. For defensive

        names `cost_of_equity` can still fall below the risk-free rate.


        - WACC uses BOOK-value weights. Market-value weights are the textbook

        convention; compute them yourself if you have market-cap access.


        - Strict `cost_of_debt` and `wacc` are never silently filled. When trusted

        SEC debt is positive but TTM interest expense cannot form a strict debt

        cost, the separate imputed fields may use a PIT-lagged high-quality-market

        proxy. Its spread is the monthly Treasury HQM 10-year spot yield minus

        the same-month GS10 monthly average; that stored spread is then added to

        the separate period-end point-in-time 10-year Treasury rate. HQM month M

        becomes eligible on day 10 of M+1. The proxy covers the A/AA/AAA market;

        it is not issuer-specific.


        - TTM sums flows over the trailing 4 reported quarters; stock quantities are

        point-in-time (ROE denominator uses trailing-4-quarter average equity).

        Ratios need 4 finite quarters or they are null.


        - `erp` (default 0.05) and `tax_rate` (default 0.21) are request parameters

        echoed in the response. The documented defaults are used when omitted;

        no equity-risk-premium opinion is stored in the data.


        - `rf_rate` is the Treasury constant-maturity yield at the selected

        `rf_tenor` (3m|1y|2y|5y|10y|30y, default 10y — the valuation convention),

        sampled at the last observation on or before each quarter''s period end.

        A short tenor should be paired with a bill-basis ERP or cost of capital

        is understated.


        **Authentication:** Required (API Key or OAuth2)

        **Billing:** $0.02 per request (deducted from account balance)

        **Rate Limit:** 60 requests/minute (default)


        Per-symbol, per-call only: no batch variant, no CSV/bulk export (JSON only).'
      operationId: getFundamentals
      tags:
      - Fundamentals
      x-pricing:
        capability_id: fundamentals
        tier: baseline
        model: per_request
        cost_usd: 0.02
        currency: USD
        billing_code: fundamentals_v2
      security:
      - BearerAuth: []
      - OAuth2AuthorizationCode:
        - mcp:read
      parameters:
      - name: ticker
        in: path
        required: true
        schema:
          type: string
        description: Ticker symbol (case-insensitive).
        example: AAPL
      - name: as_of
        in: query
        required: false
        schema:
          type: string
          format: date
        description: 'Point-in-time date. Rows are visible iff filed_date <= as_of. Default: today.

          '
        example: '2026-03-31'
      - name: periods
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 40
          default: 8
        description: Number of quarterly rows returned (most recent last). Max 40.
      - name: erp
        in: query
        required: false
        schema:
          type: number
          minimum: 0
          maximum: 0.5
          default: 0.05
        description: Equity-risk-premium request parameter for the cost-of-capital layer; default 0.05 when omitted, with no ERP opinion stored in the data.
      - name: tax_rate
        in: query
        required: false
        schema:
          type: number
          minimum: 0
          maximum: 1
          default: 0.21
        description: Tax rate applied to the WACC debt shield.
      - name: rf_tenor
        in: query
        required: false
        schema:
          type: string
          enum:
          - 3m
          - 1y
          - 2y
          - 5y
          - 10y
          - 30y
          default: 10y
        description: Treasury constant-maturity tenor backing rf_rate. Default 10y (valuation convention). Pair a short tenor with a bill-basis ERP or cost of capital is understated.
      - name: grid
        in: query
        required: false
        schema:
          type: boolean
          default: false
        description: When true, the response also carries `sensitivity_grid` — `cost_of_equity`, strict `wacc`, parallel `wacc_imputed`, and `economic_profit` across `erp_grid` x `rf_tenor_grid` for the latest PIT-visible period only (not a time series — a "what if my assumptions were different today" table). Same billing as the base call; no extra cost.
      - name: erp_grid
        in: query
        required: false
        schema:
          type: string
        description: 'Comma-separated ERP values for the sensitivity grid (1-10 values, each in [0, 0.5]), e.g. `0.03,0.04,0.05,0.06,0.07`. Ignored unless `grid=true`. Default: `0.03,0.04,0.05,0.06,0.07`.'
        example: 0.03,0.04,0.05,0.06,0.07
      - name: rf_tenor_grid
        in: query
        required: false
        schema:
          type: string
        description: 'Comma-separated subset of `3m,1y,2y,5y,10y,30y` for the sensitivity grid. Ignored unless `grid=true`. Default: all six tenors.'
        example: 1y,10y,30y
      responses:
        '200':
          description: PIT quarterly fundamentals rows.
          headers:
            X-API-Cost-USD:
              schema:
                type: string
              description: Cost deducted for this request (e.g. "0.02").
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Request limit per minute
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: Remaining requests in current window
            X-RateLimit-Reset:
              schema:
                type: integer
              description: Unix timestamp when limit resets
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FundamentalsResponse'
        '400':
          description: Malformed ticker or query parameter.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid Bearer token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: Insufficient balance.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InsufficientBalance'
        '404':
          description: Ticker not present in the fundamentals panel.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before retrying
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitExceeded'
components:
  schemas:
    RateLimitExceeded:
      type: object
      description: Returned when the per-minute rate limit is exceeded (HTTP 429).
      properties:
        error:
          type: string
          enum:
          - RATE_LIMIT_EXCEEDED
          example: RATE_LIMIT_EXCEEDED
        message:
          type: string
          example: Rate limit exceeded. Retry after 2026-03-08T12:34:56Z
        retry_after:
          type: string
          format: date-time
          description: ISO timestamp after which the client may retry.
          example: '2026-03-08T12:34:56Z'
        limit:
          type: integer
          description: Requests allowed per minute for this key.
          example: 60
    InsufficientBalance:
      type: object
      description: Returned when the account prepaid balance is exhausted (HTTP 402).
      properties:
        error:
          type: string
          enum:
          - INSUFFICIENT_BALANCE
          example: INSUFFICIENT_BALANCE
        message:
          type: string
          example: 'Insufficient balance. Current balance: $0.00. Top up at https://riskmodels.app/billing'
        balance_usd:
          type: number
          format: float
          example: 0
        top_up_url:
          type: string
          format: uri
          example: https://riskmodels.app/billing
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
          description: Machine-readable error code.
          example: TICKER_NOT_FOUND
        message:
          type: string
          description: Human-readable error description with suggested action.
          example: Ticker 'XYZABC' not found in universe 'uni_mc_3000'. Check ticker spelling or try a different universe.
        code:
          type: integer
          description: HTTP status code.
          example: 404
        history_starts:
          type: string
          format: date
          description: 'Earliest non-null daily close or return date for the resolved security. Present only when a historical request ends before the security''s own history begins.

            '
        details:
          type: object
          properties:
            field:
              type: string
              example: ticker
            received:
              type: string
              example: XYZABC
            universe:
              type: string
              example: uni_mc_3000
            suggestion:
              type: string
              example: Check for typos or use ticker search endpoint
    FundamentalsRow:
      type: object
      description: 'One PIT quarterly observation. Derived analytics plus, in sec_facts, raw line items for cells whose serving value is SEC XBRL (public). Any ratio lacking 4 finite trailing quarters, or hitting a guard (equity <= 0, debt <= 0, missing beta), is null. Never clipped.

        '
      properties:
        period_end_date:
          type: string
          format: date
          description: Quarterly reporting period end.
        filed_date:
          type:
          - string
          - 'null'
          format: date
          description: Filing date used for PIT visibility (filed_date <= as_of).
        filed_date_source:
          type:
          - string
          - 'null'
          enum:
          - exact
          - approx
          - null
          description: 'exact = vendor filing date; approx = period_end + 45 days (10-Q deadline) when the vendor date is missing.

            '
        sec_facts:
          type: object
          description: 'Raw line items for this period, present only for cells whose serving value is SEC XBRL. Keyed by concept (revenue, net_income, total_equity, cash_from_operations, dividends_paid, share_repurchases, etc.); a concept is absent when its cell is vendor-sourced or empty.

            '
          additionalProperties:
            type: object
            properties:
              value:
                type: number
              source:
                type: string
                enum:
                - us_gaap
                - ifrs
        gross_margin:
          type:
          - number
          - 'null'
          description: Currently always null — inputs not yet in the store.
        operating_margin:
          type:
          - number
          - 'null'
          description: Currently always null — inputs not yet in the store.
        roe_ttm:
          type:
          - number
          - 'null'
          description: TTM net income over trailing-4-quarter average equity. Null if average equity <= 0.
        roa_ttm:
          type:
          - number
          - 'null'
          description: TTM net income over trailing-4-quarter average total assets.
        leverage_ratio:
          type:
          - number
          - 'null'
          description: Total debt / total equity (book). Null if equity <= 0.
        fcf_margin:
          type:
          - number
          - 'null'
          description: TTM free cash flow (CFO - capex) over TTM revenue.
        payout_ratio:
          type:
          - number
          - 'null'
          description: TTM dividends paid / TTM net income. Null when TTM net income <= 0.
        retention_ratio:
          type:
          - number
          - 'null'
          description: 1 - payout_ratio (the reinvestment-rate proxy). Cash basis.
        buyback_ratio:
          type:
          - number
          - 'null'
          description: TTM share repurchases / TTM net income.
        total_payout_ratio:
          type:
          - number
          - 'null'
          description: (TTM dividends paid + share repurchases) / TTM net income. May exceed 1.
        sustainable_growth:
          type:
          - number
          - 'null'
          description: retention_ratio * roe_ttm.
        equity_bridge_residual:
          type:
          - number
          - 'null'
          description: 'Plug that closes the equity roll-forward by construction (total_equity_t - total_equity_{t-1} = sum of tagged components + residual). Frequently large; a decomposition aid, not a measured line. Null on a symbol''s first reported period.

            '
        equity_bridge_inputs:
          type: array
          items:
            type: string
          description: 'Components that backed the residual. A component MISSING from the list means its movement is inside the residual, not that it was zero.

            '
        beta_market:
          type:
          - number
          - 'null'
          description: Long-window (~60-month monthly, Vasicek-shrunk) ERM3 valuation beta sampled at the last month end <= period_end.
        beta_sector:
          type:
          - number
          - 'null'
        beta_subsector:
          type:
          - number
          - 'null'
        beta_source:
          type:
          - string
          - 'null'
          enum:
          - none
          - in-universe
          - out-of-universe
          - post-delisting
          - null
          description: Beta provenance. Post-delisting betas are never forward-filled.
        rf_rate:
          type:
          - number
          - 'null'
          description: Treasury constant-maturity rate for the requested rf_tenor, sampled at the last observation <= period_end.
        cost_of_equity:
          type:
          - number
          - 'null'
          description: rf_rate + beta_market * erp, using the long-window valuation beta. Can fall below rf_rate for defensive names.
        cost_of_debt:
          type:
          - number
          - 'null'
          description: Strict reported-data value, TTM interest expense / trusted SEC debt. Never silently imputed.
        cost_of_debt_imputed:
          type:
          - number
          - 'null'
          description: 'Separate PIT-lagged high-quality-market proxy for positive trusted SEC debt when strict cost_of_debt is null: the period-end point-in-time 10-year Treasury rate plus a spread formed from monthly Treasury HQM and GS10 observations. Not issuer-specific.

            '
        cost_of_debt_imputation:
          $ref: '#/components/schemas/CostOfDebtImputation'
        wacc:
          type:
          - number
          - 'null'
          description: Strict BOOK-value-weighted average cost of capital with tax-shielded reported-data debt leg.
        wacc_imputed:
          type:
          - number
          - 'null'
          description: BOOK-value-weighted WACC using cost_of_debt_imputed. Strict wacc remains unchanged.
        economic_profit:
          type:
          - number
          - 'null'
          description: (roe_ttm - cost_of_equity) * total equity (equity-charge form). Null if equity <= 0.
        market_cap:
          type:
          - number
          - 'null'
          description: Reserved. Currently null per row; see the top-level market_cap snapshot.
    CostOfDebtImputation:
      type: object
      description: 'Inspectable provenance for the parallel PIT-lagged high-quality-market debt-cost proxy. The HQM series covers the A/AA/AAA high-quality corporate market; it is not an issuer rating or issuer bond yield.

        '
      required:
      - status
      - method
      - risk_free_rate
      - credit_spread
      - hqm_spot_rate
      - hqm_observation_date
      - corporate_series
      - treasury_series
      - rating_scope
      properties:
        status:
          type: string
          enum:
          - used
          - not_needed
          - unavailable
        method:
          type: string
          enum:
          - rf_10y_plus_treasury_hqm_10y_spread
        risk_free_rate:
          type:
          - number
          - 'null'
          description: Period-end point-in-time 10-year Treasury input used in cost_of_debt_imputed (fraction).
        credit_spread:
          type:
          - number
          - 'null'
          description: 'Treasury HQM 10-year monthly spot yield minus the same-month GS10 monthly average used to form the stored spread. This is not calculated from risk_free_rate, which is the separate period-end point-in-time 10-year Treasury input.

            '
        hqm_spot_rate:
          type:
          - number
          - 'null'
          description: Treasury HQM 10-year monthly high-quality corporate spot yield (fraction).
        hqm_observation_date:
          type:
          - string
          - 'null'
          format: date
          description: 'Reference-month stamp for the monthly HQM/GS10 pair, represented as the first day of that month. It is not a publication timestamp. The sampler makes month M eligible on day 10 of M+1 to preserve PIT lag.

            '
        corporate_series:
          type: string
          enum:
          - HQMCB10YR
        treasury_series:
          type: string
          enum:
          - GS10
        rating_scope:
          type: string
          enum:
          - A/AA/AAA high-quality market; not issuer-specific
    FundamentalsResponse:
      type: object
      description: 'Wire response for `GET /fundamentals/{ticker}`. Rows are ordered oldest to newest and PIT-filtered by filed_date <= as_of. `disclosures` echoes the parameters and the interpretation caveats.

        '
      required:
      - ticker
      - as_of
      - rows
      - disclosures
      properties:
        ticker:
          type: string
          example: AAPL
        as_of:
          type: string
          format: date
        periods_returned:
          type: integer
        rows:
          type: array
          items:
            $ref: '#/components/schemas/FundamentalsRow'
        market_cap:
          type: object
          description: Current market cap snapshot (not PIT per quarter).
          properties:
            value:
              type:
              - number
              - 'null'
            basis:
              type: string
              example: current_snapshot
            note:
              type: string
        sensitivity_grid:
          $ref: '#/components/schemas/FundamentalsSensitivityGrid'
          description: 'Present only when the request set `grid=true`. Null (with a `note`) when no PIT-visible period exists at `as_of`.

            '
        disclosures:
          type: object
          additionalProperties: true
          description: 'Realized-historical-only statement, ~2009 coverage note, long-window valuation-beta cost-of-equity caveat, strict-versus-proxy book-weight WACC notes, TTM convention, and the request-parameter echo.

            '
        _metadata:
          type: object
          additionalProperties: true
    FundamentalsSensitivityGrid:
      type: object
      description: 'Cost-of-capital sensitivity grid for the latest PIT-visible period only — `cost_of_equity`, strict `wacc`, parallel `wacc_imputed`, and `economic_profit` recomputed across every combination of `erp_values` x `rf_tenor_values`. `cost_of_debt_imputed` and its provenance are fixed 10-year proxy inputs shared by all cells; the chosen grid tenor changes the cost-of-equity leg, not that debt proxy. Pure derived analytics, parameterized instead of single-valued. `cells` is row-major: `cells[i][j]` pairs `erp_values[i]` with `rf_tenor_values[j]`.

        '
      required:
      - period_end_date
      - erp_values
      - rf_tenor_values
      - tax_rate
      - cost_of_debt_imputed
      - cost_of_debt_imputation
      - cells
      properties:
        period_end_date:
          type: string
          format: date
        filed_date:
          type:
          - string
          - 'null'
          format: date
        erp_values:
          type: array
          items:
            type: number
        rf_tenor_values:
          type: array
          items:
            type: string
            enum:
            - 3m
            - 1y
            - 2y
            - 5y
            - 10y
            - 30y
        tax_rate:
          type: number
        cost_of_debt_imputed:
          type:
          - number
          - 'null'
          description: Fixed 10-year debt-cost proxy shared by every grid cell.
        cost_of_debt_imputation:
          $ref: '#/components/schemas/CostOfDebtImputation'
        cells:
          type: array
          description: Row-major [erp_values.length][rf_tenor_values.length].
          items:
            type: array
            items:
              type: object
              properties:
                cost_of_equity:
                  type:
                  - number
                  - 'null'
                wacc:
                  type:
                  - number
                  - 'null'
                wacc_imputed:
                  type:
                  - number
                  - 'null'
                economic_profit:
                  type:
                  - number
                  - 'null'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: rm_agent_{environment}_{random}_{checksum}
      description: 'API key in format `rm_agent_{live|test}_{random}_{checksum}` or `rm_user_{random}_{checksum}`. Obtain via `POST /api/auth/provision` or from riskmodels.app/settings → API Keys. Include as: `Authorization: Bearer rm_agent_live_...`

        '
    OAuth2AuthorizationCode:
      type: oauth2
      description: 'OAuth 2.0 authorization code flow with PKCE (S256), used by MCP clients (Claude Desktop, Cursor, ChatGPT Developer Mode, Grok) that self-register via `POST /api/oauth/register`. Public clients only — no `client_secret` is issued and `token_endpoint_auth_method` is `none`.


        The access token this flow returns **is** an `rm_user_*` API key (1 h TTL, 30 d rotating refresh token), so it authenticates every `BearerAuth` operation below, not just `/api/mcp/sse`. Scope is currently informational: the API records the presented scope for telemetry but authorises by key validity and account balance, not by scope.


        Discovery metadata: `/.well-known/oauth-authorization-server`.

        '
      flows:
        authorizationCode:
          authorizationUrl: https://riskmodels.app/oauth/authorize
          tokenUrl: https://riskmodels.app/api/oauth/token
          refreshUrl: https://riskmodels.app/api/oauth/token
          scopes:
            mcp:read: Read access to risk analytics (the only scope the authorization server advertises)