{
  "components": {
    "schemas": {
      "AIAnalysisChangesResponse": {
        "description": "Response for GET /v1/ai-analysis/changes.\n\nPaginated cross-asset feed of AI analysis changes since a given timestamp.\nCursor-based pagination: next_cursor is base64({computed_at, diff_id}).\nImplemented by T-654.\n\nLEGAL: Not financial advice. Not a fatwa. Methodology disclosed.",
        "properties": {
          "has_more": {
            "default": false,
            "description": "True if there are more results beyond this page.",
            "title": "Has More",
            "type": "boolean"
          },
          "items": {
            "description": "List of asset changes (most recent first, up to limit).",
            "items": {
              "$ref": "#/components/schemas/AssetChangeSummary"
            },
            "title": "Items",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/AIHistoryMeta",
            "description": "AMF disclaimer + tier metadata."
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opaque base64 cursor for the next page. Null if no more pages.",
            "title": "Next Cursor"
          },
          "total_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total matching records (may be None if count is expensive).",
            "title": "Total Count"
          }
        },
        "required": [
          "meta"
        ],
        "title": "AIAnalysisChangesResponse",
        "type": "object"
      },
      "AIAnalysisDiffResponse": {
        "description": "Response for GET /v1/assets/{asset_id}/ai-analysis/history/diff.\n\nCompares two snapshots for the same asset and analysis type.\nImplemented by T-652.\n\nAMF \u00a75.3 compliance: raw text diffs are NEVER exposed.\nText changes are signalled only via text_changed (bool),\ncosine_similarity (float, Jaccard token_set_ratio \u2014 named cosine_similarity for DX per COMITE-011 \u00a72.2),\nand major_text_shift (bool).\n\nLEGAL: Not financial advice. Not a fatwa. Methodology disclosed.",
        "properties": {
          "analysis_type": {
            "description": "Analysis type queried.",
            "title": "Analysis Type",
            "type": "string"
          },
          "asset_id": {
            "description": "Asset identifier.",
            "title": "Asset Id",
            "type": "string"
          },
          "change_type_summary": {
            "description": "Dominant change type across all changed fields. Priority: RESTATEMENT > METHODOLOGY_CHANGE > MODEL_UPGRADE > DATA_REFRESH.",
            "enum": [
              "DATA_REFRESH",
              "MODEL_UPGRADE",
              "METHODOLOGY_CHANGE",
              "RESTATEMENT"
            ],
            "title": "Change Type Summary",
            "type": "string"
          },
          "changes": {
            "description": "List of changed fields with before/after values.",
            "items": {
              "$ref": "#/components/schemas/FieldChange"
            },
            "title": "Changes",
            "type": "array"
          },
          "cosine_similarity": {
            "anyOf": [
              {
                "maximum": 1.0,
                "minimum": 0.0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Jaccard token_set_ratio vs previous snapshot (rapidfuzz). Named cosine_similarity for DX consistency (COMITE-011 \u00a72.2). Null if text_changed is False.",
            "title": "Cosine Similarity"
          },
          "from_snapshot": {
            "$ref": "#/components/schemas/DiffSnapshotRef",
            "description": "Earlier snapshot reference."
          },
          "major_text_shift": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True if cosine_similarity < 0.7 (material restatement threshold). Null if text_changed is False.",
            "title": "Major Text Shift"
          },
          "meta": {
            "$ref": "#/components/schemas/AIHistoryMeta",
            "description": "AMF disclaimer + tier metadata."
          },
          "text_changed": {
            "description": "True if the summary text changed between the two snapshots.",
            "title": "Text Changed",
            "type": "boolean"
          },
          "ticker": {
            "description": "Canonical ticker symbol.",
            "title": "Ticker",
            "type": "string"
          },
          "to_snapshot": {
            "$ref": "#/components/schemas/DiffSnapshotRef",
            "description": "Later snapshot reference."
          }
        },
        "required": [
          "asset_id",
          "ticker",
          "analysis_type",
          "from_snapshot",
          "to_snapshot",
          "change_type_summary",
          "text_changed",
          "meta"
        ],
        "title": "AIAnalysisDiffResponse",
        "type": "object"
      },
      "AIAnalysisImmutabilitySchema": {
        "description": "Immutability block per PROJECT_USER_REQUIREMENTS \u00a78.3.2.\n\nExposed in all tiers (Free+) \u2014 this is the moat.\ncontent_hash = 'sha256:<64-hex>' or '' when the row predates backfill (T-619).",
        "properties": {
          "content_hash": {
            "description": "'sha256:<64-hex>' of the canonical JSON, or '' for pre-backfill rows. Clients should test content_hash != '' before relying on immutability.",
            "title": "Content Hash",
            "type": "string"
          },
          "hash_algorithm": {
            "default": "sha256",
            "description": "Hash algorithm used. Currently always 'sha256'.",
            "title": "Hash Algorithm",
            "type": "string"
          },
          "signed": {
            "default": false,
            "description": "Whether the hash is cryptographically signed. Always false at this scale.",
            "title": "Signed",
            "type": "boolean"
          }
        },
        "required": [
          "content_hash"
        ],
        "title": "AIAnalysisImmutabilitySchema",
        "type": "object"
      },
      "AIAnalysisLatestResponse": {
        "description": "Response for GET /v1/assets/{asset_id}/ai-analysis/latest.\n\nReturns the most recent AI analysis snapshot for the given asset and type.\nImplemented by T-653.\n\nLEGAL: Not financial advice. Not a fatwa. Methodology disclosed.",
        "properties": {
          "analysis_type": {
            "description": "Analysis type: halal_analysis | market_context | regime.",
            "title": "Analysis Type",
            "type": "string"
          },
          "asset_id": {
            "description": "Asset identifier (matches path parameter).",
            "title": "Asset Id",
            "type": "string"
          },
          "content": {
            "$ref": "#/components/schemas/SnapshotContent",
            "description": "AI-generated content block."
          },
          "freshness": {
            "$ref": "#/components/schemas/SnapshotFreshness",
            "description": "Freshness status block."
          },
          "generated_at": {
            "description": "UTC timestamp when this snapshot was generated.",
            "format": "date-time",
            "title": "Generated At",
            "type": "string"
          },
          "immutability": {
            "$ref": "#/components/schemas/SnapshotImmutability",
            "description": "Content hash immutability block."
          },
          "meta": {
            "$ref": "#/components/schemas/AIHistoryMeta",
            "description": "AMF disclaimer + tier metadata."
          },
          "provenance": {
            "$ref": "#/components/schemas/SnapshotProvenance",
            "description": "Canonical \u00a78.3.2 provenance block."
          },
          "snapshot_id": {
            "description": "Unique snapshot identifier (UUID).",
            "title": "Snapshot Id",
            "type": "string"
          },
          "ticker": {
            "description": "Canonical ticker symbol (e.g. 'BTC', 'AAPL').",
            "title": "Ticker",
            "type": "string"
          }
        },
        "required": [
          "snapshot_id",
          "asset_id",
          "ticker",
          "analysis_type",
          "generated_at",
          "content",
          "provenance",
          "immutability",
          "freshness",
          "meta"
        ],
        "title": "AIAnalysisLatestResponse",
        "type": "object"
      },
      "AIAnalysisProvenanceSchema": {
        "description": "Provenance block per PROJECT_USER_REQUIREMENTS \u00a78.3.2.\n\nExposed in all tiers (Free+).\nprompt_hash and methodology_version gated to ai:lineage scope (Growth+);\ncaller must set them to None when scope is absent.",
        "properties": {
          "data_window_from": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start of the data window used to generate the analysis (UTC, RFC 3339).",
            "title": "Data Window From"
          },
          "data_window_to": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End of the data window used to generate the analysis (UTC, RFC 3339).",
            "title": "Data Window To"
          },
          "input_tokens": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Number of input tokens billed for this generation.",
            "title": "Input Tokens"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable methodology label (e.g. 'market-context-v1.2'). Growth (ai:lineage) only.",
            "title": "Methodology Version"
          },
          "model_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Anthropic model used (e.g. 'claude-haiku-4-5').",
            "title": "Model Id"
          },
          "output_tokens": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Number of output tokens billed for this generation.",
            "title": "Output Tokens"
          },
          "prompt_hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "sha256:<hex> of effective prompt \u2014 Growth (ai:lineage) only.",
            "title": "Prompt Hash"
          },
          "prompt_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opaque prompt version string from the prompt registry.",
            "title": "Prompt Version"
          }
        },
        "title": "AIAnalysisProvenanceSchema",
        "type": "object"
      },
      "AIHistoryMeta": {
        "description": "Meta block injected into all three endpoint responses.\n\nCarries mandatory AMF disclaimer (\u00a75.3) + ai_generated flag.\ntier_required documents the minimum subscription tier for this endpoint.",
        "properties": {
          "ai_generated": {
            "default": true,
            "description": "Always True \u2014 signals the payload is AI-generated.",
            "title": "Ai Generated",
            "type": "boolean"
          },
          "disclaimer": {
            "default": "Not financial advice. Not a fatwa. Methodology disclosed.",
            "description": "Mandatory AMF / legal disclaimer.",
            "title": "Disclaimer",
            "type": "string"
          },
          "methodology_url": {
            "default": "https://portfoliq.io/methodology",
            "description": "URL to the published methodology.",
            "title": "Methodology Url",
            "type": "string"
          },
          "tier_required": {
            "description": "Minimum subscription tier to access this endpoint.",
            "title": "Tier Required",
            "type": "string"
          }
        },
        "required": [
          "tier_required"
        ],
        "title": "AIHistoryMeta",
        "type": "object"
      },
      "AaoifiRatios": {
        "description": "AAOIFI Shari'a Standard financial ratios.\n\nThresholds (AAOIFI FAS/SS):\n  debt_to_market_cap          < 33%\n  cash_to_market_cap          < 33%\n  interest_income_to_revenue  < 5%\n\nD-087: is_halal_aaoifi signal computed from these ratios. NOT a fatwa.",
        "properties": {
          "cash_to_market_cap": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Cash and equivalents / market cap (AAOIFI threshold: < 33%).",
            "title": "Cash To Market Cap"
          },
          "debt_to_market_cap": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total debt / market cap (AAOIFI threshold: < 33%).",
            "title": "Debt To Market Cap"
          },
          "interest_income_to_revenue": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Interest income / total revenue (AAOIFI threshold: < 5%).",
            "title": "Interest Income To Revenue"
          }
        },
        "title": "AaoifiRatios",
        "type": "object"
      },
      "AddressSnapshot": {
        "description": "Latest on-chain metrics snapshot for one address \u00d7 chain.",
        "properties": {
          "address": {
            "description": "EVM address in lowercase hex (0x...).",
            "title": "Address",
            "type": "string"
          },
          "chain_id": {
            "description": "EVM chain ID. 1=ETH, 56=BSC, 137=Polygon, 42161=Arbitrum, 10=Optimism, 8453=Base.",
            "title": "Chain Id",
            "type": "integer"
          },
          "chain_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable chain name.",
            "title": "Chain Name"
          },
          "contract_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Verified contract name from Etherscan. Null if EOA or unverified.",
            "title": "Contract Name"
          },
          "is_contract": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True if smart contract, False if EOA. Null if not determined.",
            "title": "Is Contract"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data comes from curated fallback seed (no live API). False when sourced from live BigQuery/RPC pipeline. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable label from curated catalogue. Null if not in catalogue.",
            "title": "Label"
          },
          "native_balance": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Balance in native token (ETH, BNB, MATIC, etc.). Null if unavailable.",
            "title": "Native Balance"
          },
          "snapshot_date": {
            "description": "Date of the snapshot (YYYY-MM-DD).",
            "title": "Snapshot Date",
            "type": "string"
          },
          "tx_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total transaction count. Null for high-volume addresses (> 10k txs, API cap) or if unavailable.",
            "title": "Tx Count"
          }
        },
        "required": [
          "chain_id",
          "chain_name",
          "address",
          "snapshot_date"
        ],
        "title": "AddressSnapshot",
        "type": "object"
      },
      "AddressSnapshotMeta": {
        "description": "Metadata for GET /v1/onchain/{chain_id}/{address}.",
        "properties": {
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "fetched_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Fetched At",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "fetched_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "AddressSnapshotMeta",
        "type": "object"
      },
      "AddressSnapshotResponse": {
        "description": "Response for GET /v1/onchain/{chain_id}/{address}.",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/AddressSnapshot"
          },
          "meta": {
            "$ref": "#/components/schemas/AddressSnapshotMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "AddressSnapshotResponse",
        "type": "object"
      },
      "AiAnalysisBlock": {
        "description": "AI analysis block in an asset payload.\n\nIf ai:read scope is present: fields are populated from sat_asset_ai_analysis.\nIf ai:read scope is absent: all data fields are None + _upsell is set.\n\nThe _upsell field uses model_config populate_by_name=True to allow the\nalias _upsell to be used in serialisation.\n\nDisclaimer: Not financial advice. AI-generated analysis. Methodology disclosed.",
        "properties": {
          "_upsell": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UpsellMarker"
              },
              {
                "type": "null"
              }
            ],
            "description": "Upsell marker \u2014 present when ai:read scope is absent. Contains the required scope and upgrade URL. None when ai:read scope is present and data is served."
          },
          "analysis_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Type of AI analysis: token_classification | token_methodology | fundamental_summary | news_summary | sentiment_score. None if ai:read scope absent.",
            "title": "Analysis Type"
          },
          "generated_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "UTC timestamp when the AI analysis was generated. None if scope absent.",
            "title": "Generated At"
          },
          "model": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Anthropic model used to generate the analysis (e.g. 'claude-haiku-4-5', 'claude-sonnet-4-6'). None if scope absent.",
            "title": "Model"
          },
          "prompt_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Version of the prompt template from prompts/registry.yml. Enables reproducibility and auditability. None if scope absent.",
            "title": "Prompt Version"
          },
          "sentiment_score": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Sentiment score in range [-1.0, 1.0]. Negative = bearish context, positive = bullish context. Factual aggregate of public signals only \u2014 not a price forecast. None if ai:read scope absent.",
            "title": "Sentiment Score"
          },
          "summary": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "AI-generated narrative summary. Factual and descriptive. AMF guard: no price target, no investment recommendation. None if ai:read scope absent.",
            "title": "Summary"
          }
        },
        "title": "AiAnalysisBlock",
        "type": "object"
      },
      "AiAnalysisHistoryResponse": {
        "description": "Response envelope for GET /v1/assets/{asset_id}/ai-analysis/history.\n\nNote: _meta (COMITE-025 \u00a73 D3 freshness block) is injected directly\ninto the JSONResponse dict by the router (not a Pydantic field) because\nPydantic v2 disallows field names with leading underscores.",
        "properties": {
          "analysis_type": {
            "description": "Requested analysis type.",
            "title": "Analysis Type",
            "type": "string"
          },
          "as_of": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Effective bi-temporal filter applied (RFC 3339), or null if absent.",
            "title": "As Of"
          },
          "asset_id": {
            "description": "Asset identifier \u2014 coingecko slug (e.g. 'bitcoin', 'ethereum'). Type: string (coingecko_id). NOT the integer asset_id from /v1/star/dim/assets/.",
            "title": "Asset Id",
            "type": "string"
          },
          "items": {
            "description": "Ordered list of analyses (most recent first).",
            "items": {
              "$ref": "#/components/schemas/AiAnalysisItem"
            },
            "title": "Items",
            "type": "array"
          },
          "limit": {
            "description": "Applied limit (1\u201350).",
            "title": "Limit",
            "type": "integer"
          },
          "total": {
            "description": "Total matching rows (before limit).",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "asset_id",
          "analysis_type",
          "total",
          "limit"
        ],
        "title": "AiAnalysisHistoryResponse",
        "type": "object"
      },
      "AiAnalysisItem": {
        "description": "Single AI analysis record in the history list.\n\nReturned for each row matching the query filters.\n\nBackward-compatible additions (TICKET-621):\n- provenance: AIAnalysisProvenanceSchema \u2014 canonical \u00a78.3.2 block (all tiers)\n- immutability: AIAnalysisImmutabilitySchema \u2014 content_hash moat (all tiers)",
        "properties": {
          "ai_metadata": {
            "$ref": "#/components/schemas/AiMetadata",
            "description": "COMITE-025 \u00a73 D3 metadata block."
          },
          "analysis_type": {
            "description": "Analysis type: halal_analysis | market_context | regime.",
            "title": "Analysis Type",
            "type": "string"
          },
          "asset_id": {
            "description": "Asset identifier \u2014 coingecko slug (e.g. 'bitcoin', 'ethereum'). Type: string. This is the coingecko_id, NOT the integer surrogate key from marts.dim_asset. Do NOT conflate with the integer asset_id exposed by /v1/star/dim/assets/{asset_id} (BIGSERIAL). SDK generators: treat as string.",
            "title": "Asset Id",
            "type": "string"
          },
          "data_lineage": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DataLineage"
              },
              {
                "type": "null"
              }
            ],
            "description": "Growth tier only: prompt_hash + methodology_version."
          },
          "generated_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "UTC timestamp of generation.",
            "title": "Generated At"
          },
          "immutability": {
            "$ref": "#/components/schemas/AIAnalysisImmutabilitySchema",
            "description": "Immutability block with content_hash. Exposed to all tiers (Free+) \u2014 content_hash is the portfolIQ moat."
          },
          "provenance": {
            "$ref": "#/components/schemas/AIAnalysisProvenanceSchema",
            "description": "Canonical \u00a78.3.2 provenance block. methodology_version and prompt_hash populated only for Growth (ai:lineage) tier."
          },
          "sentiment_score": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Sentiment [-1.0, 1.0]. Factual aggregate only.",
            "title": "Sentiment Score"
          },
          "summary": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "AI-generated narrative summary. Factual only \u2014 no price target.",
            "title": "Summary"
          }
        },
        "required": [
          "asset_id",
          "analysis_type",
          "ai_metadata",
          "provenance",
          "immutability"
        ],
        "title": "AiAnalysisItem",
        "type": "object"
      },
      "AiAnalysisType": {
        "description": "Allowed analysis types for the history endpoint.",
        "enum": [
          "halal_analysis",
          "market_context",
          "regime"
        ],
        "title": "AiAnalysisType",
        "type": "string"
      },
      "AiMetadata": {
        "description": "ai_metadata block \u2014 COMITE-025 \u00a73 D3.\n\nExposed in every item of the history response.",
        "properties": {
          "disclaimer": {
            "default": "Not financial advice. Not a fatwa. Methodology disclosed.",
            "description": "Mandatory AMF disclaimer.",
            "title": "Disclaimer",
            "type": "string"
          },
          "freshness_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "One of: fresh | stale | expired.",
            "title": "Freshness Status"
          },
          "generated_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "UTC timestamp when the analysis was generated.",
            "title": "Generated At"
          },
          "methodology_url": {
            "default": "https://portfoliq.io/methodology",
            "description": "URL to the published methodology (portfoliq.io/methodology).",
            "title": "Methodology Url",
            "type": "string"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable methodology label (e.g. 'aaoifi-v1.2').",
            "title": "Methodology Version"
          },
          "model_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Anthropic model used (e.g. 'claude-haiku-4-5').",
            "title": "Model Id"
          },
          "next_refresh_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Tier-dependent UTC deadline for the next refresh.",
            "title": "Next Refresh At"
          },
          "prompt_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opaque prompt version string from the prompt registry.",
            "title": "Prompt Version"
          }
        },
        "title": "AiMetadata",
        "type": "object"
      },
      "ApiKeyCreateRequest": {
        "properties": {
          "label": {
            "description": "Human-readable label for this key",
            "maxLength": 100,
            "title": "Label",
            "type": "string"
          }
        },
        "required": [
          "label"
        ],
        "title": "ApiKeyCreateRequest",
        "type": "object"
      },
      "ApiKeyCreateResponse": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "key_id": {
            "title": "Key Id",
            "type": "string"
          },
          "key_prefix": {
            "title": "Key Prefix",
            "type": "string"
          },
          "label": {
            "title": "Label",
            "type": "string"
          },
          "raw_key": {
            "title": "Raw Key",
            "type": "string"
          },
          "tier": {
            "title": "Tier",
            "type": "string"
          },
          "warning": {
            "default": "Store this key securely \u2014 it will not be shown again.",
            "title": "Warning",
            "type": "string"
          }
        },
        "required": [
          "key_id",
          "raw_key",
          "key_prefix",
          "label",
          "tier",
          "created_at"
        ],
        "title": "ApiKeyCreateResponse",
        "type": "object"
      },
      "ApiKeyCreatedResponse": {
        "description": "Response for POST /auth/keys \u2014 new key created, shown once.",
        "properties": {
          "created_at": {
            "title": "Created At",
            "type": "string"
          },
          "key_id": {
            "title": "Key Id",
            "type": "string"
          },
          "raw_key": {
            "title": "Raw Key",
            "type": "string"
          },
          "tier": {
            "title": "Tier",
            "type": "string"
          }
        },
        "required": [
          "key_id",
          "raw_key",
          "tier",
          "created_at"
        ],
        "title": "ApiKeyCreatedResponse",
        "type": "object"
      },
      "ApiKeyInfo": {
        "description": "Metadata for a single API key (raw_key never included).",
        "properties": {
          "created_at": {
            "title": "Created At",
            "type": "string"
          },
          "id": {
            "title": "Id",
            "type": "string"
          },
          "is_active": {
            "title": "Is Active",
            "type": "boolean"
          },
          "label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Label"
          },
          "last_used_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Used At"
          },
          "quota_per_hour": {
            "title": "Quota Per Hour",
            "type": "integer"
          },
          "tier": {
            "title": "Tier",
            "type": "string"
          },
          "usage_current_window": {
            "title": "Usage Current Window",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "label",
          "tier",
          "is_active",
          "created_at",
          "last_used_at",
          "usage_current_window",
          "quota_per_hour"
        ],
        "title": "ApiKeyInfo",
        "type": "object"
      },
      "ApiKeyListItem": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "is_active": {
            "title": "Is Active",
            "type": "boolean"
          },
          "key_id": {
            "title": "Key Id",
            "type": "string"
          },
          "key_prefix": {
            "title": "Key Prefix",
            "type": "string"
          },
          "label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Label"
          },
          "last_used_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Used At"
          },
          "tier": {
            "title": "Tier",
            "type": "string"
          }
        },
        "required": [
          "key_id",
          "key_prefix",
          "label",
          "tier",
          "is_active",
          "created_at",
          "last_used_at"
        ],
        "title": "ApiKeyListItem",
        "type": "object"
      },
      "ApiKeyListResponse": {
        "properties": {
          "keys": {
            "items": {
              "$ref": "#/components/schemas/ApiKeyListItem"
            },
            "title": "Keys",
            "type": "array"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "keys",
          "total"
        ],
        "title": "ApiKeyListResponse",
        "type": "object"
      },
      "ApiMeta": {
        "description": "Generic response metadata.\n\nSprint 28 T-409 \u2014 4 optional fields added for HS Phase 2 meta-envelope enrichment.\nAll new fields default to None for full backward-compatibility with existing clients.",
        "properties": {
          "ai_generated_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ai Generated At"
          },
          "ai_mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ai Mode"
          },
          "ai_model": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ai Model"
          },
          "benchmark_notice": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Benchmark Notice"
          },
          "cache_hit": {
            "default": false,
            "title": "Cache Hit",
            "type": "boolean"
          },
          "computed_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Computed At"
          },
          "data_methodology": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Data Methodology"
          },
          "data_quality": {
            "anyOf": [
              {
                "enum": [
                  "full",
                  "partial",
                  "empty"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Data Quality"
          },
          "disclaimer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disclaimer"
          },
          "disclaimer_lang_canonical": {
            "anyOf": [
              {
                "const": "en",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disclaimer Lang Canonical"
          },
          "disclaimer_translations": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disclaimer Translations"
          },
          "fallback_used": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fallback Used"
          },
          "freshness_ts": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Freshness Ts"
          },
          "has_next": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Has Next"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Dev Dataset"
          },
          "licensed_for_commercial_use": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Licensed For Commercial Use"
          },
          "locale": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Locale"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Methodology Version"
          },
          "price_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Type"
          },
          "source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source"
          },
          "total": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Total"
          },
          "upstream": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Upstream"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version"
        ],
        "title": "ApiMeta",
        "type": "object"
      },
      "ApiResponse_AiAnalysisBlock_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/AiAnalysisBlock"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[AiAnalysisBlock]",
        "type": "object"
      },
      "ApiResponse_AssetCard_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/AssetCard"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[AssetCard]",
        "type": "object"
      },
      "ApiResponse_CommodityInstrument_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/CommodityInstrument"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[CommodityInstrument]",
        "type": "object"
      },
      "ApiResponse_DimAssetRead_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/DimAssetRead"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[DimAssetRead]",
        "type": "object"
      },
      "ApiResponse_ETFAIAnalysis_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/ETFAIAnalysis"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[ETFAIAnalysis]",
        "type": "object"
      },
      "ApiResponse_FundamentalsResponse_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/FundamentalsResponse"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[FundamentalsResponse]",
        "type": "object"
      },
      "ApiResponse_InstrumentEtf_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/InstrumentEtf"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[InstrumentEtf]",
        "type": "object"
      },
      "ApiResponse_InstrumentStock_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/InstrumentStock"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[InstrumentStock]",
        "type": "object"
      },
      "ApiResponse_NewsletterIssuePreview_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/NewsletterIssuePreview"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[NewsletterIssuePreview]",
        "type": "object"
      },
      "ApiResponse_NewsletterSendResponse_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/NewsletterSendResponse"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[NewsletterSendResponse]",
        "type": "object"
      },
      "ApiResponse_OhlcvResponse_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/api__schemas__ohlcv__OhlcvResponse"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[OhlcvResponse]",
        "type": "object"
      },
      "ApiResponse_OnchainMetricsResponse_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/OnchainMetricsResponse"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[OnchainMetricsResponse]",
        "type": "object"
      },
      "ApiResponse_StockAIAnalysis_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/StockAIAnalysis"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[StockAIAnalysis]",
        "type": "object"
      },
      "ApiResponse_StockFundamentals_": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "$ref": "#/components/schemas/StockFundamentals"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[StockFundamentals]",
        "type": "object"
      },
      "ApiResponse_list_AssetCard__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/AssetCard"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[AssetCard]]",
        "type": "object"
      },
      "ApiResponse_list_CorporateAction__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/CorporateAction"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[CorporateAction]]",
        "type": "object"
      },
      "ApiResponse_list_DimAnalysisTypeRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/DimAnalysisTypeRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[DimAnalysisTypeRead]]",
        "type": "object"
      },
      "ApiResponse_list_DimAssetRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/DimAssetRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[DimAssetRead]]",
        "type": "object"
      },
      "ApiResponse_list_DimChainRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/DimChainRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[DimChainRead]]",
        "type": "object"
      },
      "ApiResponse_list_DimDateRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/DimDateRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[DimDateRead]]",
        "type": "object"
      },
      "ApiResponse_list_DimEventTypeRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/DimEventTypeRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[DimEventTypeRead]]",
        "type": "object"
      },
      "ApiResponse_list_DimNewsSourceRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/DimNewsSourceRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[DimNewsSourceRead]]",
        "type": "object"
      },
      "ApiResponse_list_DimTierRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/DimTierRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[DimTierRead]]",
        "type": "object"
      },
      "ApiResponse_list_Dividend__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/Dividend"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[Dividend]]",
        "type": "object"
      },
      "ApiResponse_list_FactAiAnalysisRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/FactAiAnalysisRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[FactAiAnalysisRead]]",
        "type": "object"
      },
      "ApiResponse_list_FactAssetFundamentalsRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/FactAssetFundamentalsRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[FactAssetFundamentalsRead]]",
        "type": "object"
      },
      "ApiResponse_list_FactEventRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/FactEventRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[FactEventRead]]",
        "type": "object"
      },
      "ApiResponse_list_FactMarketSnapshotRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/FactMarketSnapshotRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[FactMarketSnapshotRead]]",
        "type": "object"
      },
      "ApiResponse_list_FactNewsMentionRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/FactNewsMentionRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[FactNewsMentionRead]]",
        "type": "object"
      },
      "ApiResponse_list_FactOnchainAdvancedRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/FactOnchainAdvancedRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[FactOnchainAdvancedRead]]",
        "type": "object"
      },
      "ApiResponse_list_FactOnchainCoreRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/FactOnchainCoreRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[FactOnchainCoreRead]]",
        "type": "object"
      },
      "ApiResponse_list_FactProtocolEconomicsRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/FactProtocolEconomicsRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[FactProtocolEconomicsRead]]",
        "type": "object"
      },
      "ApiResponse_list_FactProtocolTvlRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/FactProtocolTvlRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[FactProtocolTvlRead]]",
        "type": "object"
      },
      "ApiResponse_list_FactVwapConsensusRead__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/FactVwapConsensusRead"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[FactVwapConsensusRead]]",
        "type": "object"
      },
      "ApiResponse_list_InstrumentEtfList__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/InstrumentEtfList"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[InstrumentEtfList]]",
        "type": "object"
      },
      "ApiResponse_list_InstrumentStock__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/InstrumentStock"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[InstrumentStock]]",
        "type": "object"
      },
      "ApiResponse_list_SqlCredentialsListItem__": {
        "properties": {
          "_meta": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "COMITE-025 \u00a73 D3 freshness transparency block. Keys: data_freshness_seconds, last_updated_at, next_refresh_at, sources, freshness_status. None when endpoint not yet instrumented (backward-compatible).",
            "title": "Meta"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/SqlCredentialsListItem"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ApiResponse[list[SqlCredentialsListItem]]",
        "type": "object"
      },
      "AssetCard": {
        "description": "M0 asset card \u2014 public payload from api_views.assets_market.\n\nBreaking change (P3 D3-F8, 2026-05-21):\n  - asset_id: int (was absent; was coingecko_id str in legacy queries \u2014 D-063)\n  - coingecko_id: REMOVED (CoinGecko ToS \u00a76.2 \u2014 never expose, D-063 + \u00a79quinquies.9.4)\n  - price_usd renamed to price_consensus_usd (derived VWAP, not CoinGecko nominal)\n  - market_cap_usd renamed to market_cap_derived_usd (VWAP x on-chain supply)\n  - change_24h_pct: REMOVED (CoinGecko nominal field, forbidden in derived layer)\n\nLEGAL-001 transparency fields (added with VWAP consensus view migration):\n  - price_source: 'consensus_vwap' | 'none'\n  - source_count: number of exchanges contributing to the consensus\n  - consensus_status: 'ok' | 'insufficient_sources'\n  - methodology_version: e.g. 'vwap-consensus-v1.1'",
        "properties": {
          "asset_id": {
            "title": "Asset Id",
            "type": "integer"
          },
          "consensus_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Consensus Status"
          },
          "last_updated": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Updated"
          },
          "market_cap_derived_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Market Cap Derived Usd"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Methodology Version"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "price_consensus_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Consensus Usd"
          },
          "price_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Source"
          },
          "source_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source Count"
          },
          "ticker": {
            "title": "Ticker",
            "type": "string"
          },
          "tier": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tier"
          }
        },
        "required": [
          "asset_id",
          "ticker",
          "name"
        ],
        "title": "AssetCard",
        "type": "object"
      },
      "AssetChangeSummary": {
        "description": "One entry in the cross-asset changes feed.\n\nSummarises what changed for one asset in a given analysis cycle.\nRaw text is never exposed \u2014 only metadata about the change.",
        "properties": {
          "analysis_type": {
            "description": "Analysis type that changed.",
            "title": "Analysis Type",
            "type": "string"
          },
          "asset_id": {
            "description": "Asset identifier.",
            "title": "Asset Id",
            "type": "string"
          },
          "change_type": {
            "description": "Dominant change type for this asset.",
            "enum": [
              "DATA_REFRESH",
              "MODEL_UPGRADE",
              "METHODOLOGY_CHANGE",
              "RESTATEMENT"
            ],
            "title": "Change Type",
            "type": "string"
          },
          "changed_at": {
            "description": "UTC timestamp of the newer snapshot (= to_snapshot.generated_at).",
            "format": "date-time",
            "title": "Changed At",
            "type": "string"
          },
          "cosine_similarity": {
            "anyOf": [
              {
                "maximum": 1.0,
                "minimum": 0.0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Text similarity score if summary changed. Null if text_changed is False.",
            "title": "Cosine Similarity"
          },
          "from_snapshot_id": {
            "description": "UUID of the earlier snapshot.",
            "title": "From Snapshot Id",
            "type": "string"
          },
          "major_text_shift": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True if cosine_similarity < 0.7. Null if no text change.",
            "title": "Major Text Shift"
          },
          "ticker": {
            "description": "Canonical ticker symbol.",
            "title": "Ticker",
            "type": "string"
          },
          "to_snapshot_id": {
            "description": "UUID of the later snapshot.",
            "title": "To Snapshot Id",
            "type": "string"
          }
        },
        "required": [
          "asset_id",
          "ticker",
          "analysis_type",
          "change_type",
          "from_snapshot_id",
          "to_snapshot_id",
          "changed_at"
        ],
        "title": "AssetChangeSummary",
        "type": "object"
      },
      "AssetRef": {
        "description": "Compact asset reference embedded in correlation response.",
        "properties": {
          "asset_id": {
            "title": "Asset Id",
            "type": "integer"
          },
          "asset_kind": {
            "title": "Asset Kind",
            "type": "string"
          },
          "ticker": {
            "title": "Ticker",
            "type": "string"
          }
        },
        "required": [
          "asset_id",
          "ticker",
          "asset_kind"
        ],
        "title": "AssetRef",
        "type": "object"
      },
      "AuthResponse": {
        "description": "Response for POST /auth/login.",
        "properties": {
          "access_token": {
            "title": "Access Token",
            "type": "string"
          },
          "expires_in": {
            "title": "Expires In",
            "type": "integer"
          },
          "token_type": {
            "default": "bearer",
            "title": "Token Type",
            "type": "string"
          },
          "user": {
            "$ref": "#/components/schemas/UserProfile"
          }
        },
        "required": [
          "access_token",
          "expires_in",
          "user"
        ],
        "title": "AuthResponse",
        "type": "object"
      },
      "BISCountriesResponse": {
        "description": "Response for GET /v1/macro/bis/countries.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/BISCountryEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "BISCountriesResponse",
        "type": "object"
      },
      "BISCountryEntry": {
        "description": "A single country entry in the countries catalogue.",
        "properties": {
          "code": {
            "title": "Code",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "series_keys": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Pre-computed series keys per dataset. Key=dataset_code, value=series_key.",
            "title": "Series Keys",
            "type": "object"
          }
        },
        "required": [
          "code",
          "name",
          "series_keys"
        ],
        "title": "BISCountryEntry",
        "type": "object"
      },
      "BISDatasetEntry": {
        "description": "A single dataset entry in the datasets catalogue.",
        "properties": {
          "code": {
            "title": "Code",
            "type": "string"
          },
          "description": {
            "title": "Description",
            "type": "string"
          },
          "frequency": {
            "title": "Frequency",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "series_key_pattern": {
            "title": "Series Key Pattern",
            "type": "string"
          },
          "unit": {
            "title": "Unit",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "frequency",
          "unit",
          "description",
          "series_key_pattern"
        ],
        "title": "BISDatasetEntry",
        "type": "object"
      },
      "BISDatasetMeta": {
        "description": "Dataset metadata embedded in response.",
        "properties": {
          "code": {
            "description": "BIS internal dataset code (BIS_CBS, BIS_LBS, etc.).",
            "title": "Code",
            "type": "string"
          },
          "frequency": {
            "description": "Data release frequency: quarterly or annual.",
            "title": "Frequency",
            "type": "string"
          },
          "name": {
            "description": "Human-readable dataset name.",
            "title": "Name",
            "type": "string"
          },
          "series_key_pattern": {
            "description": "Series key pattern for this dataset. Replace {CC} with country ISO2.",
            "title": "Series Key Pattern",
            "type": "string"
          },
          "unit": {
            "description": "Default unit of measurement.",
            "title": "Unit",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "frequency",
          "unit",
          "series_key_pattern"
        ],
        "title": "BISDatasetMeta",
        "type": "object"
      },
      "BISDatasetsResponse": {
        "description": "Response for GET /v1/macro/bis/datasets.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/BISDatasetEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "BISDatasetsResponse",
        "type": "object"
      },
      "BISObservation": {
        "description": "A single BIS observation.",
        "properties": {
          "period": {
            "description": "Observation period. Format depends on dataset frequency: '2025-Q1' (quarterly), '2024' (annual).",
            "title": "Period",
            "type": "string"
          },
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unit of measurement: 'USD_B' (USD billions), '%_GDP', 'INDEX_2020=100' (REER/NEER index).",
            "title": "Unit"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Observation value. Null if not published for this series/period.",
            "title": "Value"
          }
        },
        "required": [
          "period"
        ],
        "title": "BISObservation",
        "type": "object"
      },
      "BISSeriesMeta": {
        "description": "Response metadata for a dataset/series_key query.",
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "country_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO2 country code inferred from series_key (if identifiable).",
            "title": "Country Code"
          },
          "country_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Country name inferred from series_key (if identifiable).",
            "title": "Country Name"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "dataset": {
            "$ref": "#/components/schemas/BISDatasetMeta"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End period filter applied (inclusive).",
            "title": "End Period"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live BIS Stats API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of observations in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "series_key": {
            "description": "BIS SDMX series key used in this query.",
            "title": "Series Key",
            "type": "string"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start period filter applied (inclusive).",
            "title": "Start Period"
          },
          "total": {
            "description": "Total observations matching the query.",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "dataset",
          "series_key",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_period",
          "end_period",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "BISSeriesMeta",
        "type": "object"
      },
      "BISSeriesResponse": {
        "description": "Response for GET /v1/macro/bis/{dataset_code}/{series_key}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/BISObservation"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/BISSeriesMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "BISSeriesResponse",
        "type": "object"
      },
      "BatchScreenMeta": {
        "properties": {
          "attribution": {
            "default": "Sanctions data sourced from OpenSanctions (opensanctions.org), licensed under CC-BY 4.0.",
            "title": "Attribution",
            "type": "string"
          },
          "disclaimer": {
            "default": "Sanctions data is provided for informational purposes only. It is NOT a substitute for licensed compliance services. PortfolIQ is not a licensed compliance vendor. Users must perform their own KYC/AML due diligence for regulated activities.",
            "title": "Disclaimer",
            "type": "string"
          },
          "fetched_at": {
            "description": "ISO 8601 timestamp of this API response",
            "title": "Fetched At",
            "type": "string"
          },
          "invalid_lei_count": {
            "title": "Invalid Lei Count",
            "type": "integer"
          },
          "license": {
            "default": "CC-BY 4.0",
            "title": "License",
            "type": "string"
          },
          "lists_covered": {
            "items": {
              "type": "string"
            },
            "title": "Lists Covered",
            "type": "array"
          },
          "not_screened_count": {
            "title": "Not Screened Count",
            "type": "integer"
          },
          "screened_count": {
            "title": "Screened Count",
            "type": "integer"
          },
          "source": {
            "default": "OpenSanctions",
            "title": "Source",
            "type": "string"
          },
          "total_requested": {
            "title": "Total Requested",
            "type": "integer"
          }
        },
        "required": [
          "fetched_at",
          "total_requested",
          "screened_count",
          "not_screened_count",
          "invalid_lei_count"
        ],
        "title": "BatchScreenMeta",
        "type": "object"
      },
      "BatchScreenRequest": {
        "properties": {
          "leis": {
            "description": "List of LEI codes to screen (max 50).",
            "examples": [
              [
                "HWUPKR0MPOU8FGXBT394",
                "INR2EJN1ERAN0W5ZP974"
              ]
            ],
            "items": {
              "type": "string"
            },
            "maxItems": 50,
            "minItems": 1,
            "title": "Leis",
            "type": "array"
          }
        },
        "required": [
          "leis"
        ],
        "title": "BatchScreenRequest",
        "type": "object"
      },
      "BatchScreenResponse": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/BatchScreenResult"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/BatchScreenMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "BatchScreenResponse",
        "type": "object"
      },
      "BatchScreenResult": {
        "properties": {
          "checked_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Timestamp of the cached screening. Null when status='not_screened'.",
            "title": "Checked At"
          },
          "is_sanctioned": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Null when status='not_screened' (entity not in cache).",
            "title": "Is Sanctioned"
          },
          "last_listed_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Listed Date"
          },
          "legal_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Legal Name"
          },
          "lei": {
            "title": "Lei",
            "type": "string"
          },
          "opensanctions_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Opensanctions Id"
          },
          "risk_score": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Risk Score"
          },
          "sanction_programs": {
            "items": {
              "type": "string"
            },
            "title": "Sanction Programs",
            "type": "array"
          },
          "sanctions_lists": {
            "items": {
              "type": "string"
            },
            "title": "Sanctions Lists",
            "type": "array"
          },
          "status": {
            "description": "'screened' \u2014 entity found in cache. 'not_screened' \u2014 entity not in cache (run seed script). 'invalid_lei' \u2014 LEI format invalid.",
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "lei",
          "status"
        ],
        "title": "BatchScreenResult",
        "type": "object"
      },
      "BojCatalogueEntry": {
        "description": "A single entry in the BoJ series catalogue.",
        "properties": {
          "description": {
            "title": "Description",
            "type": "string"
          },
          "frequency": {
            "title": "Frequency",
            "type": "string"
          },
          "series_id": {
            "title": "Series Id",
            "type": "string"
          },
          "unit": {
            "title": "Unit",
            "type": "string"
          }
        },
        "required": [
          "series_id",
          "description",
          "frequency",
          "unit"
        ],
        "title": "BojCatalogueEntry",
        "type": "object"
      },
      "BojCatalogueResponse": {
        "description": "Response for GET /v1/macro/japan/series.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/BojCatalogueEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "BojCatalogueResponse",
        "type": "object"
      },
      "BojObservation": {
        "description": "A single BoJ time-series observation.",
        "properties": {
          "frequency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Data frequency: daily | monthly | quarterly.",
            "title": "Frequency"
          },
          "observation_date": {
            "description": "Date of observation.",
            "format": "date",
            "title": "Observation Date",
            "type": "string"
          },
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unit of measurement.",
            "title": "Unit"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Observation value. Null if unreleased or not available.",
            "title": "Value"
          }
        },
        "required": [
          "observation_date"
        ],
        "title": "BojObservation",
        "type": "object"
      },
      "BojSeriesMeta": {
        "description": "Response metadata for a BoJ series query.",
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End date filter applied.",
            "title": "End Date"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live BoJ API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of observations in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "series_description": {
            "description": "Human-readable series description.",
            "title": "Series Description",
            "type": "string"
          },
          "series_id": {
            "description": "Logical series identifier (BOJ_*).",
            "title": "Series Id",
            "type": "string"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start date filter applied.",
            "title": "Start Date"
          },
          "total": {
            "description": "Total observations matching the query.",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "series_id",
          "series_description",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_date",
          "end_date",
          "computed_at",
          "disclaimer",
          "disclaimer_fr",
          "source",
          "license"
        ],
        "title": "BojSeriesMeta",
        "type": "object"
      },
      "BojSeriesResponse": {
        "description": "Response for GET /v1/macro/japan/{series_id}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/BojObservation"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/BojSeriesMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "BojSeriesResponse",
        "type": "object"
      },
      "BokCatalogueEntry": {
        "description": "A single entry in the BoK series catalogue.",
        "properties": {
          "description": {
            "title": "Description",
            "type": "string"
          },
          "frequency": {
            "title": "Frequency",
            "type": "string"
          },
          "series_id": {
            "title": "Series Id",
            "type": "string"
          },
          "unit": {
            "title": "Unit",
            "type": "string"
          }
        },
        "required": [
          "series_id",
          "description",
          "frequency",
          "unit"
        ],
        "title": "BokCatalogueEntry",
        "type": "object"
      },
      "BokCatalogueResponse": {
        "description": "Response for GET /v1/macro/kr/series.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/BokCatalogueEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "BokCatalogueResponse",
        "type": "object"
      },
      "BokObservation": {
        "description": "A single BoK macro time-series observation.",
        "properties": {
          "observation_date": {
            "description": "Date of observation.",
            "format": "date",
            "title": "Observation Date",
            "type": "string"
          },
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unit of measurement.",
            "title": "Unit"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Observation value. Null if unreleased or not available.",
            "title": "Value"
          }
        },
        "required": [
          "observation_date"
        ],
        "title": "BokObservation",
        "type": "object"
      },
      "BokSeriesMeta": {
        "description": "Response metadata for a BoK series query.",
        "properties": {
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "description": {
            "description": "Human-readable series description.",
            "title": "Description",
            "type": "string"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End date filter applied.",
            "title": "End Date"
          },
          "fetched_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Fetched At",
            "type": "string"
          },
          "frequency": {
            "description": "Data frequency: daily | monthly | quarterly.",
            "title": "Frequency",
            "type": "string"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live BoK ECOS API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of observations in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "series_id": {
            "description": "Logical series identifier (BOK_*).",
            "title": "Series Id",
            "type": "string"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start date filter applied.",
            "title": "Start Date"
          },
          "total": {
            "description": "Total observations matching the query.",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "series_id",
          "description",
          "frequency",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_date",
          "end_date",
          "fetched_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "BokSeriesMeta",
        "type": "object"
      },
      "BokSeriesResponse": {
        "description": "Response for GET /v1/macro/kr/{series_id}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/BokObservation"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/BokSeriesMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "BokSeriesResponse",
        "type": "object"
      },
      "BtcCycleResponse": {
        "description": "Response payload for GET /v1/analytics/btc-cycle.",
        "properties": {
          "current_block_height": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Current BTC block height (None if unavailable).",
            "title": "Current Block Height"
          },
          "cycle_position_label": {
            "enum": [
              "early_post_halving",
              "mid_cycle",
              "late_cycle_euphoria",
              "post_peak_drawdown"
            ],
            "title": "Cycle Position Label",
            "type": "string"
          },
          "cycle_progress_pct": {
            "description": "% of cycle elapsed (days basis).",
            "maximum": 100.0,
            "minimum": 0.0,
            "title": "Cycle Progress Pct",
            "type": "number"
          },
          "days_since_last_halving": {
            "title": "Days Since Last Halving",
            "type": "integer"
          },
          "days_until_next_halving": {
            "title": "Days Until Next Halving",
            "type": "integer"
          },
          "historical_pattern_note": {
            "description": "Reference to prior 3 halvings \u2014 purely descriptive.",
            "title": "Historical Pattern Note",
            "type": "string"
          },
          "last_halving_block": {
            "description": "Block at last halving.",
            "title": "Last Halving Block",
            "type": "integer"
          },
          "last_halving_date": {
            "description": "Date of the most recent halving.",
            "format": "date",
            "title": "Last Halving Date",
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          },
          "methodology_version": {
            "default": "btc-cycle-v1.0",
            "title": "Methodology Version",
            "type": "string"
          },
          "next_halving_block": {
            "title": "Next Halving Block",
            "type": "integer"
          },
          "next_halving_estimate": {
            "description": "Estimated next halving (block 210000 from previous).",
            "format": "date",
            "title": "Next Halving Estimate",
            "type": "string"
          }
        },
        "required": [
          "last_halving_date",
          "last_halving_block",
          "next_halving_estimate",
          "next_halving_block",
          "days_since_last_halving",
          "days_until_next_halving",
          "cycle_progress_pct",
          "cycle_position_label",
          "historical_pattern_note",
          "meta"
        ],
        "title": "BtcCycleResponse",
        "type": "object"
      },
      "BulkHistoryRequest": {
        "description": "Request body for POST /v1/ai-analysis/bulk-history.\n\nsymbols: 1-50 asset identifiers (e.g. 'bitcoin', 'ethereum').\ntype:    Analysis type \u2014 must match existing analysis_type values in DB.\nfrom_:   Start of the date window (ISO 8601, aliased as 'from' in JSON).\nto:      End of the date window (ISO 8601).",
        "properties": {
          "from": {
            "description": "Start datetime of the history window (ISO 8601, UTC).",
            "format": "date-time",
            "title": "From",
            "type": "string"
          },
          "symbols": {
            "description": "List of asset identifiers. Min 1, max 50.",
            "items": {
              "type": "string"
            },
            "maxItems": 50,
            "minItems": 1,
            "title": "Symbols",
            "type": "array"
          },
          "to": {
            "description": "End datetime of the history window (ISO 8601, UTC).",
            "format": "date-time",
            "title": "To",
            "type": "string"
          },
          "type": {
            "description": "Analysis type (market_context | halal_analysis | regime).",
            "title": "Type",
            "type": "string"
          }
        },
        "required": [
          "symbols",
          "type",
          "from",
          "to"
        ],
        "title": "BulkHistoryRequest",
        "type": "object"
      },
      "CatalogueEntry": {
        "description": "One entry in the curated address catalogue.",
        "properties": {
          "address": {
            "title": "Address",
            "type": "string"
          },
          "chain_id": {
            "title": "Chain Id",
            "type": "integer"
          },
          "chain_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Chain Name"
          },
          "has_data": {
            "description": "True if the DB has at least one snapshot for this entry.",
            "title": "Has Data",
            "type": "boolean"
          },
          "is_contract": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Contract"
          },
          "label": {
            "title": "Label",
            "type": "string"
          },
          "native_balance": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Native Balance"
          },
          "snapshot_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Date of the most recent DB snapshot. Null if not seeded.",
            "title": "Snapshot Date"
          }
        },
        "required": [
          "chain_id",
          "chain_name",
          "address",
          "label",
          "has_data",
          "snapshot_date"
        ],
        "title": "CatalogueEntry",
        "type": "object"
      },
      "CatalogueMeta": {
        "description": "Metadata for GET /v1/onchain/addresses.",
        "properties": {
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Data Quality"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "fetched_at": {
            "title": "Fetched At",
            "type": "string"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Dev Dataset"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "total",
          "fetched_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "CatalogueMeta",
        "type": "object"
      },
      "CatalogueResponse": {
        "description": "Response for GET /v1/onchain/addresses.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/CatalogueEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/CatalogueMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "CatalogueResponse",
        "type": "object"
      },
      "CatalystItem": {
        "description": "A single catalyst entry in the Top 10 list.",
        "properties": {
          "catalyst_type": {
            "description": "Catalyst category (e.g. halving, earnings, macro_shift, regulatory).",
            "title": "Catalyst Type",
            "type": "string"
          },
          "confidence": {
            "description": "AI confidence score in [0, 1].",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Confidence",
            "type": "number"
          },
          "name": {
            "description": "Human-readable asset name.",
            "title": "Name",
            "type": "string"
          },
          "narrative_snippet": {
            "description": "Short narrative excerpt (max ~280 chars) from the AI analysis.",
            "title": "Narrative Snippet",
            "type": "string"
          },
          "ticker": {
            "description": "Asset ticker symbol (e.g. BTC, ETH, AAPL).",
            "title": "Ticker",
            "type": "string"
          }
        },
        "required": [
          "ticker",
          "name",
          "catalyst_type",
          "confidence",
          "narrative_snippet"
        ],
        "title": "CatalystItem",
        "type": "object"
      },
      "CheckoutRequest": {
        "description": "Body for POST /billing/checkout.",
        "properties": {
          "tier": {
            "title": "Tier",
            "type": "string"
          }
        },
        "required": [
          "tier"
        ],
        "title": "CheckoutRequest",
        "type": "object"
      },
      "CheckoutResponse": {
        "description": "Successful checkout session response.",
        "properties": {
          "checkout_url": {
            "title": "Checkout Url",
            "type": "string"
          }
        },
        "required": [
          "checkout_url"
        ],
        "title": "CheckoutResponse",
        "type": "object"
      },
      "CheckoutUnavailableResponse": {
        "description": "Response when Stripe keys are not configured.",
        "properties": {
          "message": {
            "title": "Message",
            "type": "string"
          },
          "status": {
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "status",
          "message"
        ],
        "title": "CheckoutUnavailableResponse",
        "type": "object"
      },
      "CommodityInstrument": {
        "description": "Commodity instrument response schema \u2014 T-454.\n\nExposes the 3 HS-blocking fields (mig 066) as raw factual data.\nPIQ never makes a fiqh verdict \u2014 HalalStack consumes these fields.",
        "properties": {
          "asset_kind": {
            "const": "commodity",
            "title": "Asset Kind",
            "type": "string"
          },
          "category": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Category"
          },
          "contract_unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contract Unit"
          },
          "delivery_location": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Delivery Location"
          },
          "instrument_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Instrument Type"
          },
          "is_physically_backed": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Physically Backed"
          },
          "last_price": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Price"
          },
          "last_updated": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Updated"
          },
          "metal_storage_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metal Storage Type"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "price_ts": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Ts"
          },
          "primary_exchange": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Primary Exchange"
          },
          "quote_currency": {
            "default": "USD",
            "title": "Quote Currency",
            "type": "string"
          },
          "symbol": {
            "title": "Symbol",
            "type": "string"
          }
        },
        "required": [
          "symbol",
          "name",
          "asset_kind"
        ],
        "title": "CommodityInstrument",
        "type": "object"
      },
      "CommodityPriceMeta": {
        "properties": {
          "cache_hit": {
            "default": false,
            "title": "Cache Hit",
            "type": "boolean"
          },
          "data_methodology": {
            "title": "Data Methodology",
            "type": "string"
          },
          "data_quality": {
            "default": "full",
            "title": "Data Quality",
            "type": "string"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "licensed_for_commercial_use": {
            "title": "Licensed For Commercial Use",
            "type": "boolean"
          },
          "source_attribution": {
            "title": "Source Attribution",
            "type": "string"
          }
        },
        "required": [
          "data_methodology",
          "licensed_for_commercial_use",
          "source_attribution",
          "disclaimer"
        ],
        "title": "CommodityPriceMeta",
        "type": "object"
      },
      "CommodityPriceResponse": {
        "properties": {
          "data": {
            "additionalProperties": true,
            "title": "Data",
            "type": "object"
          },
          "meta": {
            "$ref": "#/components/schemas/CommodityPriceMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "CommodityPriceResponse",
        "type": "object"
      },
      "CompaniesHouseData": {
        "properties": {
          "annual_filings_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "URL to official Companies House filing history page. Pattern: https://find-and-update.company-information.service.gov.uk/company/{number}/filing-history",
            "title": "Annual Filings Url"
          },
          "company_name": {
            "description": "Official company name as registered at Companies House",
            "title": "Company Name",
            "type": "string"
          },
          "company_number": {
            "description": "Companies House company number. Standard: 8 numeric digits zero-padded. Scottish: SC prefix. NI: NI prefix. Example: 02723534 for AstraZeneca.",
            "title": "Company Number",
            "type": "string"
          },
          "company_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Companies House company status. Values: active, liquidation, dissolved, administration, receivership, converted-closed, voluntary-arrangement.",
            "title": "Company Status"
          },
          "company_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Companies House company type. Examples: plc, ltd, llp, private-limited-guarant-nsc, old-public-company.",
            "title": "Company Type"
          },
          "date_of_creation": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Date of company registration (ISO 8601 date)",
            "title": "Date Of Creation"
          },
          "listing_venue": {
            "default": "XLON",
            "description": "Listing venue",
            "title": "Listing Venue",
            "type": "string"
          },
          "registered_office_address": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "Registered office address as JSONB object. Keys: address_line_1, address_line_2, locality, region, postal_code, country.",
            "title": "Registered Office Address"
          },
          "sic_codes": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "UK Standard Industrial Classification (SIC) codes. Example: ['72190'] for AstraZeneca (R&D on natural sciences).",
            "title": "Sic Codes"
          },
          "ticker": {
            "description": "Asset ticker (XLON)",
            "title": "Ticker",
            "type": "string"
          }
        },
        "required": [
          "ticker",
          "company_number",
          "company_name"
        ],
        "title": "CompaniesHouseData",
        "type": "object"
      },
      "CompaniesHouseMeta": {
        "properties": {
          "attribution": {
            "default": "Contains public sector information licensed under the Open Government Licence v3.0. https://www.nationalarchives.gov.uk/doc/open-government-licence/",
            "title": "Attribution",
            "type": "string"
          },
          "fetched_at": {
            "description": "ISO 8601 timestamp of this response",
            "title": "Fetched At",
            "type": "string"
          },
          "license": {
            "default": "Open Government Licence v3.0",
            "title": "License",
            "type": "string"
          },
          "record_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Seed record source identifier. e.g. 'companies_house_uk_2026-05-26' or 'curated_wikipedia_2026-05-26'",
            "title": "Record Source"
          },
          "served_from": {
            "default": "db_cache",
            "title": "Served From",
            "type": "string"
          },
          "source": {
            "default": "Companies House UK",
            "title": "Source",
            "type": "string"
          }
        },
        "required": [
          "fetched_at"
        ],
        "title": "CompaniesHouseMeta",
        "type": "object"
      },
      "CompaniesHouseResponse": {
        "properties": {
          "data": {
            "$ref": "#/components/schemas/CompaniesHouseData"
          },
          "meta": {
            "$ref": "#/components/schemas/CompaniesHouseMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "CompaniesHouseResponse",
        "type": "object"
      },
      "CompareAssetResult": {
        "description": "Per-asset comparison result.",
        "properties": {
          "asset": {
            "description": "Asset identifier as provided in query.",
            "title": "Asset",
            "type": "string"
          },
          "cagr_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Compound annual growth rate %.",
            "title": "Cagr Pct"
          },
          "data_quality": {
            "enum": [
              "full",
              "partial",
              "missing"
            ],
            "title": "Data Quality",
            "type": "string"
          },
          "end_date": {
            "format": "date",
            "title": "End Date",
            "type": "string"
          },
          "end_price": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Price at end_date (or latest available).",
            "title": "End Price"
          },
          "final_value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Final portfolio value if budget invested at start.",
            "title": "Final Value"
          },
          "note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional explanation (e.g. 'limited history').",
            "title": "Note"
          },
          "pnl_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total return %.",
            "title": "Pnl Pct"
          },
          "start_date": {
            "format": "date",
            "title": "Start Date",
            "type": "string"
          },
          "start_price": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Price at start_date.",
            "title": "Start Price"
          }
        },
        "required": [
          "asset",
          "start_price",
          "end_price",
          "start_date",
          "end_date",
          "final_value",
          "pnl_pct",
          "cagr_pct",
          "data_quality"
        ],
        "title": "CompareAssetResult",
        "type": "object"
      },
      "CompareResponse": {
        "description": "Response payload for GET /v1/analytics/compare.",
        "properties": {
          "best_performer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Best Performer"
          },
          "budget": {
            "description": "Hypothetical investment budget (currency-agnostic).",
            "exclusiveMinimum": 0.0,
            "title": "Budget",
            "type": "number"
          },
          "end_date": {
            "format": "date",
            "title": "End Date",
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          },
          "methodology_version": {
            "default": "compare-v1.0",
            "title": "Methodology Version",
            "type": "string"
          },
          "results": {
            "items": {
              "$ref": "#/components/schemas/CompareAssetResult"
            },
            "title": "Results",
            "type": "array"
          },
          "start_date": {
            "format": "date",
            "title": "Start Date",
            "type": "string"
          },
          "worst_performer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Worst Performer"
          }
        },
        "required": [
          "budget",
          "start_date",
          "end_date",
          "results",
          "best_performer",
          "worst_performer",
          "meta"
        ],
        "title": "CompareResponse",
        "type": "object"
      },
      "ConstituentItem": {
        "description": "A single index constituent row.",
        "properties": {
          "asset_hk": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Asset Hk"
          },
          "constituent_name": {
            "title": "Constituent Name",
            "type": "string"
          },
          "constituent_ticker": {
            "title": "Constituent Ticker",
            "type": "string"
          },
          "data_source": {
            "title": "Data Source",
            "type": "string"
          },
          "matched_in_hub": {
            "title": "Matched In Hub",
            "type": "boolean"
          },
          "snapshot_date": {
            "format": "date",
            "title": "Snapshot Date",
            "type": "string"
          },
          "wikidata_qid": {
            "title": "Wikidata Qid",
            "type": "string"
          }
        },
        "required": [
          "constituent_ticker",
          "constituent_name",
          "wikidata_qid",
          "matched_in_hub",
          "snapshot_date",
          "data_source"
        ],
        "title": "ConstituentItem",
        "type": "object"
      },
      "ContractCapability": {
        "description": "HS-facing capability entry \u2014 mirrors CONTRACT-HS-PIQ \u00a72 columns.\n\nKeyed by DAT-NNN identifiers (e.g. 'DAT-001').\nUsed by HS cron contract-check (5 min) to detect drift vs CONTRACT-HS-PIQ.md.\nCOMITE-021 / MESSAGES-HS-TO-PIQ.md Message 2 Q2.",
        "properties": {
          "api_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Api Version"
          },
          "endpoint": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Endpoint"
          },
          "eta": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Eta"
          },
          "notes": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Notes"
          },
          "status": {
            "enum": [
              "planned",
              "wip",
              "staging",
              "ga",
              "deprecated"
            ],
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "status"
        ],
        "title": "ContractCapability",
        "type": "object"
      },
      "CorporateAction": {
        "description": "Single corporate action record returned by GET /v1/stocks/{ticker}/corporate-actions.",
        "properties": {
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "effective_date": {
            "title": "Effective Date",
            "type": "string"
          },
          "event_type": {
            "title": "Event Type",
            "type": "string"
          },
          "from_ticker": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "From Ticker"
          },
          "ratio": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ratio"
          },
          "source_filing": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source Filing"
          },
          "to_ticker": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "To Ticker"
          }
        },
        "required": [
          "effective_date",
          "event_type"
        ],
        "title": "CorporateAction",
        "type": "object"
      },
      "CorrelationMatrixCell": {
        "properties": {
          "asset_a": {
            "description": "Asset A identifier (e.g. crypto:BTC).",
            "title": "Asset A",
            "type": "string"
          },
          "asset_b": {
            "description": "Asset B identifier.",
            "title": "Asset B",
            "type": "string"
          },
          "pearson": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Pearson r. Null if not enough overlapping observations.",
            "title": "Pearson"
          },
          "sample_size": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sample Size"
          },
          "snapshot_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Snapshot Date"
          },
          "spearman": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Spearman rho. Null if not enough overlap.",
            "title": "Spearman"
          }
        },
        "required": [
          "asset_a",
          "asset_b",
          "pearson",
          "spearman",
          "sample_size",
          "snapshot_date"
        ],
        "title": "CorrelationMatrixCell",
        "type": "object"
      },
      "CorrelationMatrixResponse": {
        "description": "Response payload for GET /v1/analytics/correlations/matrix.",
        "properties": {
          "assets": {
            "description": "Echo of the requested asset list (order preserved).",
            "items": {
              "type": "string"
            },
            "title": "Assets",
            "type": "array"
          },
          "matrix": {
            "description": "Flat list of pairs (i<=j) \u2014 frontend reconstructs NxN symmetric matrix.",
            "items": {
              "$ref": "#/components/schemas/CorrelationMatrixCell"
            },
            "title": "Matrix",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          },
          "methodology_version": {
            "default": "corr-matrix-v1.0",
            "title": "Methodology Version",
            "type": "string"
          },
          "missing_pairs": {
            "description": "Number of (A,B) pairs without correlation data in PIQ store.",
            "minimum": 0.0,
            "title": "Missing Pairs",
            "type": "integer"
          },
          "period_days": {
            "title": "Period Days",
            "type": "integer"
          }
        },
        "required": [
          "assets",
          "period_days",
          "matrix",
          "missing_pairs",
          "meta"
        ],
        "title": "CorrelationMatrixResponse",
        "type": "object"
      },
      "CorrelationResponse": {
        "description": "Response payload for GET /v1/correlations.\n\nFields:\n    from_asset:           Source asset reference.\n    to_asset:             Target asset reference.\n    period_days:          Rolling window in days (30 | 90 | 252).\n    snapshot_date:        Date of the correlation snapshot.\n    correlation_pearson:  Pearson r on log returns, range [-1, 1].\n    correlation_spearman: Spearman rho on log returns, range [-1, 1].\n    sample_size:          Number of observations used. Always >= 30.\n    ai_narrative:         Optional AI explanation (T-603). Null if feature flag off.\n    methodology_version:  \"corr-v1.0\" \u2014 stable identifier for audit trail.\n    meta:                 Standard ApiMeta envelope (disclaimer, computed_at, etc.).",
        "properties": {
          "ai_narrative": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "AI-generated factual explanation (T-603). Null if ENABLE_AI_CORRELATIONS=false.",
            "title": "Ai Narrative"
          },
          "correlation_pearson": {
            "description": "Pearson correlation coefficient.",
            "maximum": 1.0,
            "minimum": -1.0,
            "title": "Correlation Pearson",
            "type": "number"
          },
          "correlation_spearman": {
            "description": "Spearman rank correlation coefficient.",
            "maximum": 1.0,
            "minimum": -1.0,
            "title": "Correlation Spearman",
            "type": "number"
          },
          "from": {
            "$ref": "#/components/schemas/AssetRef"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          },
          "methodology_version": {
            "default": "corr-v1.0",
            "description": "Stable methodology identifier for audit trail.",
            "title": "Methodology Version",
            "type": "string"
          },
          "period_days": {
            "description": "Rolling window in days.",
            "minimum": 1.0,
            "title": "Period Days",
            "type": "integer"
          },
          "sample_size": {
            "description": "Observations used. Minimum 30.",
            "minimum": 30.0,
            "title": "Sample Size",
            "type": "integer"
          },
          "snapshot_date": {
            "format": "date",
            "title": "Snapshot Date",
            "type": "string"
          },
          "to": {
            "$ref": "#/components/schemas/AssetRef"
          }
        },
        "required": [
          "from",
          "to",
          "period_days",
          "snapshot_date",
          "correlation_pearson",
          "correlation_spearman",
          "sample_size",
          "meta"
        ],
        "title": "CorrelationResponse",
        "type": "object"
      },
      "CoverageCapability": {
        "description": "Coverage status for a single API capability.",
        "properties": {
          "asset_count": {
            "default": 0,
            "title": "Asset Count",
            "type": "integer"
          },
          "enabled": {
            "title": "Enabled",
            "type": "boolean"
          },
          "last_refresh": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Refresh"
          },
          "probe_error": {
            "default": false,
            "title": "Probe Error",
            "type": "boolean"
          }
        },
        "required": [
          "enabled"
        ],
        "title": "CoverageCapability",
        "type": "object"
      },
      "CoverageFlags": {
        "description": "Boolean flags indicating which data types are available for this instrument.",
        "properties": {
          "ai_analysis": {
            "description": "AI-generated analysis snapshots available.",
            "title": "Ai Analysis",
            "type": "boolean"
          },
          "fundamentals": {
            "description": "Fundamental data (earnings, balance sheet) available.",
            "title": "Fundamentals",
            "type": "boolean"
          },
          "ohlcv": {
            "description": "Open/high/low/close/volume daily data available.",
            "title": "Ohlcv",
            "type": "boolean"
          }
        },
        "required": [
          "ohlcv",
          "fundamentals",
          "ai_analysis"
        ],
        "title": "CoverageFlags",
        "type": "object"
      },
      "CoverageItem": {
        "description": "Single instrument coverage entry.\n\ndata_sources is a list of strings (not FK-normalised in v1 \u2014 PO-approved M0 simplification).\n\nNote: halal attributes (is_halal_aaoifi, purification_ratio) are NOT exposed here.\nportfolIQ provides raw financial data; halal screening is sovereign to HalalStack.",
        "properties": {
          "asset_class": {
            "description": "Asset class identifier: 'crypto', 'stock', 'etf', 'commodity', etc.",
            "title": "Asset Class",
            "type": "string"
          },
          "coverage": {
            "$ref": "#/components/schemas/CoverageFlags",
            "description": "Available data type flags."
          },
          "data_sources": {
            "description": "List of data source identifiers, e.g. ['coingecko', 'cryptocompare'].",
            "items": {
              "type": "string"
            },
            "title": "Data Sources",
            "type": "array"
          },
          "ticker": {
            "description": "Instrument ticker / symbol, e.g. 'AAPL' or 'BTC'.",
            "title": "Ticker",
            "type": "string"
          },
          "tier": {
            "description": "Coverage tier: 'tier1', 'tier2', or 'tier3'.",
            "title": "Tier",
            "type": "string"
          }
        },
        "required": [
          "ticker",
          "asset_class",
          "tier",
          "coverage"
        ],
        "title": "CoverageItem",
        "type": "object"
      },
      "CoverageResponse": {
        "description": "Full coverage manifest response envelope.",
        "properties": {
          "generated_at": {
            "description": "UTC timestamp when this manifest was generated.",
            "format": "date-time",
            "title": "Generated At",
            "type": "string"
          },
          "items": {
            "description": "List of coverage items.",
            "items": {
              "$ref": "#/components/schemas/CoverageItem"
            },
            "title": "Items",
            "type": "array"
          },
          "meta": {
            "additionalProperties": true,
            "description": "Response metadata: disclaimer and optional pagination cursor.",
            "title": "Meta",
            "type": "object"
          },
          "total": {
            "description": "Total number of instruments matching the query.",
            "minimum": 0.0,
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "total",
          "generated_at",
          "items"
        ],
        "title": "CoverageResponse",
        "type": "object"
      },
      "CreateKeyRequest": {
        "description": "Optional body for POST /auth/keys.",
        "properties": {
          "label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Label"
          }
        },
        "title": "CreateKeyRequest",
        "type": "object"
      },
      "CryptoCatalogItem": {
        "description": "A single crypto asset entry in the catalog (VWAP consensus contract).\n\nLEGAL-001 migration:\n  - price_usd: portfolIQ VWAP consensus (\u22653 exchanges). NULL when insufficient\n    sources \u2014 coin remains listed, price=null (never 0).\n  - market_cap_usd: derived (vwap\u00d7supply). NULL when consensus absent.\n  - REMOVED: volume_24h_usd (was CoinGecko raw \u2014 dropped per ToS \u00a76.2).\n  - REMOVED: coingecko_id from public payload (CoinGecko ToS \u00a76.2 \u2014 internal\n    lookup key only, never exposed).\n  - ADDED: asset_id (portfolIQ internal stable unique integer ID \u2014 from\n    marts.dim_asset, resolved via asset_hk). Allows HalalStack and all clients\n    to key stably on a unique ID even when symbols are duplicated (TON, FRAX,\n    SAFE, VELO\u2026). Matches the asset_id returned by /v1/assets/{id}.\n    NULL if dim_asset row absent (backfill gap \u2014 transient).\n  - ADDED: price_source, source_count, consensus_status, methodology_version\n    (LEGAL-001 transparency fields).",
        "properties": {
          "asset_id": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "portfolIQ stable unique integer asset ID (from marts.dim_asset). Unique per asset \u2014 use this to key across assets, not symbol (symbols can be duplicated: TON, FRAX, SAFE\u2026). Matches asset_id returned by /v1/assets/{id}. Null if dim_asset row absent (transient backfill gap). Note: coingecko_id is NOT exposed (CoinGecko ToS \u00a76.2 \u2014 internal lookup only).",
            "title": "Asset Id"
          },
          "categories": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "Category tags. Currently null \u2014 not yet populated (DAT-008 scope).",
            "title": "Categories"
          },
          "circulating_supply": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Circulating supply in native token units.",
            "title": "Circulating Supply"
          },
          "consensus_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Consensus quality: 'ok' (\u22653 sources) | 'insufficient_sources'.",
            "title": "Consensus Status"
          },
          "market_cap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Market capitalisation in USD (VWAP\u00d7supply derived). Null when price consensus is absent or supply unavailable.",
            "title": "Market Cap Usd"
          },
          "max_supply": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Maximum supply. Currently null \u2014 not in source tables (DAT-008 scope).",
            "title": "Max Supply"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "VWAP methodology version label, e.g. 'vwap-consensus-v1.1'.",
            "title": "Methodology Version"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable coin name. Null if metadata unavailable.",
            "title": "Name"
          },
          "price_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Price source type: 'consensus_vwap' | 'none'.",
            "title": "Price Source"
          },
          "price_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "portfolIQ VWAP consensus price in USD (\u22653 exchanges). Null when consensus_status='insufficient_sources'.",
            "title": "Price Usd"
          },
          "primary_sector": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Primary sector. Currently null \u2014 not yet populated (DAT-008 scope).",
            "title": "Primary Sector"
          },
          "rank": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Market-cap rank (1-based, by market_cap_usd DESC). ROW_NUMBER() over the filtered result set \u2014 not a global persistent rank.",
            "title": "Rank"
          },
          "source_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Number of exchanges contributing to the VWAP consensus.",
            "title": "Source Count"
          },
          "staleness_hours": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Hours elapsed since updated_at (NOW() - updated_at in hours, rounded to 2 decimal places). Null when updated_at is null. Example usage (HalalStack): exclude from primary analysis if staleness_hours > 48 for micro-caps with high volatility (30-46% gap vs majors at 2-4%).",
            "title": "Staleness Hours"
          },
          "symbol": {
            "description": "Ticker symbol, e.g. 'BTC', 'ETH'.",
            "title": "Symbol",
            "type": "string"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 8601 timestamp of the last meaningful data change for this asset (GREATEST of consensus VWAP change_ts and CoinGecko metadata change_ts). Stable across dbt full-refresh (derived from business timestamps, not load_ts). Use this to gate trust: assets with staleness_hours > 48 on micro-caps may have stale price data. Null for assets with no tracked change yet.",
            "title": "Updated At"
          }
        },
        "required": [
          "symbol"
        ],
        "title": "CryptoCatalogItem",
        "type": "object"
      },
      "CryptoCatalogMeta": {
        "description": "Response metadata for GET /v1/catalog/cryptos.\n\nLEGAL-001 fields:\n  - disclaimer: VWAP consensus + CoinGecko attribution + not-financial-advice.\n  - price_type: stable label for the price methodology.\n  - methodology_version: VWAP version in use.\n  - benchmark_notice: BMR Regulation (EU) 2016/1011 informational notice.",
        "properties": {
          "benchmark_notice": {
            "description": "BMR (EU) 2016/1011 informational notice.",
            "title": "Benchmark Notice",
            "type": "string"
          },
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opaque base64 keyset cursor (high-water mark of this page). Pass as ?since= in the next request to pull incremental changes. None in full-list mode (no ?since= / ?updated_after= param).",
            "title": "Cursor"
          },
          "data_quality": {
            "description": "'fresh' \u2014 market data present for at least one asset in the response. 'empty' \u2014 no market data available (tables not yet seeded or filter too strict).",
            "enum": [
              "fresh",
              "empty"
            ],
            "title": "Data Quality",
            "type": "string"
          },
          "data_source": {
            "description": "Data source attribution string.",
            "title": "Data Source",
            "type": "string"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English). VWAP consensus + CoinGecko attribution.",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "freshness": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Freshness",
            "type": "string"
          },
          "is_dev_dataset": {
            "description": "False when data originates from live APIs.",
            "title": "Is Dev Dataset",
            "type": "boolean"
          },
          "methodology_version": {
            "description": "VWAP methodology version, e.g. 'vwap-consensus-v1.1'.",
            "title": "Methodology Version",
            "type": "string"
          },
          "price_type": {
            "description": "Price methodology label: 'portfolIQ consensus VWAP (derived)'.",
            "title": "Price Type",
            "type": "string"
          },
          "version": {
            "description": "API version (semver).",
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "data_source",
          "freshness",
          "is_dev_dataset",
          "data_quality",
          "disclaimer",
          "disclaimer_fr",
          "price_type",
          "methodology_version",
          "benchmark_notice"
        ],
        "title": "CryptoCatalogMeta",
        "type": "object"
      },
      "CryptoCatalogPagination": {
        "description": "Pagination metadata for the crypto catalog response.",
        "properties": {
          "has_more": {
            "description": "True if more results are available beyond this page.",
            "title": "Has More",
            "type": "boolean"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "offset": {
            "description": "Current pagination offset.",
            "title": "Offset",
            "type": "integer"
          },
          "total": {
            "description": "Total number of assets matching the query.",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "total",
          "offset",
          "limit",
          "has_more"
        ],
        "title": "CryptoCatalogPagination",
        "type": "object"
      },
      "CryptoCatalogResponse": {
        "description": "Response for GET /v1/catalog/cryptos.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/CryptoCatalogItem"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/CryptoCatalogMeta"
          },
          "pagination": {
            "$ref": "#/components/schemas/CryptoCatalogPagination"
          }
        },
        "required": [
          "data",
          "pagination",
          "meta"
        ],
        "title": "CryptoCatalogResponse",
        "type": "object"
      },
      "CryptoCheckoutRequest": {
        "description": "Body for POST /v1/billing/crypto/checkout.",
        "properties": {
          "period": {
            "title": "Period",
            "type": "string"
          },
          "tier": {
            "title": "Tier",
            "type": "string"
          }
        },
        "required": [
          "tier",
          "period"
        ],
        "title": "CryptoCheckoutRequest",
        "type": "object"
      },
      "CryptoCheckoutResponse": {
        "description": "Successful crypto checkout response.",
        "properties": {
          "amount_eur": {
            "title": "Amount Eur",
            "type": "number"
          },
          "checkout_url": {
            "title": "Checkout Url",
            "type": "string"
          },
          "currency": {
            "default": "EUR",
            "title": "Currency",
            "type": "string"
          },
          "note": {
            "default": "Pay in any supported crypto. Settlement in EUR. Payment expires after 1 hour.",
            "title": "Note",
            "type": "string"
          },
          "payment_id": {
            "title": "Payment Id",
            "type": "string"
          }
        },
        "required": [
          "checkout_url",
          "payment_id",
          "amount_eur"
        ],
        "title": "CryptoCheckoutResponse",
        "type": "object"
      },
      "DataLineage": {
        "description": "data_lineage block \u2014 Growth tier only.\n\nExposed only when 'ai:lineage' scope is granted.\nprompt_hash and methodology_version are sanitized via LineageSanitizer\nbefore inclusion (SEC-ACT-04 / RGPD).",
        "properties": {
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Methodology label at time of generation.",
            "title": "Methodology Version"
          },
          "prompt_hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "SHA-256 hex of the effective prompt submitted to the LLM. Audit trail \u2014 proves non-rewriting of historical analyses.",
            "title": "Prompt Hash"
          }
        },
        "title": "DataLineage",
        "type": "object"
      },
      "DeleteMeResponse": {
        "description": "Response for DELETE /auth/me \u2014 RGPD Article 17 account deletion.\n\nT-165 Sprint 13.",
        "properties": {
          "message": {
            "title": "Message",
            "type": "string"
          },
          "status": {
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "status",
          "message"
        ],
        "title": "DeleteMeResponse",
        "type": "object"
      },
      "DiffSnapshotRef": {
        "description": "Lightweight reference to one snapshot in a diff pair.",
        "properties": {
          "generated_at": {
            "description": "UTC timestamp of this snapshot.",
            "format": "date-time",
            "title": "Generated At",
            "type": "string"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Methodology version at the time of generation.",
            "title": "Methodology Version"
          },
          "snapshot_id": {
            "description": "Unique snapshot identifier (UUID).",
            "title": "Snapshot Id",
            "type": "string"
          }
        },
        "required": [
          "snapshot_id",
          "generated_at"
        ],
        "title": "DiffSnapshotRef",
        "type": "object"
      },
      "DimAnalysisTypeRead": {
        "description": "Public read schema for marts.dim_analysis_type.",
        "properties": {
          "analysis_type_id": {
            "title": "Analysis Type Id",
            "type": "string"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "is_enabled": {
            "title": "Is Enabled",
            "type": "boolean"
          },
          "label": {
            "title": "Label",
            "type": "string"
          }
        },
        "required": [
          "analysis_type_id",
          "label",
          "description",
          "is_enabled"
        ],
        "title": "DimAnalysisTypeRead",
        "type": "object"
      },
      "DimAssetRead": {
        "description": "Public read schema for marts.dim_asset.\n\nPK exposed: asset_id (stable integer business key, D-063 DECISIONS.md 2026-05-21).\nType: integer (BIGSERIAL surrogate key from marts.dim_asset \u2014 NOT a coingecko_id string).\nSDK generators: this field is always integer; do NOT conflate with the string\n'asset_id' path param used in /v1/assets/{asset_id}/ai-analysis/* endpoints,\nwhich accepts coingecko slugs (e.g. 'bitcoin', 'ethereum').\ncoingecko_id is excluded (CoinGecko ToS \u00a76.2 \u2014 internal only).\nasset_hk / asset_sk excluded (internal DV2 keys).\nSCD2: valid_to=None means current version.",
        "properties": {
          "asset_id": {
            "description": "Stable integer surrogate key (BIGSERIAL) from marts.dim_asset (D-063). Type: integer. Not a coingecko slug. Use this key for star-schema endpoints (/v1/star/dim/assets/{asset_id}). See /v1/assets/{coingecko_id}/ai-analysis/* for string-keyed endpoints.",
            "title": "Asset Id",
            "type": "integer"
          },
          "is_current": {
            "title": "Is Current",
            "type": "boolean"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "ticker": {
            "title": "Ticker",
            "type": "string"
          },
          "tier": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tier"
          },
          "valid_from": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Valid From"
          },
          "valid_to": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Valid To"
          }
        },
        "required": [
          "asset_id",
          "ticker",
          "name",
          "is_current",
          "tier",
          "valid_from",
          "valid_to"
        ],
        "title": "DimAssetRead",
        "type": "object"
      },
      "DimChainRead": {
        "description": "Public read schema for marts.dim_chain.\n\n2026-06-10: real column names in prod are chain_name (not name) and\nnative_symbol (not symbol). SQL aliases them back to name/symbol for\nbackward-compatible payload. New columns is_l2 / parent_chain_id not\nyet exposed (not in SQL alias \u2014 future enrichment).",
        "properties": {
          "chain_id": {
            "title": "Chain Id",
            "type": "string"
          },
          "is_evm": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Evm"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "symbol": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Symbol"
          }
        },
        "required": [
          "chain_id",
          "name",
          "symbol",
          "is_evm"
        ],
        "title": "DimChainRead",
        "type": "object"
      },
      "DimDateRead": {
        "description": "Public read schema for marts.dim_date.",
        "properties": {
          "date_day": {
            "format": "date",
            "title": "Date Day",
            "type": "string"
          },
          "date_key": {
            "title": "Date Key",
            "type": "integer"
          },
          "day": {
            "title": "Day",
            "type": "integer"
          },
          "day_of_week": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Day Of Week"
          },
          "is_weekend": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Weekend"
          },
          "month": {
            "title": "Month",
            "type": "integer"
          },
          "quarter": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Quarter"
          },
          "year": {
            "title": "Year",
            "type": "integer"
          }
        },
        "required": [
          "date_key",
          "date_day",
          "year",
          "month",
          "day",
          "day_of_week",
          "is_weekend",
          "quarter"
        ],
        "title": "DimDateRead",
        "type": "object"
      },
      "DimEventTypeRead": {
        "description": "Public read schema for marts.dim_event_type.",
        "properties": {
          "category": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Category"
          },
          "event_type_id": {
            "title": "Event Type Id",
            "type": "string"
          },
          "label": {
            "title": "Label",
            "type": "string"
          }
        },
        "required": [
          "event_type_id",
          "label",
          "category"
        ],
        "title": "DimEventTypeRead",
        "type": "object"
      },
      "DimNewsSourceRead": {
        "description": "Public read schema for marts.dim_news_source.",
        "properties": {
          "feed_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Feed Type"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "source_id": {
            "title": "Source Id",
            "type": "string"
          },
          "url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Url"
          }
        },
        "required": [
          "source_id",
          "name",
          "url",
          "feed_type"
        ],
        "title": "DimNewsSourceRead",
        "type": "object"
      },
      "DimTierRead": {
        "description": "Public read schema for marts.dim_tier.\n\ntier_id is an int (1, 2, 3) per seed definition.",
        "properties": {
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "label": {
            "title": "Label",
            "type": "string"
          },
          "tier_id": {
            "title": "Tier Id",
            "type": "integer"
          },
          "token_count_approx": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Token Count Approx"
          }
        },
        "required": [
          "tier_id",
          "label",
          "description",
          "token_count_approx"
        ],
        "title": "DimTierRead",
        "type": "object"
      },
      "Dividend": {
        "description": "Single dividend record returned by GET /v1/stocks/{ticker}/dividends.\n\nData quality fields (REX U3 \u2014 anti-survente) :\n  dividend_date_note : 'approx_period_end' when ex_date comes from EDGAR XBRL\n                       period_end (not the true ex-dividend date). None = exact date.\n  amount_type        : 'per_share' (CommonStockDividendsPerShare* concepts) or\n                       'total_declared' (DividendsCommonStockCash \u2014 total, not per share).\n                       None = unknown (legacy sources).",
        "properties": {
          "amount": {
            "title": "Amount",
            "type": "number"
          },
          "amount_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Amount Type"
          },
          "currency": {
            "title": "Currency",
            "type": "string"
          },
          "dividend_date_note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dividend Date Note"
          },
          "dividend_type": {
            "title": "Dividend Type",
            "type": "string"
          },
          "ex_date": {
            "title": "Ex Date",
            "type": "string"
          },
          "frequency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Frequency"
          },
          "payment_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Payment Date"
          },
          "record_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Record Date"
          }
        },
        "required": [
          "ex_date",
          "amount",
          "currency",
          "dividend_type"
        ],
        "title": "Dividend",
        "type": "object"
      },
      "ETFAIAnalysis": {
        "description": "AI analysis payload for a single ETF ticker.\n\nKey rule (brief HS \u00a74.2 + COMITE-014 \u00a7legal):\n  - synthetic_swap ETFs \u2192 synthetic_swap_flag=True, 0 LLM call, halal_lookthrough_note set.\n  - holdings_screening_halal \u2192 Sonnet 4.6, top 20 holdings GICS description.\n  - No halal verdict \u2014 PIQ exposes factual data only.\n\nDisclaimer: Not financial advice. Not a fatwa. Methodology disclosed.",
        "properties": {
          "analysis_type": {
            "description": "Analysis type: 'composition' | 'holdings_screening_halal' | 'tracking_error'. Determines model routing and content.",
            "title": "Analysis Type",
            "type": "string"
          },
          "generated_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "UTC timestamp of generation or cache retrieval.",
            "title": "Generated At"
          },
          "halal_lookthrough_note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Factual note on halal lookthrough. For synthetic_swap: 'Synthetic swap ETF \u2014 classified non-shariah-compliant per AAOIFI standards. Verify with qualified scholar.' For holdings_screening_halal: GICS sector description of underlying holdings. PIQ describes facts; halal verdict is consumer-side.",
            "title": "Halal Lookthrough Note"
          },
          "model_used": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Anthropic model: 'claude-haiku-4-5' | 'claude-sonnet-4-6' | null (synthetic_swap). Null means 0 LLM calls (synthetic_swap fast-path).",
            "title": "Model Used"
          },
          "prompt_version": {
            "default": "v2.0-multi-asset",
            "description": "Prompt version identifier for audit trail.",
            "title": "Prompt Version",
            "type": "string"
          },
          "replication_method": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ETF replication method: physical_full | physical_sampling | synthetic_swap.",
            "title": "Replication Method"
          },
          "summary": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "AI-generated 3-4 sentence factual summary of the ETF. For synthetic_swap: 'Synthetic replication detected. No lookthrough analysis available.' AMF guard: no investment recommendation.",
            "title": "Summary"
          },
          "synthetic_swap_flag": {
            "default": false,
            "description": "True if replication_method=synthetic_swap. When True: 0 LLM calls made, halal_lookthrough_note is auto-set. Per OIC Fiqh Academy Resolution N\u00b040 / AAOIFI methodology.",
            "title": "Synthetic Swap Flag",
            "type": "boolean"
          },
          "ticker": {
            "description": "ETF ticker (uppercase, e.g. 'SPY').",
            "title": "Ticker",
            "type": "string"
          },
          "top_holdings_summary": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Factual summary of top holdings (ticker + weight). Null for synthetic_swap ETFs or if not provided in payload.",
            "title": "Top Holdings Summary"
          }
        },
        "required": [
          "ticker",
          "analysis_type"
        ],
        "title": "ETFAIAnalysis",
        "type": "object"
      },
      "ETFHolding": {
        "description": "Single ETF constituent holding \u2014 T-485 (HS brief \u00a74.2 ETFHoldings schema).\n\nOrdered by weight DESC in the API response (heaviest constituent first).\nweight is a fraction (0.0714 = 7.14%).\n\nSource: dv.sat_etf_holdings (mig 049 + 068).\nLegal: SEC EDGAR N-PORT 17 CFR \u00a7200.80 \u2014 public domain.\n       KIDs PRIIPs EU \u2014 Etalab 2.0 / CC-BY.\nNot financial advice. Not a fatwa. Methodology disclosed.",
        "properties": {
          "as_of_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "As Of Date"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Currency"
          },
          "isin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isin"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "rank": {
            "title": "Rank",
            "type": "integer"
          },
          "ticker": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ticker"
          },
          "weight": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Weight"
          }
        },
        "required": [
          "rank"
        ],
        "title": "ETFHolding",
        "type": "object"
      },
      "ETFHoldingsMeta": {
        "description": "Meta envelope for GET /v1/etf/{ticker}/holdings (T-485).\n\nExtends the standard meta with holdings-specific fields.\nMirrors ApiMeta structure but typed for the holdings context.",
        "properties": {
          "as_of_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "As Of Date"
          },
          "data_quality": {
            "title": "Data Quality",
            "type": "string"
          },
          "disclaimer": {
            "default": "Factual data only. Not financial advice. Methodology disclosed.",
            "title": "Disclaimer",
            "type": "string"
          },
          "has_next": {
            "title": "Has Next",
            "type": "boolean"
          },
          "licensed_for_commercial_use": {
            "default": true,
            "title": "Licensed For Commercial Use",
            "type": "boolean"
          },
          "source_primary": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source Primary"
          },
          "synthetic_swap_warning": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Synthetic Swap Warning"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "total",
          "has_next",
          "data_quality"
        ],
        "title": "ETFHoldingsMeta",
        "type": "object"
      },
      "ETFHoldingsResponse": {
        "description": "Full response envelope for GET /v1/etf/{ticker}/holdings (T-485).",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/ETFHolding"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ETFHoldingsMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ETFHoldingsResponse",
        "type": "object"
      },
      "EcbCatalogueEntry": {
        "description": "A single entry in the ECB series catalogue.",
        "properties": {
          "country_iso2": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country Iso2"
          },
          "description": {
            "title": "Description",
            "type": "string"
          },
          "flow_ref": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flow Ref"
          },
          "frequency": {
            "title": "Frequency",
            "type": "string"
          },
          "series_id": {
            "title": "Series Id",
            "type": "string"
          },
          "unit": {
            "title": "Unit",
            "type": "string"
          }
        },
        "required": [
          "series_id",
          "description",
          "frequency",
          "unit",
          "flow_ref",
          "country_iso2"
        ],
        "title": "EcbCatalogueEntry",
        "type": "object"
      },
      "EcbCatalogueResponse": {
        "description": "Response for GET /v1/macro/eu/series.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/EcbCatalogueEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "EcbCatalogueResponse",
        "type": "object"
      },
      "EcbObservation": {
        "description": "A single ECB macro time-series observation.",
        "properties": {
          "observation_date": {
            "description": "Date of observation.",
            "format": "date",
            "title": "Observation Date",
            "type": "string"
          },
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unit of measurement.",
            "title": "Unit"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Observation value. Null if unreleased or not available.",
            "title": "Value"
          }
        },
        "required": [
          "observation_date"
        ],
        "title": "EcbObservation",
        "type": "object"
      },
      "EcbSeriesMeta": {
        "description": "Response metadata for an ECB series query.",
        "properties": {
          "country_iso2": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO2 country code for country-specific series. Null = Euro area-wide.",
            "title": "Country Iso2"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "description": {
            "description": "Human-readable series description.",
            "title": "Description",
            "type": "string"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End date filter applied.",
            "title": "End Date"
          },
          "fetched_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Fetched At",
            "type": "string"
          },
          "flow_ref": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ECB SDW dataflow identifier (FM, ICP, BSI, IRS, MNA, LFS).",
            "title": "Flow Ref"
          },
          "frequency": {
            "description": "Data frequency: daily | monthly | quarterly.",
            "title": "Frequency",
            "type": "string"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live ECB SDW API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of observations in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "series_id": {
            "description": "Logical series identifier (ECB_*).",
            "title": "Series Id",
            "type": "string"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start date filter applied.",
            "title": "Start Date"
          },
          "total": {
            "description": "Total observations matching the query.",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "series_id",
          "description",
          "frequency",
          "flow_ref",
          "country_iso2",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_date",
          "end_date",
          "fetched_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "EcbSeriesMeta",
        "type": "object"
      },
      "EcbSeriesResponse": {
        "description": "Response for GET /v1/macro/eu/{series_id}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/EcbObservation"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/EcbSeriesMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "EcbSeriesResponse",
        "type": "object"
      },
      "EdinetAssetMeta": {
        "description": "Asset metadata embedded in response.",
        "properties": {
          "company_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Company name (English).",
            "title": "Company Name"
          },
          "listing_venue": {
            "description": "MIC listing venue (XJPX).",
            "title": "Listing Venue",
            "type": "string"
          },
          "ticker": {
            "description": "TSE 4-digit ticker.",
            "title": "Ticker",
            "type": "string"
          }
        },
        "required": [
          "ticker",
          "listing_venue"
        ],
        "title": "EdinetAssetMeta",
        "type": "object"
      },
      "EdinetFiling": {
        "description": "A single EDINET filing entry.",
        "properties": {
          "doc_description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Description of the document (may be in Japanese).",
            "title": "Doc Description"
          },
          "doc_id": {
            "description": "EDINET document ID (e.g. 'S100XXXX').",
            "title": "Doc Id",
            "type": "string"
          },
          "doc_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Normalised document type: 'Annual', 'Quarterly', 'Semi-annual', 'Other'.",
            "title": "Doc Type"
          },
          "edinet_code": {
            "description": "EDINET corporate code (e.g. 'E02144').",
            "title": "Edinet Code",
            "type": "string"
          },
          "filer_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Company name as registered with EDINET (may be in Japanese).",
            "title": "Filer Name"
          },
          "filing_date": {
            "description": "Date the document was filed with EDINET.",
            "format": "date",
            "title": "Filing Date",
            "type": "string"
          },
          "fiscal_year_end": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Fiscal year end date.",
            "title": "Fiscal Year End"
          },
          "pdf_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Direct URL to download the PDF from EDINET.",
            "title": "Pdf Url"
          },
          "period_end": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Reporting period end date.",
            "title": "Period End"
          },
          "period_start": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Reporting period start date.",
            "title": "Period Start"
          },
          "sec_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "5-digit TSE code (e.g. '72030' for Toyota 7203). Null if not listed at TSE.",
            "title": "Sec Code"
          },
          "submit_datetime": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Exact submission timestamp (UTC). EDINET source is JST, converted.",
            "title": "Submit Datetime"
          }
        },
        "required": [
          "doc_id",
          "filing_date",
          "edinet_code"
        ],
        "title": "EdinetFiling",
        "type": "object"
      },
      "EdinetFilingsMeta": {
        "description": "Response metadata for EDINET filings query.",
        "properties": {
          "asset": {
            "$ref": "#/components/schemas/EdinetAssetMeta"
          },
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "doc_type_filter": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "doc_type filter applied (Annual/Quarterly/Semi-annual).",
            "title": "Doc Type Filter"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live EDINET API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of filings in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "since": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Lower bound date filter applied.",
            "title": "Since"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "total": {
            "description": "Total filings matching the query.",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "asset",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "EdinetFilingsMeta",
        "type": "object"
      },
      "EdinetFilingsResponse": {
        "description": "Response for GET /v1/asset/{ticker}/edinet-filings.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/EdinetFiling"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/EdinetFilingsMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "EdinetFilingsResponse",
        "type": "object"
      },
      "EmailConfirmResponse": {
        "description": "Response for GET /auth/confirm \u2014 successful email confirmation.\n\nReturns JWT + api_key so the developer can immediately authenticate.\nThe api_key is the raw key previously created at signup (returned once here only).",
        "properties": {
          "access_token": {
            "title": "Access Token",
            "type": "string"
          },
          "api_key": {
            "title": "Api Key",
            "type": "string"
          },
          "expires_in": {
            "title": "Expires In",
            "type": "integer"
          },
          "message": {
            "default": "Account confirmed. Welcome to portfolIQ.",
            "title": "Message",
            "type": "string"
          },
          "token_type": {
            "default": "bearer",
            "title": "Token Type",
            "type": "string"
          }
        },
        "required": [
          "access_token",
          "expires_in",
          "api_key"
        ],
        "title": "EmailConfirmResponse",
        "type": "object"
      },
      "EmailLogEntry": {
        "properties": {
          "category": {
            "title": "Category",
            "type": "string"
          },
          "locale": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Locale"
          },
          "resend_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Resend Id"
          },
          "status": {
            "default": "sent",
            "pattern": "^(sent|bounced|complained|delivered|unsubscribed|failed)$",
            "title": "Status",
            "type": "string"
          },
          "subject": {
            "title": "Subject",
            "type": "string"
          },
          "template_name": {
            "title": "Template Name",
            "type": "string"
          },
          "to_email": {
            "title": "To Email",
            "type": "string"
          },
          "type": {
            "pattern": "^(transactional|marketing)$",
            "title": "Type",
            "type": "string"
          },
          "user_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "User Id"
          }
        },
        "required": [
          "to_email",
          "type",
          "category",
          "template_name",
          "subject"
        ],
        "title": "EmailLogEntry",
        "type": "object"
      },
      "EquityFundamentalsData": {
        "description": "Payload data block \u2014 CONTRACT-HS-PIQ Message 4 B.2.",
        "properties": {
          "aaoifi_ratios": {
            "$ref": "#/components/schemas/AaoifiRatios",
            "description": "AAOIFI Shari'a Standard computed financial ratios."
          },
          "cash_and_equivalents": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Cash and equivalents (EUR/local currency, snapshot date).",
            "title": "Cash And Equivalents"
          },
          "company_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Legal company name.",
            "title": "Company Name"
          },
          "country_iso": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "2-letter ISO 3166-1 alpha-2 country code of incorporation.",
            "title": "Country Iso"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Reporting currency (ISO 4217, e.g. EUR, GBP, USD).",
            "title": "Currency"
          },
          "fiscal_year": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Fiscal year of the snapshot (e.g. 2024).",
            "title": "Fiscal Year"
          },
          "interest_expense": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Interest expense / finance cost (EUR/local currency, fiscal year).",
            "title": "Interest Expense"
          },
          "interest_income": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Interest income (EUR/local currency, fiscal year).",
            "title": "Interest Income"
          },
          "is_halal_aaoifi": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "D-087 PIQ computed signal: True if all AAOIFI ratio thresholds pass and sector is not haram. NOT a fatwa. HS cross-validates independently. Null if ratios cannot be computed (missing data).",
            "title": "Is Halal Aaoifi"
          },
          "isin": {
            "description": "ISIN (ISO 6166), 12 chars.",
            "title": "Isin",
            "type": "string"
          },
          "market_cap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Market capitalisation in USD at snapshot date.",
            "title": "Market Cap Usd"
          },
          "sector_classification": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "GICS sector code in dot-notation (e.g. 'GICS:25.30'). Null if not classified.",
            "title": "Sector Classification"
          },
          "snapshot_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Balance sheet / snapshot date (ISO 8601, e.g. '2024-12-31').",
            "title": "Snapshot Date"
          },
          "ticker": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Exchange ticker symbol.",
            "title": "Ticker"
          },
          "total_debt": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total financial debt (EUR/local currency, snapshot date).",
            "title": "Total Debt"
          },
          "total_revenue": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total revenue (EUR/local currency, fiscal year).",
            "title": "Total Revenue"
          }
        },
        "required": [
          "isin"
        ],
        "title": "EquityFundamentalsData",
        "type": "object"
      },
      "EquityFundamentalsMeta": {
        "description": "Response metadata block \u2014 CONTRACT-HS-PIQ Message 4 B.2.",
        "properties": {
          "computed_signals": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Methodology labels for computed signals (e.g. is_halal_aaoifi).",
            "title": "Computed Signals",
            "type": "object"
          },
          "data_quality": {
            "default": "official_filings",
            "title": "Data Quality",
            "type": "string"
          },
          "disclaimer": {
            "default": "Stock fundamentals data sourced from SEC EDGAR public filings (10-K, 10-Q, 8-K \u2014 US public domain) and EOD price data from Stooq, normalised, currency-converted, and re-aggregated by portfolIQ. For informational purposes only. Not financial advice. Not a fatwa. No personalised recommendation under MAR (EU 596/2014) Art. 20 or AMF DOC-2013-21. Methodology disclosed at https://portfoliq.io/docs/methodology/fundamentals. Issuer classifications and ratios are computed best-effort from disclosed regulatory filings and may lag the most recent corporate events. Past performance does not guarantee future results.",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_lang_canonical": {
            "default": "en",
            "title": "Disclaimer Lang Canonical",
            "type": "string"
          },
          "disclaimer_translations": {
            "additionalProperties": {
              "type": "string"
            },
            "default": {
              "en": "Stock fundamentals data sourced from SEC EDGAR public filings (10-K, 10-Q, 8-K \u2014 US public domain) and EOD price data from Stooq, normalised, currency-converted, and re-aggregated by portfolIQ. For informational purposes only. Not financial advice. Not a fatwa. No personalised recommendation under MAR (EU 596/2014) Art. 20 or AMF DOC-2013-21. Methodology disclosed at https://portfoliq.io/docs/methodology/fundamentals. Issuer classifications and ratios are computed best-effort from disclosed regulatory filings and may lag the most recent corporate events. Past performance does not guarantee future results.",
              "fr": "Donn\u00e9es fondamentales actions issues des d\u00e9p\u00f4ts publics SEC EDGAR (10-K, 10-Q, 8-K \u2014 domaine public US) et des prix de cl\u00f4ture Stooq, normalis\u00e9es, converties en devise et r\u00e9-agr\u00e9g\u00e9es par portfolIQ. \u00c0 titre informatif uniquement. Ce n'est pas un conseil financier. Ce n'est pas une fatwa. Aucune recommandation personnalis\u00e9e au sens du r\u00e8glement MAR (UE 596/2014) art. 20 ni de la position AMF DOC-2013-21. M\u00e9thodologie publi\u00e9e sur https://portfoliq.io/docs/methodology/fundamentals. Les classifications et ratios \u00e9metteurs sont calcul\u00e9s en mode \u00ab meilleur effort \u00bb \u00e0 partir de d\u00e9p\u00f4ts r\u00e9glementaires publics et peuvent ne pas refl\u00e9ter les \u00e9v\u00e8nements corporatifs les plus r\u00e9cents. Les performances pass\u00e9es ne garantissent pas les r\u00e9sultats futurs."
            },
            "title": "Disclaimer Translations",
            "type": "object"
          },
          "source": {
            "default": "portfoliq.v1.0.0",
            "title": "Source",
            "type": "string"
          },
          "upstream": {
            "description": "List of upstream data sources (record_source from DV2.0 satellite).",
            "items": {
              "type": "string"
            },
            "title": "Upstream",
            "type": "array"
          }
        },
        "required": [
          "upstream"
        ],
        "title": "EquityFundamentalsMeta",
        "type": "object"
      },
      "EquityFundamentalsResponse": {
        "description": "Full response envelope \u2014 GET /v1/fundamentals/equity/{isin}.",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/EquityFundamentalsData"
          },
          "meta": {
            "$ref": "#/components/schemas/EquityFundamentalsMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "EquityFundamentalsResponse",
        "type": "object"
      },
      "EtfCatalogItem": {
        "description": "A single ETF entry in the catalog.\n\n2026-06-10: certifying_board / certification_methodology / certification_url\nREMOVED \u2014 HS is sovereign on halal verdicts (PIQ does not expose them).\nNew fields: issuer, fund_name, ter_bps (TER in basis points), aum_usd,\nisin (metadata_isin alias), fund_currency, index_tracked, ucits, domicile,\nmetadata_source, last_refresh, updated_at.",
        "properties": {
          "aum_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Assets Under Management in USD. Null if unknown or not yet backfilled.",
            "title": "Aum Usd"
          },
          "domicile": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Fund domicile country ISO 3166-1 alpha-2 (e.g. IE, LU, US).",
            "title": "Domicile"
          },
          "exchange": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "MIC exchange code (e.g. XLON, XNAS, XNYS, XETR). 'OTC' for US mutual funds seeded under PIQ doctrine.",
            "title": "Exchange"
          },
          "fund_currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Fund base currency ISO 4217 code (e.g. USD, EUR, GBP).",
            "title": "Fund Currency"
          },
          "fund_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Full fund name (e.g. 'iShares MSCI World Islamic UCITS ETF').",
            "title": "Fund Name"
          },
          "index_tracked": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Underlying index tracked by the ETF (e.g. 'MSCI World Islamic').",
            "title": "Index Tracked"
          },
          "isin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISIN identifier (12 chars). Sourced from metadata_isin column in the view.",
            "title": "Isin"
          },
          "issuer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ETF issuer / asset manager (e.g. iShares, Invesco, Saturna Capital).",
            "title": "Issuer"
          },
          "last_refresh": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 8601 timestamp of the last metadata refresh for this ETF record.",
            "title": "Last Refresh"
          },
          "listing_venue": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Listing venue MIC (same as exchange in most cases; raw hub_asset value).",
            "title": "Listing Venue"
          },
          "metadata_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Source of the ETF metadata record (e.g. 'justetf', 'factsheet', 'manual').",
            "title": "Metadata Source"
          },
          "ter_bps": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total Expense Ratio in basis points (e.g. 50 = 0.50% TER). Null if unknown.",
            "title": "Ter Bps"
          },
          "ticker": {
            "description": "ETF ticker symbol (e.g. ISWD, HLAL, SPUS).",
            "title": "Ticker",
            "type": "string"
          },
          "ucits": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True if UCITS-compliant (EU regulated). False for US mutual funds / non-UCITS.",
            "title": "Ucits"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 8601 timestamp of the last update tracked by the catalog view.",
            "title": "Updated At"
          }
        },
        "required": [
          "ticker"
        ],
        "title": "EtfCatalogItem",
        "type": "object"
      },
      "EtfCatalogMeta": {
        "description": "Response metadata for GET /v1/catalog/etfs.",
        "properties": {
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opaque base64 keyset cursor (high-water mark of this page). Pass as ?since= in the next request to pull incremental changes. None in full-list mode. None if no certified ETF was returned on this page.",
            "title": "Cursor"
          },
          "data_quality": {
            "enum": [
              "fresh",
              "empty"
            ],
            "title": "Data Quality",
            "type": "string"
          },
          "data_source": {
            "title": "Data Source",
            "type": "string"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "freshness": {
            "title": "Freshness",
            "type": "string"
          },
          "is_dev_dataset": {
            "title": "Is Dev Dataset",
            "type": "boolean"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "data_source",
          "freshness",
          "is_dev_dataset",
          "data_quality",
          "disclaimer"
        ],
        "title": "EtfCatalogMeta",
        "type": "object"
      },
      "EtfCatalogPagination": {
        "description": "Pagination metadata for the ETF catalog response.",
        "properties": {
          "has_more": {
            "title": "Has More",
            "type": "boolean"
          },
          "limit": {
            "title": "Limit",
            "type": "integer"
          },
          "offset": {
            "title": "Offset",
            "type": "integer"
          },
          "total": {
            "description": "Total ETFs matching the query.",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "total",
          "offset",
          "limit",
          "has_more"
        ],
        "title": "EtfCatalogPagination",
        "type": "object"
      },
      "EtfCatalogResponse": {
        "description": "Response for GET /v1/catalog/etfs.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/EtfCatalogItem"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/EtfCatalogMeta"
          },
          "pagination": {
            "$ref": "#/components/schemas/EtfCatalogPagination"
          }
        },
        "required": [
          "data",
          "pagination",
          "meta"
        ],
        "title": "EtfCatalogResponse",
        "type": "object"
      },
      "EurostatDatasetEntry": {
        "description": "A single dataset entry in the datasets catalogue.",
        "properties": {
          "code": {
            "title": "Code",
            "type": "string"
          },
          "description": {
            "title": "Description",
            "type": "string"
          },
          "frequency": {
            "title": "Frequency",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "unit": {
            "title": "Unit",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "frequency",
          "unit",
          "description"
        ],
        "title": "EurostatDatasetEntry",
        "type": "object"
      },
      "EurostatDatasetMeta": {
        "description": "Dataset metadata embedded in response.",
        "properties": {
          "code": {
            "description": "Eurostat dataset code.",
            "title": "Code",
            "type": "string"
          },
          "frequency": {
            "description": "Data release frequency: monthly, quarterly, or annual.",
            "title": "Frequency",
            "type": "string"
          },
          "name": {
            "description": "Human-readable dataset name.",
            "title": "Name",
            "type": "string"
          },
          "unit": {
            "description": "Default unit of measurement.",
            "title": "Unit",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "frequency",
          "unit"
        ],
        "title": "EurostatDatasetMeta",
        "type": "object"
      },
      "EurostatDatasetsResponse": {
        "description": "Response for GET /v1/macro/eurostat/datasets.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/EurostatDatasetEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "EurostatDatasetsResponse",
        "type": "object"
      },
      "EurostatGeoEntry": {
        "description": "A single geo entry in the geo catalogue.",
        "properties": {
          "code": {
            "title": "Code",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name"
        ],
        "title": "EurostatGeoEntry",
        "type": "object"
      },
      "EurostatGeoMeta": {
        "description": "Geo code metadata embedded in response.",
        "properties": {
          "code": {
            "description": "Eurostat geo code (EA20, EU27_2020, or ISO2 country code).",
            "title": "Code",
            "type": "string"
          },
          "name": {
            "description": "Geographic area name.",
            "title": "Name",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name"
        ],
        "title": "EurostatGeoMeta",
        "type": "object"
      },
      "EurostatGeoResponse": {
        "description": "Response for GET /v1/macro/eurostat/geo.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/EurostatGeoEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "EurostatGeoResponse",
        "type": "object"
      },
      "EurostatObservation": {
        "description": "A single Eurostat observation.",
        "properties": {
          "period": {
            "description": "Observation period. Format depends on dataset frequency: '2026-03' (monthly), '2026-Q1' (quarterly), '2025' (annual).",
            "title": "Period",
            "type": "string"
          },
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unit of measurement (%, EUR_millions, index_2015=100, PPS_EU27_2020=100).",
            "title": "Unit"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Observation value. Null if not published for this geo/period.",
            "title": "Value"
          }
        },
        "required": [
          "period"
        ],
        "title": "EurostatObservation",
        "type": "object"
      },
      "EurostatSeriesMeta": {
        "description": "Response metadata for a dataset/geo query.",
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "dataset": {
            "$ref": "#/components/schemas/EurostatDatasetMeta"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End period filter applied (inclusive).",
            "title": "End Period"
          },
          "geo": {
            "$ref": "#/components/schemas/EurostatGeoMeta"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live Eurostat API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of observations in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start period filter applied (inclusive).",
            "title": "Start Period"
          },
          "total": {
            "description": "Total observations matching the query.",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "geo",
          "dataset",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_period",
          "end_period",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "EurostatSeriesMeta",
        "type": "object"
      },
      "EurostatSeriesResponse": {
        "description": "Response for GET /v1/macro/eurostat/{dataset_code}/{geo_code}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/EurostatObservation"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/EurostatSeriesMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "EurostatSeriesResponse",
        "type": "object"
      },
      "ExportApiKeyInfo": {
        "description": "API key metadata for RGPD export.\n\nkey_hash is never returned; only last_4 and key_id are exposed.",
        "properties": {
          "created_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At"
          },
          "id": {
            "title": "Id",
            "type": "string"
          },
          "is_active": {
            "title": "Is Active",
            "type": "boolean"
          },
          "label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Label"
          },
          "last_4": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last 4"
          },
          "last_used_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Used At"
          },
          "scope": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Scope"
          },
          "tier": {
            "title": "Tier",
            "type": "string"
          }
        },
        "required": [
          "id",
          "label",
          "tier",
          "is_active",
          "created_at",
          "last_used_at"
        ],
        "title": "ExportApiKeyInfo",
        "type": "object"
      },
      "ExportAuditLogEntry": {
        "description": "Audit log entry for RGPD export (last 90 days, no sensitive payload).",
        "properties": {
          "created_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At"
          },
          "event_type": {
            "title": "Event Type",
            "type": "string"
          },
          "id": {
            "title": "Id",
            "type": "string"
          }
        },
        "required": [
          "id",
          "event_type",
          "created_at"
        ],
        "title": "ExportAuditLogEntry",
        "type": "object"
      },
      "ExportBillingInfo": {
        "description": "Billing summary for RGPD export \u2014 Stripe IDs + tier only.\n\nNo payment card data (held by Stripe, never in our DB).",
        "properties": {
          "stripe_customer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stripe Customer Id"
          },
          "stripe_subscription_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stripe Subscription Id"
          },
          "tier": {
            "title": "Tier",
            "type": "string"
          }
        },
        "required": [
          "stripe_customer_id",
          "stripe_subscription_id",
          "tier"
        ],
        "title": "ExportBillingInfo",
        "type": "object"
      },
      "ExportConsentInfo": {
        "description": "Consent and email preference state for RGPD export.",
        "properties": {
          "consent_marketing_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Consent Marketing At"
          },
          "consent_marketing_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Consent Marketing Source"
          },
          "marketing_optin": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Marketing Optin"
          },
          "newsletter": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Newsletter"
          },
          "product_updates": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Product Updates"
          },
          "promotions": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Promotions"
          },
          "recommendations": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Recommendations"
          },
          "unsubscribed_all": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Unsubscribed All"
          }
        },
        "title": "ExportConsentInfo",
        "type": "object"
      },
      "ExportEmailEvent": {
        "description": "Email event for RGPD export.",
        "properties": {
          "id": {
            "title": "Id",
            "type": "integer"
          },
          "sent_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sent At"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status"
          },
          "template_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Template Key"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated At"
          }
        },
        "required": [
          "id",
          "template_key",
          "sent_at",
          "status",
          "updated_at"
        ],
        "title": "ExportEmailEvent",
        "type": "object"
      },
      "ExportHalalPosition": {
        "description": "Halal portfolio position for RGPD Art. 20 export.\n\nTICKET-747 Sprint 97 \u2014 B97-11.\nColumns sourced from api.user_halal_positions (migration 247, T-728 Sprint 96).\nticker: instrument identifier (TEXT, UNIQUE per user)\nquantity: NUMERIC(20,8) \u2014 converted to float for JSON portability\ncurrency: valuation currency (EUR/USD/GBP/CHF)\nadded_at: ISO 8601 UTC timestamp of first insertion",
        "properties": {
          "added_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Added At"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Currency"
          },
          "quantity": {
            "title": "Quantity",
            "type": "number"
          },
          "ticker": {
            "title": "Ticker",
            "type": "string"
          }
        },
        "required": [
          "ticker",
          "quantity",
          "currency",
          "added_at"
        ],
        "title": "ExportHalalPosition",
        "type": "object"
      },
      "ExportObjection": {
        "description": "Art. 21 objection record for RGPD export.",
        "properties": {
          "objected_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Objected At"
          },
          "processing_category": {
            "title": "Processing Category",
            "type": "string"
          }
        },
        "required": [
          "processing_category",
          "objected_at"
        ],
        "title": "ExportObjection",
        "type": "object"
      },
      "ExportSqlCredential": {
        "description": "SQL credential metadata for RGPD export (Enterprise tier).\n\npg_username only \u2014 password_hash never returned.",
        "properties": {
          "created_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At"
          },
          "id": {
            "title": "Id",
            "type": "string"
          },
          "pg_username": {
            "title": "Pg Username",
            "type": "string"
          },
          "revoked_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Revoked At"
          }
        },
        "required": [
          "id",
          "pg_username",
          "created_at",
          "revoked_at"
        ],
        "title": "ExportSqlCredential",
        "type": "object"
      },
      "FactAiAnalysisRead": {
        "description": "AI-generated analysis per asset per analysis type per date.\n\nSource: marts.fact_ai_analysis.\nKey: (asset_id, analysis_type_id, generated_date) \u2014 composite business key.\nai_analysis_sk (surrogate key) is NOT exposed.\nExcludes: *_hk, *_sk, _loaded_at, cost_usd_micros, cache_hit.\ncost_usd_micros and cache_hit are doubly excluded (T-244 absolute prohibition\nat dbt level + this Pydantic schema as defense-in-depth).\nai_generated=True is always present in the payload for transparency.",
        "properties": {
          "ai_generated": {
            "default": true,
            "title": "Ai Generated",
            "type": "boolean"
          },
          "analysis_type_id": {
            "title": "Analysis Type Id",
            "type": "string"
          },
          "asset_id": {
            "title": "Asset Id",
            "type": "integer"
          },
          "content_json": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Content Json"
          },
          "generated_date": {
            "format": "date",
            "title": "Generated Date",
            "type": "string"
          },
          "locale": {
            "default": "en",
            "title": "Locale",
            "type": "string"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Methodology Version"
          },
          "model_id": {
            "title": "Model Id",
            "type": "string"
          },
          "prompt_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Prompt Version"
          }
        },
        "required": [
          "asset_id",
          "analysis_type_id",
          "generated_date",
          "model_id",
          "prompt_version",
          "content_json",
          "methodology_version"
        ],
        "title": "FactAiAnalysisRead",
        "type": "object"
      },
      "FactAssetFundamentalsRead": {
        "description": "Protocol valuation fundamentals (P/S, P/R ratios) per asset per date.\n\nSource: marts.fact_asset_fundamentals.\nKey: (asset_id, snapshot_date).\nExcludes: *_hk, *_sk, _loaded_at, cost_usd_micros, cache_hit.\nLegal: DeFiLlama MIT licence, on-chain derived data.",
        "properties": {
          "asset_id": {
            "title": "Asset Id",
            "type": "integer"
          },
          "fees_30d_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fees 30D Usd"
          },
          "fees_annualized": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fees Annualized"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Methodology Version"
          },
          "pr_ratio": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pr Ratio"
          },
          "ps_ratio": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ps Ratio"
          },
          "revenue_30d_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Revenue 30D Usd"
          },
          "revenue_annualized": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Revenue Annualized"
          },
          "snapshot_date": {
            "format": "date",
            "title": "Snapshot Date",
            "type": "string"
          }
        },
        "required": [
          "asset_id",
          "snapshot_date",
          "ps_ratio",
          "pr_ratio",
          "fees_30d_usd",
          "revenue_30d_usd",
          "fees_annualized",
          "revenue_annualized",
          "methodology_version"
        ],
        "title": "FactAssetFundamentalsRead",
        "type": "object"
      },
      "FactEventRead": {
        "description": "Market and asset-specific events.\n\nSource: marts.fact_event.\nKey: (asset_id, event_type_id, event_date) \u2014 asset_id may be NULL for market-wide events.\nExcludes: *_hk, *_sk, _loaded_at, cost_usd_micros, cache_hit.",
        "properties": {
          "asset_id": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Asset Id"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "event_date": {
            "format": "date",
            "title": "Event Date",
            "type": "string"
          },
          "event_type_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Event Type Id"
          },
          "source_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source Url"
          },
          "title": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Title"
          }
        },
        "required": [
          "asset_id",
          "event_type_id",
          "event_date",
          "title",
          "description",
          "source_url"
        ],
        "title": "FactEventRead",
        "type": "object"
      },
      "FactMarketSnapshotRead": {
        "description": "Daily market snapshot per asset.\n\nSource: marts.fact_market_snapshot.\nKey: (asset_id, snapshot_date).\nExcludes: *_hk, *_sk, exposure_tag, _loaded_at, total_volume_usd,\n          price_dispersion_pct, cost_usd_micros, cache_hit.",
        "properties": {
          "asset_id": {
            "title": "Asset Id",
            "type": "integer"
          },
          "change_24h_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Change 24H Pct"
          },
          "market_cap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Market Cap Usd"
          },
          "price_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Usd"
          },
          "snapshot_date": {
            "format": "date",
            "title": "Snapshot Date",
            "type": "string"
          },
          "tier": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tier"
          },
          "volume_24h_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Volume 24H Usd"
          }
        },
        "required": [
          "asset_id",
          "snapshot_date",
          "price_usd",
          "market_cap_usd",
          "volume_24h_usd",
          "change_24h_pct",
          "tier"
        ],
        "title": "FactMarketSnapshotRead",
        "type": "object"
      },
      "FactNewsMentionRead": {
        "description": "News article mentions per asset.\n\nSource: marts.fact_news_mention.\nKey: (article_id, asset_id).\narticle_id is the public business key (aliased from article_hk or source ID \u2014\naligned with the actual column in marts.fact_news_mention; see T-252 for the\nexact SQL alias). Surrogate keys are NOT exposed.\nExcludes: *_hk, *_sk, _loaded_at, cost_usd_micros, cache_hit.",
        "properties": {
          "article_id": {
            "title": "Article Id",
            "type": "string"
          },
          "asset_id": {
            "title": "Asset Id",
            "type": "integer"
          },
          "mention_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mention Count"
          },
          "published_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Published At"
          },
          "source_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source Id"
          }
        },
        "required": [
          "article_id",
          "asset_id",
          "published_at",
          "source_id",
          "mention_count"
        ],
        "title": "FactNewsMentionRead",
        "type": "object"
      },
      "FactOnchainAdvancedRead": {
        "description": "Advanced on-chain metrics (BTC-specific: MVRV, NUPL, SOPR, HODL waves).\n\nSource: marts.fact_onchain_advanced.\nKey: (asset_id, metric_date). Currently BTC-only.\nExcludes: *_hk, *_sk, _loaded_at, cost_usd_micros, cache_hit.\nNote: hodl_waves is JSONB (keyed by age bucket); structure described in\nmethodology/onchain-realized-metrics-v1.0.md.",
        "properties": {
          "asset_id": {
            "title": "Asset Id",
            "type": "integer"
          },
          "hodl_waves": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hodl Waves"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Methodology Version"
          },
          "metric_date": {
            "format": "date",
            "title": "Metric Date",
            "type": "string"
          },
          "mvrv_ratio": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mvrv Ratio"
          },
          "nupl": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nupl"
          },
          "realized_cap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Realized Cap Usd"
          },
          "realized_price_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Realized Price Usd"
          },
          "sopr": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sopr"
          }
        },
        "required": [
          "asset_id",
          "metric_date",
          "realized_cap_usd",
          "realized_price_usd",
          "mvrv_ratio",
          "nupl",
          "sopr",
          "hodl_waves",
          "methodology_version"
        ],
        "title": "FactOnchainAdvancedRead",
        "type": "object"
      },
      "FactOnchainCoreRead": {
        "description": "Core on-chain metrics per asset per date.\n\nSource: marts.fact_onchain_core.\nKey: (asset_id, metric_date).\nExcludes: *_hk, *_sk, _loaded_at, cost_usd_micros, cache_hit.\nNote: hash_rate is NULL for non-PoW assets.",
        "properties": {
          "active_addresses": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Active Addresses"
          },
          "asset_id": {
            "title": "Asset Id",
            "type": "integer"
          },
          "hash_rate": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hash Rate"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Methodology Version"
          },
          "metric_date": {
            "format": "date",
            "title": "Metric Date",
            "type": "string"
          },
          "transaction_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Transaction Count"
          },
          "transaction_volume_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Transaction Volume Usd"
          }
        },
        "required": [
          "asset_id",
          "metric_date",
          "active_addresses",
          "transaction_count",
          "transaction_volume_usd",
          "hash_rate",
          "methodology_version"
        ],
        "title": "FactOnchainCoreRead",
        "type": "object"
      },
      "FactProtocolEconomicsRead": {
        "description": "Protocol fees and revenue (24h / 7d) from DeFiLlama.\n\nSource: marts.fact_protocol_economics.\nKey: (protocol_id, snapshot_date).\nprotocol_id is the defillama_slug (string, not a surrogate key).\nExcludes: *_hk, *_sk, _loaded_at, cost_usd_micros, cache_hit.\nLegal: DeFiLlama MIT licence.",
        "properties": {
          "fees_24h_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fees 24H Usd"
          },
          "fees_7d_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fees 7D Usd"
          },
          "protocol_id": {
            "title": "Protocol Id",
            "type": "string"
          },
          "revenue_24h_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Revenue 24H Usd"
          },
          "revenue_7d_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Revenue 7D Usd"
          },
          "snapshot_date": {
            "format": "date",
            "title": "Snapshot Date",
            "type": "string"
          }
        },
        "required": [
          "protocol_id",
          "snapshot_date",
          "fees_24h_usd",
          "fees_7d_usd",
          "revenue_24h_usd",
          "revenue_7d_usd"
        ],
        "title": "FactProtocolEconomicsRead",
        "type": "object"
      },
      "FactProtocolTvlRead": {
        "description": "Protocol TVL snapshots from DeFiLlama.\n\nSource: marts.fact_protocol_tvl.\nKey: (protocol_id, snapshot_date).\nprotocol_id is the defillama_slug (string, not a surrogate key).\nExcludes: *_hk, *_sk, _loaded_at, tvl_defillama_check_usd,\n          ecart_pct, alert_ecart_gt5pct, cost_usd_micros, cache_hit.\nLegal: DeFiLlama MIT licence.",
        "properties": {
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Methodology Version"
          },
          "protocol_id": {
            "title": "Protocol Id",
            "type": "string"
          },
          "snapshot_date": {
            "format": "date",
            "title": "Snapshot Date",
            "type": "string"
          },
          "tvl_change_1d_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tvl Change 1D Pct"
          },
          "tvl_change_7d_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tvl Change 7D Pct"
          },
          "tvl_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tvl Usd"
          }
        },
        "required": [
          "protocol_id",
          "snapshot_date",
          "tvl_usd",
          "tvl_change_1d_pct",
          "tvl_change_7d_pct",
          "methodology_version"
        ],
        "title": "FactProtocolTvlRead",
        "type": "object"
      },
      "FactVwapConsensusRead": {
        "description": "VWAP consensus per asset per timeframe per date.\n\nSource: marts.fact_vwap_consensus.\nKey: (asset_id, snapshot_date, timeframe).\nExcludes: *_hk, *_sk, exposure_tag, _loaded_at, total_volume_usd,\n          price_dispersion_pct, cost_usd_micros, cache_hit.",
        "properties": {
          "asset_id": {
            "title": "Asset Id",
            "type": "integer"
          },
          "exchange_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Exchange Count"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Methodology Version"
          },
          "snapshot_date": {
            "format": "date",
            "title": "Snapshot Date",
            "type": "string"
          },
          "timeframe": {
            "title": "Timeframe",
            "type": "string"
          },
          "volume_usd_total": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Volume Usd Total"
          },
          "vwap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vwap Usd"
          }
        },
        "required": [
          "asset_id",
          "snapshot_date",
          "timeframe",
          "vwap_usd",
          "volume_usd_total",
          "exchange_count",
          "methodology_version"
        ],
        "title": "FactVwapConsensusRead",
        "type": "object"
      },
      "FieldChange": {
        "description": "One changed field between two snapshots.\n\nNumeric fields carry a delta. Text fields carry text_changed + cosine_similarity.\nRaw text diff is NEVER exposed (AMF \u00a75.3 \u2014 risque l\u00e9gal).",
        "properties": {
          "change_type": {
            "description": "Nature of the change (DATA_REFRESH | MODEL_UPGRADE | METHODOLOGY_CHANGE | RESTATEMENT).",
            "enum": [
              "DATA_REFRESH",
              "MODEL_UPGRADE",
              "METHODOLOGY_CHANGE",
              "RESTATEMENT"
            ],
            "title": "Change Type",
            "type": "string"
          },
          "delta": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Numeric delta (to_value - from_value). Populated only for numeric fields.",
            "title": "Delta"
          },
          "field": {
            "description": "Name of the changed field (e.g. 'sentiment_score', 'summary').",
            "title": "Field",
            "type": "string"
          },
          "from_value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              },
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Previous value (numeric, string label, or bool). Never raw text.",
            "title": "From Value"
          },
          "to_value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              },
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "New value (numeric, string label, or bool). Never raw text.",
            "title": "To Value"
          }
        },
        "required": [
          "field",
          "change_type"
        ],
        "title": "FieldChange",
        "type": "object"
      },
      "ForexData": {
        "description": "Forex pair payload \u2014 Sprint 42 Lane B contract.",
        "properties": {
          "as_of_date": {
            "title": "As Of Date",
            "type": "string"
          },
          "base": {
            "title": "Base",
            "type": "string"
          },
          "change_pct_1d": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Change Pct 1D"
          },
          "latest_rate": {
            "title": "Latest Rate",
            "type": "number"
          },
          "pair": {
            "title": "Pair",
            "type": "string"
          },
          "quote": {
            "title": "Quote",
            "type": "string"
          },
          "series_30d": {
            "default": [],
            "items": {
              "$ref": "#/components/schemas/ForexObservation"
            },
            "title": "Series 30D",
            "type": "array"
          }
        },
        "required": [
          "pair",
          "base",
          "quote",
          "latest_rate",
          "as_of_date"
        ],
        "title": "ForexData",
        "type": "object"
      },
      "ForexMeta": {
        "description": "Forex response metadata.",
        "properties": {
          "computed_at": {
            "title": "Computed At",
            "type": "string"
          },
          "data_quality": {
            "default": "full",
            "title": "Data Quality",
            "type": "string"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_ar": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disclaimer Ar"
          },
          "disclaimer_fr": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disclaimer Fr"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "upstream": {
            "items": {
              "type": "string"
            },
            "title": "Upstream",
            "type": "array"
          }
        },
        "required": [
          "source",
          "upstream",
          "disclaimer",
          "computed_at"
        ],
        "title": "ForexMeta",
        "type": "object"
      },
      "ForexObservation": {
        "description": "One observation in the daily series.",
        "properties": {
          "mid_rate": {
            "title": "Mid Rate",
            "type": "number"
          },
          "rate_date": {
            "title": "Rate Date",
            "type": "string"
          }
        },
        "required": [
          "rate_date",
          "mid_rate"
        ],
        "title": "ForexObservation",
        "type": "object"
      },
      "ForexPairSummary": {
        "description": "One available pair item returned by GET /v1/forex/search.",
        "properties": {
          "as_of_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "As Of Date"
          },
          "base": {
            "title": "Base",
            "type": "string"
          },
          "latest_rate": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Latest Rate"
          },
          "pair": {
            "title": "Pair",
            "type": "string"
          },
          "quote": {
            "title": "Quote",
            "type": "string"
          }
        },
        "required": [
          "pair",
          "base",
          "quote"
        ],
        "title": "ForexPairSummary",
        "type": "object"
      },
      "ForexResponse": {
        "description": "GET /v1/forex/{pair} response.",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/ForexData"
          },
          "meta": {
            "$ref": "#/components/schemas/ForexMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ForexResponse",
        "type": "object"
      },
      "ForexSearchMeta": {
        "description": "Pagination metadata for GET /v1/forex/search.",
        "properties": {
          "computed_at": {
            "title": "Computed At",
            "type": "string"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "has_next": {
            "title": "Has Next",
            "type": "boolean"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "source",
          "total",
          "has_next",
          "disclaimer",
          "computed_at"
        ],
        "title": "ForexSearchMeta",
        "type": "object"
      },
      "ForexSearchResponse": {
        "description": "GET /v1/forex/search response.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/ForexPairSummary"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ForexSearchMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ForexSearchResponse",
        "type": "object"
      },
      "ForgotPasswordRequest": {
        "description": "Body for POST /auth/forgot-password.",
        "properties": {
          "email": {
            "format": "email",
            "title": "Email",
            "type": "string"
          }
        },
        "required": [
          "email"
        ],
        "title": "ForgotPasswordRequest",
        "type": "object"
      },
      "ForgotPasswordResponse": {
        "description": "Response for POST /auth/forgot-password.\n\nAlways returns 200 with the same message regardless of whether the email exists\n(anti-enumeration protection).",
        "properties": {
          "message": {
            "title": "Message",
            "type": "string"
          },
          "status": {
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "status",
          "message"
        ],
        "title": "ForgotPasswordResponse",
        "type": "object"
      },
      "FundamentalsResponse": {
        "description": "Asset fundamental valuation ratios.\n\nP/S  = market_cap_usd / (revenue_30d_usd * 365/30)  [preferred]\n     = market_cap_usd / (fees_30d_usd * 365/30)     [fallback when revenue unavailable]\nP/R  = market_cap_usd / (revenue_30d_usd * 365/30)  [strict \u2014 NULL when revenue unavailable]\n\nSprint 12 T-144: ps_ratio_label documents which denominator was used for ps_ratio.\nWhen revenue_30d_usd is NULL, ps_ratio falls back to fees_30d_usd as denominator and\nps_ratio_label is set to 'P/S approx (fees_30d)' for transparency.\n\nRatios are NULL when:\n- No DeFiLlama protocol link exists for the asset\n- Both fees and revenue data are unavailable or zero\n- market_cap_usd is unavailable\n\nLegal: DeFiLlama MIT licence, on-chain derived data.\nNot financial advice. Methodology disclosed.",
        "properties": {
          "asset_id": {
            "description": "Stable integer surrogate key for the asset (D-063).",
            "title": "Asset Id",
            "type": "integer"
          },
          "fees_30d_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total protocol fees (last 30 days, USD). Source: DeFiLlama /overview/fees. NULL if no DeFiLlama protocol link or data unavailable.",
            "title": "Fees 30D Usd"
          },
          "fees_annualized": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "fees_30d_usd * (365 / 30). Annualized projection.",
            "title": "Fees Annualized"
          },
          "market_cap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Market capitalisation in USD at snapshot_date.",
            "title": "Market Cap Usd"
          },
          "methodology_version": {
            "default": "defillama-v1",
            "description": "Methodology version used for fees sourcing. 'defillama-v1' = DeFiLlama /overview/fees bulk endpoint (MIT licence).",
            "title": "Methodology Version",
            "type": "string"
          },
          "pr_ratio": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Price-to-Revenue (P/R) ratio: market_cap_usd / revenue_annualized. NULL if revenue_annualized is zero or unavailable. Not financial advice. Factual metric only.",
            "title": "Pr Ratio"
          },
          "price_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Token price in USD at snapshot_date.",
            "title": "Price Usd"
          },
          "ps_ratio": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Price-to-Sales (P/S) ratio. Preferred denominator: revenue_annualized. Fallback denominator: fees_annualized (when revenue unavailable). See ps_ratio_label for which denominator was used. NULL if both fees and revenue are zero or unavailable. Not financial advice. Factual metric only.",
            "title": "Ps Ratio"
          },
          "ps_ratio_label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Documents which denominator was used for ps_ratio. Values: 'P/S (revenue_30d)' | 'P/S approx (fees_30d)' | null. Sprint 12 T-144: transparency field for P/S approx fallback.",
            "title": "Ps Ratio Label"
          },
          "revenue_30d_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Protocol revenue retained by the protocol (last 30 days, USD). Subset of fees_30d_usd. NULL if unavailable.",
            "title": "Revenue 30D Usd"
          },
          "revenue_annualized": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "revenue_30d_usd * (365 / 30). Annualized projection.",
            "title": "Revenue Annualized"
          },
          "snapshot_date": {
            "description": "Date of the latest available data snapshot (UTC).",
            "format": "date",
            "title": "Snapshot Date",
            "type": "string"
          }
        },
        "required": [
          "asset_id",
          "snapshot_date"
        ],
        "title": "FundamentalsResponse",
        "type": "object"
      },
      "FxData": {
        "description": "FX rate payload \u2014 DAT-006 HS contract format.",
        "properties": {
          "as_of_date": {
            "title": "As Of Date",
            "type": "string"
          },
          "base": {
            "title": "Base",
            "type": "string"
          },
          "quote": {
            "title": "Quote",
            "type": "string"
          },
          "rate": {
            "title": "Rate",
            "type": "number"
          }
        },
        "required": [
          "base",
          "quote",
          "rate",
          "as_of_date"
        ],
        "title": "FxData",
        "type": "object"
      },
      "FxMeta": {
        "description": "FX response metadata \u2014 DAT-006 HS contract format.",
        "properties": {
          "computed_at": {
            "title": "Computed At",
            "type": "string"
          },
          "data_quality": {
            "default": "full",
            "title": "Data Quality",
            "type": "string"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "upstream": {
            "items": {
              "type": "string"
            },
            "title": "Upstream",
            "type": "array"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "source",
          "upstream",
          "disclaimer",
          "computed_at"
        ],
        "title": "FxMeta",
        "type": "object"
      },
      "FxResponse": {
        "description": "DAT-006 FX endpoint response \u2014 matches HS Message 1 payload contract.",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/FxData"
          },
          "meta": {
            "$ref": "#/components/schemas/FxMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "FxResponse",
        "type": "object"
      },
      "GeopoliticalCountriesResponse": {
        "description": "Response for GET /v1/geopolitical/countries.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/GeopoliticalCountryEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "GeopoliticalCountriesResponse",
        "type": "object"
      },
      "GeopoliticalCountryEntry": {
        "description": "A single country entry in the countries catalogue.",
        "properties": {
          "iso3": {
            "title": "Iso3",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          }
        },
        "required": [
          "iso3",
          "name"
        ],
        "title": "GeopoliticalCountryEntry",
        "type": "object"
      },
      "GeopoliticalCountryMeta": {
        "description": "Country metadata embedded in response.",
        "properties": {
          "iso3": {
            "description": "ISO 3166-1 alpha-3 country code.",
            "title": "Iso3",
            "type": "string"
          },
          "name": {
            "description": "Country name.",
            "title": "Name",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "iso3",
          "name"
        ],
        "title": "GeopoliticalCountryMeta",
        "type": "object"
      },
      "GeopoliticalEvent": {
        "description": "A single geopolitical event aggregation row.",
        "properties": {
          "articles_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Number of source news articles covering these events.",
            "title": "Articles Count"
          },
          "avg_tone": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Average sentiment tone, normalised to [-10, +10]. Negative = negative sentiment.",
            "title": "Avg Tone"
          },
          "event_date": {
            "description": "Calendar date of the event aggregation.",
            "format": "date",
            "title": "Event Date",
            "type": "string"
          },
          "event_type": {
            "description": "Event category: economic, political, conflict, diplomatic, social, general.",
            "title": "Event Type",
            "type": "string"
          },
          "events_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Number of GDELT events/articles in this bucket. Null if not available.",
            "title": "Events Count"
          }
        },
        "required": [
          "event_date",
          "event_type"
        ],
        "title": "GeopoliticalEvent",
        "type": "object"
      },
      "GeopoliticalEventTypeEntry": {
        "description": "A single event type entry in the catalogue.",
        "properties": {
          "code": {
            "title": "Code",
            "type": "string"
          },
          "description": {
            "title": "Description",
            "type": "string"
          }
        },
        "required": [
          "code",
          "description"
        ],
        "title": "GeopoliticalEventTypeEntry",
        "type": "object"
      },
      "GeopoliticalEventTypesResponse": {
        "description": "Response for GET /v1/geopolitical/event-types.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/GeopoliticalEventTypeEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "disclaimer"
        ],
        "title": "GeopoliticalEventTypesResponse",
        "type": "object"
      },
      "GeopoliticalResponse": {
        "description": "Response for GET /v1/geopolitical/{country_iso3}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/GeopoliticalEvent"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/GeopoliticalResponseMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "GeopoliticalResponse",
        "type": "object"
      },
      "GeopoliticalResponseMeta": {
        "description": "Response metadata for a country query.",
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "country": {
            "$ref": "#/components/schemas/GeopoliticalCountryMeta"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End date filter applied.",
            "title": "End Date"
          },
          "event_type_filter": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Event type filter applied, if any.",
            "title": "Event Type Filter"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live GDELT API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of rows in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start date filter applied.",
            "title": "Start Date"
          },
          "total": {
            "description": "Total rows matching the query.",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "country",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_date",
          "end_date",
          "event_type_filter",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "GeopoliticalResponseMeta",
        "type": "object"
      },
      "HKMACatalogueEntry": {
        "description": "A single entry in the HKMA series catalogue.",
        "properties": {
          "description": {
            "title": "Description",
            "type": "string"
          },
          "frequency": {
            "title": "Frequency",
            "type": "string"
          },
          "series_id": {
            "title": "Series Id",
            "type": "string"
          },
          "unit": {
            "title": "Unit",
            "type": "string"
          }
        },
        "required": [
          "series_id",
          "description",
          "frequency",
          "unit"
        ],
        "title": "HKMACatalogueEntry",
        "type": "object"
      },
      "HKMACatalogueResponse": {
        "description": "Response for GET /v1/macro/hk/series.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/HKMACatalogueEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "HKMACatalogueResponse",
        "type": "object"
      },
      "HKMAObservation": {
        "description": "A single HKMA time-series observation.",
        "properties": {
          "frequency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Data frequency: daily | monthly.",
            "title": "Frequency"
          },
          "observation_date": {
            "description": "Date of observation.",
            "format": "date",
            "title": "Observation Date",
            "type": "string"
          },
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unit of measurement.",
            "title": "Unit"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Observation value. Null if unreleased or not available.",
            "title": "Value"
          }
        },
        "required": [
          "observation_date"
        ],
        "title": "HKMAObservation",
        "type": "object"
      },
      "HKMASeriesMeta": {
        "description": "Response metadata for an HKMA series query.",
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End date filter applied.",
            "title": "End Date"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live HKMA API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of observations in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "series_description": {
            "description": "Human-readable series description.",
            "title": "Series Description",
            "type": "string"
          },
          "series_id": {
            "description": "Logical series identifier (HKMA_*).",
            "title": "Series Id",
            "type": "string"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start date filter applied.",
            "title": "Start Date"
          },
          "total": {
            "description": "Total observations matching the query.",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "series_id",
          "series_description",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_date",
          "end_date",
          "computed_at",
          "disclaimer",
          "disclaimer_fr",
          "source",
          "license"
        ],
        "title": "HKMASeriesMeta",
        "type": "object"
      },
      "HKMASeriesResponse": {
        "description": "Response for GET /v1/macro/hk/{series_id}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/HKMAObservation"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/HKMASeriesMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "HKMASeriesResponse",
        "type": "object"
      },
      "HNCatalogMeta": {
        "description": "Metadata for the catalog endpoint.",
        "properties": {
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total_keywords": {
            "title": "Total Keywords",
            "type": "integer"
          }
        },
        "required": [
          "total_keywords",
          "source",
          "disclaimer"
        ],
        "title": "HNCatalogMeta",
        "type": "object"
      },
      "HNCatalogResponse": {
        "description": "Envelope for GET /v1/news/hn/catalog.",
        "properties": {
          "keywords": {
            "items": {
              "type": "string"
            },
            "title": "Keywords",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/HNCatalogMeta"
          }
        },
        "required": [
          "keywords",
          "meta"
        ],
        "title": "HNCatalogResponse",
        "type": "object"
      },
      "HNResponse": {
        "description": "Envelope for GET /v1/news/hn.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/HNStory"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/HNResponseMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "HNResponse",
        "type": "object"
      },
      "HNResponseMeta": {
        "description": "Response metadata envelope.",
        "properties": {
          "computed_at": {
            "description": "UTC ISO timestamp of query execution.",
            "title": "Computed At",
            "type": "string"
          },
          "disclaimer": {
            "description": "Disclaimer (EN).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Avertissement (FR).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "has_next": {
            "description": "True if more rows exist beyond this page.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True if served from dev/seed data. None if no rows present.",
            "title": "Is Dev Dataset"
          },
          "keyword": {
            "description": "Keyword filter applied.",
            "title": "Keyword",
            "type": "string"
          },
          "license": {
            "description": "License / redistribution terms.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size requested.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-based).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of rows in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "since": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start date filter applied.",
            "title": "Since"
          },
          "source": {
            "description": "Attribution string.",
            "title": "Source",
            "type": "string"
          },
          "total": {
            "description": "Total matching rows in DB.",
            "title": "Total",
            "type": "integer"
          },
          "until": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End date filter applied.",
            "title": "Until"
          }
        },
        "required": [
          "keyword",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "HNResponseMeta",
        "type": "object"
      },
      "HNStory": {
        "description": "Single HN story snapshot.",
        "properties": {
          "author": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "HN submitter username.",
            "title": "Author"
          },
          "created_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Original HN submission timestamp (UTC).",
            "title": "Created At"
          },
          "hn_id": {
            "description": "Hacker News story ID (objectID from Algolia).",
            "title": "Hn Id",
            "type": "string"
          },
          "matched_keyword": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Keyword query that returned this story.",
            "title": "Matched Keyword"
          },
          "num_comments": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Comment count at snapshot time.",
            "title": "Num Comments"
          },
          "points": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "HN karma score at snapshot time.",
            "title": "Points"
          },
          "snapshot_date": {
            "description": "Date this snapshot was fetched.",
            "format": "date",
            "title": "Snapshot Date",
            "type": "string"
          },
          "story_text": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Body text for Ask HN posts (may contain HTML).",
            "title": "Story Text"
          },
          "tags": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "Algolia _tags (e.g. story, ask_hn, front_page).",
            "title": "Tags"
          },
          "title": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Story title.",
            "title": "Title"
          },
          "url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Submitted URL. null for Ask HN / jobs.",
            "title": "Url"
          }
        },
        "required": [
          "hn_id",
          "snapshot_date"
        ],
        "title": "HNStory",
        "type": "object"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "title": "Detail",
            "type": "array"
          }
        },
        "title": "HTTPValidationError",
        "type": "object"
      },
      "HalalBoardSignupRequest": {
        "properties": {
          "consent": {
            "title": "Consent",
            "type": "boolean"
          },
          "email": {
            "format": "email",
            "title": "Email",
            "type": "string"
          },
          "language": {
            "default": "fr",
            "enum": [
              "fr",
              "en"
            ],
            "title": "Language",
            "type": "string"
          }
        },
        "required": [
          "email",
          "consent"
        ],
        "title": "HalalBoardSignupRequest",
        "type": "object"
      },
      "HodlWaveBucket": {
        "description": "Single HODL wave age bucket.\n\nEach bucket represents the BTC supply last moved within a given age range.\nThese are factual on-chain aggregates \u2014 not financial advice.\nMethodology: methodology/onchain-realized-metrics-v1.0.md \u00a77.",
        "properties": {
          "realized_value_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Realized value USD of UTXOs in this bucket (supply * price at last move).",
            "title": "Realized Value Usd"
          },
          "supply_btc": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "BTC supply in this age bucket (satoshis converted to BTC).",
            "title": "Supply Btc"
          },
          "supply_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Percentage of circulating supply in this age bucket (0-100).",
            "title": "Supply Pct"
          }
        },
        "title": "HodlWaveBucket",
        "type": "object"
      },
      "IdentifierData": {
        "properties": {
          "bbg_ticker": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Bloomberg ticker, e.g. 'AAPL US Equity'",
            "title": "Bbg Ticker"
          },
          "composite_figi": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Composite FIGI (country-level)",
            "title": "Composite Figi"
          },
          "cusip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "CUSIP \u2014 US/CA instruments only. NULL for EU/Asia.",
            "title": "Cusip"
          },
          "exchange_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "OpenFIGI exchCode, e.g. 'UW', 'LN', 'GR'",
            "title": "Exchange Code"
          },
          "figi": {
            "description": "Bloomberg FIGI \u2014 12-char instrument-level identifier",
            "title": "Figi",
            "type": "string"
          },
          "isin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 6166 ISIN \u2014 if returned by OpenFIGI (not always present)",
            "title": "Isin"
          },
          "listing_venue": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 10383 MIC of primary listing venue",
            "title": "Listing Venue"
          },
          "market_sector": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "OpenFIGI market sector: Equity|Comdty|Curncy|Corp|...",
            "title": "Market Sector"
          },
          "security_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "OpenFIGI security type: Common Stock|ETP|ADR|...",
            "title": "Security Type"
          },
          "sedol": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "SEDOL \u2014 UK/IE instruments only. NULL for non-LSE.",
            "title": "Sedol"
          },
          "share_class_figi": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Share Class FIGI (global)",
            "title": "Share Class Figi"
          },
          "ticker": {
            "description": "Ticker symbol as stored in portfolIQ hub_asset",
            "title": "Ticker",
            "type": "string"
          },
          "wkn": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "WKN (Wertpapierkennnummer) \u2014 German instruments only.",
            "title": "Wkn"
          }
        },
        "required": [
          "ticker",
          "figi"
        ],
        "title": "IdentifierData",
        "type": "object"
      },
      "IdentifierMeta": {
        "properties": {
          "attribution": {
            "default": "Bloomberg OpenFIGI \u2014 openfigi.com",
            "title": "Attribution",
            "type": "string"
          },
          "disclaimer": {
            "default": "Not financial advice. Not a fatwa. Methodology disclosed.",
            "title": "Disclaimer",
            "type": "string"
          },
          "fetched_at": {
            "description": "ISO 8601 timestamp",
            "title": "Fetched At",
            "type": "string"
          },
          "license_note": {
            "default": "FIGI is an open standard. Redistribution permitted per OpenFIGI ToS.",
            "title": "License Note",
            "type": "string"
          },
          "served_from": {
            "description": "'db_cache' | 'openfigi_live'",
            "title": "Served From",
            "type": "string"
          },
          "source": {
            "default": "openfigi.com (Bloomberg)",
            "title": "Source",
            "type": "string"
          },
          "source_url": {
            "default": "https://www.openfigi.com/api",
            "title": "Source Url",
            "type": "string"
          },
          "ttl_hours": {
            "default": 168,
            "title": "Ttl Hours",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "fetched_at",
          "served_from"
        ],
        "title": "IdentifierMeta",
        "type": "object"
      },
      "IdentifierResponse": {
        "properties": {
          "data": {
            "$ref": "#/components/schemas/IdentifierData"
          },
          "meta": {
            "$ref": "#/components/schemas/IdentifierMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "IdentifierResponse",
        "type": "object"
      },
      "ImfCountriesResponse": {
        "description": "Response for GET /v1/macro/imf/countries.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/ImfCountryEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "ImfCountriesResponse",
        "type": "object"
      },
      "ImfCountryEntry": {
        "description": "A single country entry in the countries catalogue.",
        "properties": {
          "iso3": {
            "title": "Iso3",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          }
        },
        "required": [
          "iso3",
          "name"
        ],
        "title": "ImfCountryEntry",
        "type": "object"
      },
      "ImfCountryMeta": {
        "description": "Country metadata embedded in response.",
        "properties": {
          "iso3": {
            "description": "ISO 3166-1 alpha-3 country code.",
            "title": "Iso3",
            "type": "string"
          },
          "name": {
            "description": "Country name.",
            "title": "Name",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "iso3",
          "name"
        ],
        "title": "ImfCountryMeta",
        "type": "object"
      },
      "ImfIndicatorEntry": {
        "description": "A single indicator entry in the indicators catalogue.",
        "properties": {
          "code": {
            "title": "Code",
            "type": "string"
          },
          "dataset": {
            "title": "Dataset",
            "type": "string"
          },
          "description": {
            "title": "Description",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "unit": {
            "title": "Unit",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "unit",
          "description",
          "dataset"
        ],
        "title": "ImfIndicatorEntry",
        "type": "object"
      },
      "ImfIndicatorMeta": {
        "description": "Indicator metadata embedded in response.",
        "properties": {
          "code": {
            "description": "IMF WEO indicator code.",
            "title": "Code",
            "type": "string"
          },
          "dataset": {
            "description": "IMF dataset code (e.g. 'WEO').",
            "title": "Dataset",
            "type": "string"
          },
          "name": {
            "description": "Human-readable indicator name.",
            "title": "Name",
            "type": "string"
          },
          "unit": {
            "description": "Unit of measurement.",
            "title": "Unit",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "unit",
          "dataset"
        ],
        "title": "ImfIndicatorMeta",
        "type": "object"
      },
      "ImfIndicatorsResponse": {
        "description": "Response for GET /v1/macro/imf/indicators.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/ImfIndicatorEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "dataset": {
            "title": "Dataset",
            "type": "string"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "dataset",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "ImfIndicatorsResponse",
        "type": "object"
      },
      "ImfObservation": {
        "description": "A single IMF WEO annual observation.",
        "properties": {
          "period": {
            "description": "Observation period. Annual: '2023'. Quarterly (future): '2023Q1'.",
            "title": "Period",
            "type": "string"
          },
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unit of measurement (%, USD billions, index, etc.).",
            "title": "Unit"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Observation value. Null if not available for this country/period.",
            "title": "Value"
          }
        },
        "required": [
          "period"
        ],
        "title": "ImfObservation",
        "type": "object"
      },
      "ImfSeriesMeta": {
        "description": "Response metadata for a country/indicator query.",
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "country": {
            "$ref": "#/components/schemas/ImfCountryMeta"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End period filter applied.",
            "title": "End Period"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "indicator": {
            "$ref": "#/components/schemas/ImfIndicatorMeta"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live IMF DataMapper API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of observations in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start period filter applied.",
            "title": "Start Period"
          },
          "total": {
            "description": "Total observations matching the query.",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "country",
          "indicator",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_period",
          "end_period",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "ImfSeriesMeta",
        "type": "object"
      },
      "ImfSeriesResponse": {
        "description": "Response for GET /v1/macro/imf/{country_iso3}/{indicator_code}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/ImfObservation"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ImfSeriesMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ImfSeriesResponse",
        "type": "object"
      },
      "IndexConstituentsMeta": {
        "description": "Response metadata for the constituents endpoint.",
        "properties": {
          "coverage_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Coverage Pct"
          },
          "data_source_summary": {
            "title": "Data Source Summary",
            "type": "string"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "freshness_ts": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Freshness Ts"
          },
          "has_next": {
            "title": "Has Next",
            "type": "boolean"
          },
          "index_code": {
            "title": "Index Code",
            "type": "string"
          },
          "snapshot_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Snapshot Date"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          },
          "wikidata_qid": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Wikidata Qid"
          }
        },
        "required": [
          "version",
          "index_code",
          "total",
          "has_next",
          "data_source_summary",
          "disclaimer"
        ],
        "title": "IndexConstituentsMeta",
        "type": "object"
      },
      "IndexConstituentsResponse": {
        "description": "Envelope for GET /v1/catalog/index/{index_code}/constituents.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/ConstituentItem"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/IndexConstituentsMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "IndexConstituentsResponse",
        "type": "object"
      },
      "InstrumentEtf": {
        "description": "ETF instrument metadata response schema (T-450).\n\nExtends InstrumentBase with ETF-specific structural fields and the four\nHS-blocking fields (brief \u00a74.2 \u2014 exposed raw, no fiqh verdict from PIQ).\n\nIMPORTANT: replication_method='synthetic_swap' is automatically classified\nharam by HalalStack. PIQ does NOT make this verdict \u2014 it exposes raw data only.\nFactual data only. Not financial advice. Not a fatwa. Methodology disclosed.",
        "properties": {
          "asset_id": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Asset Id"
          },
          "asset_kind": {
            "default": "etf",
            "title": "Asset Kind",
            "type": "string"
          },
          "aum_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Aum Usd"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Currency"
          },
          "distribution_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Distribution Type"
          },
          "domicile": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Domicile"
          },
          "fund_size_eur": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fund Size Eur"
          },
          "inception_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Inception Date"
          },
          "index_tracked": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Index Tracked"
          },
          "isin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isin"
          },
          "islamic_certifier": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Islamic Certifier"
          },
          "issuer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Issuer"
          },
          "last_updated": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Updated"
          },
          "listing_venue": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Listing Venue"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "nav_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nav Date"
          },
          "nav_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nav Usd"
          },
          "replication_method": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Replication Method"
          },
          "securities_lending": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Securities Lending"
          },
          "securities_lending_revenue_share": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Securities Lending Revenue Share"
          },
          "share_class": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Share Class"
          },
          "symbol": {
            "title": "Symbol",
            "type": "string"
          },
          "ter_bps": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ter Bps"
          },
          "ucits": {
            "default": false,
            "title": "Ucits",
            "type": "boolean"
          }
        },
        "required": [
          "symbol"
        ],
        "title": "InstrumentEtf",
        "type": "object"
      },
      "InstrumentEtfList": {
        "description": "List item schema \u2014 lighter payload for ETF search results (T-451).",
        "properties": {
          "asset_id": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Asset Id"
          },
          "asset_kind": {
            "default": "etf",
            "title": "Asset Kind",
            "type": "string"
          },
          "distribution_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Distribution Type"
          },
          "domicile": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Domicile"
          },
          "isin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isin"
          },
          "issuer": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Issuer"
          },
          "listing_venue": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Listing Venue"
          },
          "replication_method": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Replication Method"
          },
          "symbol": {
            "title": "Symbol",
            "type": "string"
          },
          "ter_bps": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ter Bps"
          }
        },
        "required": [
          "symbol"
        ],
        "title": "InstrumentEtfList",
        "type": "object"
      },
      "InstrumentStock": {
        "description": "Stock metadata response schema.\n\nPopulated from:\n  - dv.hub_asset (asset_id, symbol, asset_kind)\n  - dv.sat_stock_enriched (mig 064): company_name, listing_venue, isin,\n    sector, country, fiscal_year_end, figi (nullable), share_class\n  - dv.sat_stock_fundamentals (mig 048): market_cap_usd snapshot\n\nWave 1 nullable fields (v1): price_usd, market_cap_usd, pe_rolling_12m.\nWave 3 will add: marketCapAvg24m, nonPermissibleRevenue (HS DJIM screening).\nPIQ neutral: no halal ratios here \u2014 those are computed on HS side from raw inputs.",
        "properties": {
          "asset_id": {
            "title": "Asset Id",
            "type": "integer"
          },
          "asset_kind": {
            "default": "stock",
            "title": "Asset Kind",
            "type": "string"
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country"
          },
          "figi": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Figi"
          },
          "fiscal_year_end": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fiscal Year End"
          },
          "isin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isin"
          },
          "last_updated": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Updated"
          },
          "listing_venue": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Listing Venue"
          },
          "market_cap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Market Cap Usd"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "pe_rolling_12m": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pe Rolling 12M"
          },
          "price_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Usd"
          },
          "sector": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sector"
          },
          "share_class": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Share Class"
          },
          "symbol": {
            "title": "Symbol",
            "type": "string"
          }
        },
        "required": [
          "asset_id",
          "symbol",
          "name",
          "listing_venue",
          "isin",
          "sector",
          "country",
          "fiscal_year_end",
          "figi",
          "share_class",
          "last_updated"
        ],
        "title": "InstrumentStock",
        "type": "object"
      },
      "KrxEodMeta": {
        "description": "Response metadata for a KRX EOD query.",
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End date filter applied (ISO 8601).",
            "title": "End Date"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live KRX open data portal. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "listing_venue": {
            "default": "XKRX",
            "description": "MIC code for KRX.",
            "title": "Listing Venue",
            "type": "string"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of records in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start date filter applied (ISO 8601).",
            "title": "Start Date"
          },
          "ticker": {
            "description": "KRX 6-digit ticker code.",
            "title": "Ticker",
            "type": "string"
          },
          "total": {
            "description": "Total EOD records matching the query.",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "ticker",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_date",
          "end_date",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "KrxEodMeta",
        "type": "object"
      },
      "KrxEodRecord": {
        "description": "A single KRX EOD price record.",
        "properties": {
          "close_krw": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Closing price in KRW.",
            "title": "Close Krw"
          },
          "currency": {
            "default": "KRW",
            "description": "Currency (always KRW).",
            "title": "Currency",
            "type": "string"
          },
          "high_krw": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Daily high price in KRW.",
            "title": "High Krw"
          },
          "low_krw": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Daily low price in KRW.",
            "title": "Low Krw"
          },
          "observation_date": {
            "description": "Trading date (ISO 8601).",
            "format": "date",
            "title": "Observation Date",
            "type": "string"
          },
          "open_krw": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opening price in KRW (South Korean Won).",
            "title": "Open Krw"
          },
          "volume": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Number of shares traded.",
            "title": "Volume"
          }
        },
        "required": [
          "observation_date"
        ],
        "title": "KrxEodRecord",
        "type": "object"
      },
      "KrxEodResponse": {
        "description": "Response for GET /v1/stock/{ticker}/krx-eod.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/KrxEodRecord"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/KrxEodMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "KrxEodResponse",
        "type": "object"
      },
      "LegalEntityAddress": {
        "properties": {
          "city": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "City"
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country"
          },
          "postal_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Postal Code"
          },
          "region": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Region"
          },
          "street": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Street"
          }
        },
        "title": "LegalEntityAddress",
        "type": "object"
      },
      "LegalEntityData": {
        "properties": {
          "category": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Entity category (GENERAL, BRANCH, FUND, ...)",
            "title": "Category"
          },
          "headquarters": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/LegalEntityAddress"
              },
              {
                "type": "null"
              }
            ]
          },
          "hierarchy": {
            "$ref": "#/components/schemas/LegalEntityHierarchy"
          },
          "legal_address": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/LegalEntityAddress"
              },
              {
                "type": "null"
              }
            ]
          },
          "legal_form": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Legal form name, e.g. 'Corporation', 'SA'",
            "title": "Legal Form"
          },
          "legal_form_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ELF code",
            "title": "Legal Form Code"
          },
          "legal_jurisdiction": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 3166-2 jurisdiction code, e.g. 'US-CA', 'FR'",
            "title": "Legal Jurisdiction"
          },
          "legal_name": {
            "description": "Official legal name",
            "title": "Legal Name",
            "type": "string"
          },
          "lei": {
            "description": "ISO 17442 LEI code (20 chars)",
            "title": "Lei",
            "type": "string"
          },
          "other_names": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "Trade names, previous names",
            "title": "Other Names"
          },
          "registration": {
            "$ref": "#/components/schemas/LegalEntityRegistration"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ACTIVE | INACTIVE | LAPSED",
            "title": "Status"
          }
        },
        "required": [
          "lei",
          "legal_name",
          "registration",
          "hierarchy"
        ],
        "title": "LegalEntityData",
        "type": "object"
      },
      "LegalEntityHierarchy": {
        "properties": {
          "direct_parent_lei": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "LEI of direct parent entity",
            "title": "Direct Parent Lei"
          },
          "is_top_of_hierarchy": {
            "description": "True if entity has no parent (ultimate_parent_lei is NULL or equals own LEI)",
            "title": "Is Top Of Hierarchy",
            "type": "boolean"
          },
          "ultimate_parent_lei": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "LEI of ultimate parent entity",
            "title": "Ultimate Parent Lei"
          }
        },
        "required": [
          "is_top_of_hierarchy"
        ],
        "title": "LegalEntityHierarchy",
        "type": "object"
      },
      "LegalEntityMeta": {
        "properties": {
          "attribution": {
            "default": "Global Legal Entity Identifier Foundation (GLEIF) \u2014 gleif.org",
            "title": "Attribution",
            "type": "string"
          },
          "fetched_at": {
            "description": "ISO 8601 timestamp of response",
            "title": "Fetched At",
            "type": "string"
          },
          "license": {
            "default": "CC0",
            "title": "License",
            "type": "string"
          },
          "served_from": {
            "description": "'db_cache' or 'gleif_live'",
            "title": "Served From",
            "type": "string"
          },
          "source": {
            "default": "GLEIF",
            "title": "Source",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "fetched_at",
          "served_from"
        ],
        "title": "LegalEntityMeta",
        "type": "object"
      },
      "LegalEntityRegistration": {
        "properties": {
          "issued_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Initial LEI registration date (ISO 8601)",
            "title": "Issued Date"
          },
          "last_updated": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Last GLEIF data update date",
            "title": "Last Updated"
          },
          "next_renewal": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Next renewal date",
            "title": "Next Renewal"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISSUED | LAPSED | CANCELLED | ...",
            "title": "Status"
          }
        },
        "title": "LegalEntityRegistration",
        "type": "object"
      },
      "LegalEntityResponse": {
        "properties": {
          "data": {
            "$ref": "#/components/schemas/LegalEntityData"
          },
          "meta": {
            "$ref": "#/components/schemas/LegalEntityMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "LegalEntityResponse",
        "type": "object"
      },
      "LegalEntitySearchResponse": {
        "properties": {
          "count": {
            "title": "Count",
            "type": "integer"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/LegalEntitySearchResult"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/LegalEntityMeta"
          }
        },
        "required": [
          "data",
          "meta",
          "count"
        ],
        "title": "LegalEntitySearchResponse",
        "type": "object"
      },
      "LegalEntitySearchResult": {
        "properties": {
          "category": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Category"
          },
          "legal_jurisdiction": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Legal Jurisdiction"
          },
          "legal_name": {
            "title": "Legal Name",
            "type": "string"
          },
          "lei": {
            "title": "Lei",
            "type": "string"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Status"
          }
        },
        "required": [
          "lei",
          "legal_name"
        ],
        "title": "LegalEntitySearchResult",
        "type": "object"
      },
      "ListResponse": {
        "properties": {
          "subscriptions": {
            "items": {
              "$ref": "#/components/schemas/WebhookSubscription"
            },
            "title": "Subscriptions",
            "type": "array"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "subscriptions",
          "total"
        ],
        "title": "ListResponse",
        "type": "object"
      },
      "LoginRequest": {
        "description": "Body for POST /auth/login.",
        "properties": {
          "email": {
            "format": "email",
            "title": "Email",
            "type": "string"
          },
          "password": {
            "title": "Password",
            "type": "string"
          }
        },
        "required": [
          "email",
          "password"
        ],
        "title": "LoginRequest",
        "type": "object"
      },
      "LseEodBar": {
        "properties": {
          "close_gbp": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Closing price in GBP",
            "title": "Close Gbp"
          },
          "currency": {
            "default": "GBP",
            "description": "Currency of price fields (always GBP)",
            "title": "Currency",
            "type": "string"
          },
          "high_gbp": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Daily high price in GBP",
            "title": "High Gbp"
          },
          "low_gbp": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Daily low price in GBP",
            "title": "Low Gbp"
          },
          "observation_date": {
            "description": "Trading date (ISO 8601 date)",
            "title": "Observation Date",
            "type": "string"
          },
          "open_gbp": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opening price in GBP",
            "title": "Open Gbp"
          },
          "volume": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Shares traded",
            "title": "Volume"
          }
        },
        "required": [
          "observation_date"
        ],
        "title": "LseEodBar",
        "type": "object"
      },
      "LseEodData": {
        "properties": {
          "bars": {
            "description": "EOD price bars, most recent first",
            "items": {
              "$ref": "#/components/schemas/LseEodBar"
            },
            "title": "Bars",
            "type": "array"
          },
          "listing_venue": {
            "default": "XLON",
            "description": "Listing venue",
            "title": "Listing Venue",
            "type": "string"
          },
          "ticker": {
            "description": "Asset ticker (XLON)",
            "title": "Ticker",
            "type": "string"
          }
        },
        "required": [
          "ticker",
          "bars"
        ],
        "title": "LseEodData",
        "type": "object"
      },
      "LseEodMeta": {
        "properties": {
          "attribution": {
            "default": "Prices sourced from London Stock Exchange (delayed 15 min). \u00a9 London Stock Exchange Group plc. Not for real-time trading.",
            "title": "Attribution",
            "type": "string"
          },
          "count": {
            "description": "Number of bars returned",
            "title": "Count",
            "type": "integer"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "delay_minutes": {
            "default": 15,
            "title": "Delay Minutes",
            "type": "integer"
          },
          "fetched_at": {
            "description": "ISO 8601 timestamp of this response",
            "title": "Fetched At",
            "type": "string"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed. False when sourced from live LSE delayed CSV. None = unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "default": "LSE Open Data 2024+",
            "title": "License",
            "type": "string"
          },
          "record_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Seed record source identifier. e.g. 'curated_lse_delayed_2026-05-26' or 'lse_delayed_csv_<date>'",
            "title": "Record Source"
          },
          "served_from": {
            "default": "db_cache",
            "title": "Served From",
            "type": "string"
          },
          "source": {
            "default": "London Stock Exchange",
            "title": "Source",
            "type": "string"
          }
        },
        "required": [
          "fetched_at",
          "count"
        ],
        "title": "LseEodMeta",
        "type": "object"
      },
      "LseEodResponse": {
        "properties": {
          "data": {
            "$ref": "#/components/schemas/LseEodData"
          },
          "meta": {
            "$ref": "#/components/schemas/LseEodMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "LseEodResponse",
        "type": "object"
      },
      "MacroCalendarMeta": {
        "description": "Response metadata.",
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "from_date": {
            "description": "Start date filter applied.",
            "format": "date",
            "title": "From Date",
            "type": "string"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of events in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "sources": {
            "description": "Data sources: Federal Reserve, ECB, BLS, BEA.",
            "items": {
              "type": "string"
            },
            "title": "Sources",
            "type": "array"
          },
          "to_date": {
            "description": "End date filter applied.",
            "format": "date",
            "title": "To Date",
            "type": "string"
          },
          "total": {
            "description": "Total events matching the query (before pagination).",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "description": "API version (semver).",
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "from_date",
          "to_date",
          "computed_at",
          "disclaimer",
          "disclaimer_fr",
          "sources"
        ],
        "title": "MacroCalendarMeta",
        "type": "object"
      },
      "MacroCalendarResponse": {
        "description": "Response for GET /v1/macro/calendar.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/MacroEvent"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/MacroCalendarMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "MacroCalendarResponse",
        "type": "object"
      },
      "MacroEvent": {
        "description": "A single macro-economic calendar event.",
        "properties": {
          "actual": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Actual published value (if available, null if future).",
            "title": "Actual"
          },
          "country": {
            "description": "ISO-2 country code: US, EU, GB, ...",
            "title": "Country",
            "type": "string"
          },
          "currency_impact": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO-4217 currency most impacted.",
            "title": "Currency Impact"
          },
          "event_category": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Category: monetary_policy | labor | inflation | gdp | trade | treasury.",
            "title": "Event Category"
          },
          "event_date_utc": {
            "description": "Event date in UTC.",
            "format": "date",
            "title": "Event Date Utc",
            "type": "string"
          },
          "event_id": {
            "description": "UUID stable identifier for this event.",
            "title": "Event Id",
            "type": "string"
          },
          "event_name": {
            "description": "Human-readable event name.",
            "title": "Event Name",
            "type": "string"
          },
          "event_time_utc": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Event time in UTC (HH:MM:SS) if known, null otherwise.",
            "title": "Event Time Utc"
          },
          "forecast": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Consensus forecast (if available).",
            "title": "Forecast"
          },
          "importance": {
            "description": "Editorial importance: high | medium | low.",
            "title": "Importance",
            "type": "string"
          },
          "previous": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Previous period value (if available).",
            "title": "Previous"
          },
          "source": {
            "description": "Data source: fed_fomc | ecb | bls | bea | treasury.",
            "title": "Source",
            "type": "string"
          }
        },
        "required": [
          "event_id",
          "source",
          "event_date_utc",
          "country",
          "event_name",
          "importance"
        ],
        "title": "MacroEvent",
        "type": "object"
      },
      "MacroRegimeResponse": {
        "description": "Response payload for GET /v1/analytics/macro-regime.",
        "properties": {
          "as_of": {
            "description": "Date of the latest macro observation.",
            "format": "date",
            "title": "As Of",
            "type": "string"
          },
          "confidence": {
            "description": "Confidence score 0\u2013100 (deterministic, based on rule strength).",
            "maximum": 100.0,
            "minimum": 0.0,
            "title": "Confidence",
            "type": "integer"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          },
          "methodology_version": {
            "default": "macro-regime-v1.0",
            "title": "Methodology Version",
            "type": "string"
          },
          "rationale": {
            "description": "Human-readable explanation (factual, methodology-disclosed).",
            "title": "Rationale",
            "type": "string"
          },
          "regime": {
            "enum": [
              "risk_on",
              "risk_off",
              "stagflation_risk",
              "deflation_risk",
              "neutral"
            ],
            "title": "Regime",
            "type": "string"
          },
          "signals": {
            "$ref": "#/components/schemas/MacroRegimeSignals"
          }
        },
        "required": [
          "regime",
          "confidence",
          "rationale",
          "signals",
          "as_of",
          "meta"
        ],
        "title": "MacroRegimeResponse",
        "type": "object"
      },
      "MacroRegimeSignals": {
        "description": "Underlying signals feeding the regime classifier.",
        "properties": {
          "fed_funds_rate": {
            "description": "DFF \u2014 Federal Funds Effective Rate (%).",
            "title": "Fed Funds Rate",
            "type": "number"
          },
          "sp500_1y_chg_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "S&P 500 1-year change (%).",
            "title": "Sp500 1Y Chg Pct"
          },
          "sp500_30d_chg_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "S&P 500 30-day change (%).",
            "title": "Sp500 30D Chg Pct"
          },
          "sp500_90d_chg_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "S&P 500 90-day change (%).",
            "title": "Sp500 90D Chg Pct"
          },
          "usd_eur_latest": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "USD per EUR (proxy DXY direction).",
            "title": "Usd Eur Latest"
          },
          "vix_latest": {
            "description": "Latest CBOE VIX value.",
            "title": "Vix Latest",
            "type": "number"
          },
          "vix_p75_1y": {
            "description": "75th percentile of VIX over trailing 365 days.",
            "title": "Vix P75 1Y",
            "type": "number"
          },
          "yield_spread_10y_2y": {
            "description": "DGS10 - DGS2 (percentage points). Negative = inverted curve.",
            "title": "Yield Spread 10Y 2Y",
            "type": "number"
          }
        },
        "required": [
          "vix_latest",
          "vix_p75_1y",
          "yield_spread_10y_2y",
          "fed_funds_rate",
          "sp500_30d_chg_pct",
          "sp500_90d_chg_pct",
          "sp500_1y_chg_pct"
        ],
        "title": "MacroRegimeSignals",
        "type": "object"
      },
      "MeExportResponse": {
        "description": "Response for GET /auth/me/export \u2014 RGPD Art. 15 + Art. 20 full data export.\n\nSEC-AUDIT-P1S2-005 Sprint 35.\nTICKET-747 Sprint 97 \u2014 schema_version bumped to 1.1 (halal_positions added).\nJSON download attachment with all personal data associated with the account.",
        "properties": {
          "api_keys": {
            "items": {
              "$ref": "#/components/schemas/ExportApiKeyInfo"
            },
            "title": "Api Keys",
            "type": "array"
          },
          "audit_logs": {
            "items": {
              "$ref": "#/components/schemas/ExportAuditLogEntry"
            },
            "title": "Audit Logs",
            "type": "array"
          },
          "billing": {
            "$ref": "#/components/schemas/ExportBillingInfo"
          },
          "consents": {
            "$ref": "#/components/schemas/ExportConsentInfo"
          },
          "email_events": {
            "items": {
              "$ref": "#/components/schemas/ExportEmailEvent"
            },
            "title": "Email Events",
            "type": "array"
          },
          "exported_at": {
            "title": "Exported At",
            "type": "string"
          },
          "halal_positions": {
            "default": [],
            "items": {
              "$ref": "#/components/schemas/ExportHalalPosition"
            },
            "title": "Halal Positions",
            "type": "array"
          },
          "objections": {
            "items": {
              "$ref": "#/components/schemas/ExportObjection"
            },
            "title": "Objections",
            "type": "array"
          },
          "profile": {
            "additionalProperties": true,
            "title": "Profile",
            "type": "object"
          },
          "schema_version": {
            "default": "1.1",
            "title": "Schema Version",
            "type": "string"
          },
          "sql_credentials": {
            "items": {
              "$ref": "#/components/schemas/ExportSqlCredential"
            },
            "title": "Sql Credentials",
            "type": "array"
          }
        },
        "required": [
          "exported_at",
          "profile",
          "api_keys",
          "billing",
          "email_events",
          "audit_logs",
          "sql_credentials",
          "consents",
          "objections"
        ],
        "title": "MeExportResponse",
        "type": "object"
      },
      "MeResponse": {
        "description": "Response for GET /auth/me.",
        "properties": {
          "created_at": {
            "title": "Created At",
            "type": "string"
          },
          "email": {
            "title": "Email",
            "type": "string"
          },
          "id": {
            "title": "Id",
            "type": "string"
          },
          "keys": {
            "items": {
              "$ref": "#/components/schemas/ApiKeyInfo"
            },
            "title": "Keys",
            "type": "array"
          },
          "stripe_customer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stripe Customer Id"
          },
          "tier": {
            "title": "Tier",
            "type": "string"
          }
        },
        "required": [
          "id",
          "email",
          "tier",
          "stripe_customer_id",
          "created_at",
          "keys"
        ],
        "title": "MeResponse",
        "type": "object"
      },
      "MetalsSpot": {
        "description": "Optional caller-supplied metals spot prices (USD per gram).",
        "properties": {
          "gold_usd_per_gram": {
            "description": "Gold spot price in USD per gram.",
            "exclusiveMinimum": 0.0,
            "title": "Gold Usd Per Gram",
            "type": "number"
          },
          "silver_usd_per_gram": {
            "description": "Silver spot price in USD per gram.",
            "exclusiveMinimum": 0.0,
            "title": "Silver Usd Per Gram",
            "type": "number"
          }
        },
        "required": [
          "gold_usd_per_gram",
          "silver_usd_per_gram"
        ],
        "title": "MetalsSpot",
        "type": "object"
      },
      "NewsArticle": {
        "description": "Single news mention item returned by the API.\n\ntitle is intentionally absent \u2014 EU droit voisin presse (Directive 2019/790 art. 15).\nOnly the AI-generated short summary (ai_summary_short) may be exposed.",
        "properties": {
          "ai_summary_short": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "AI-generated 2-4 sentence transformative summary. ai_generated=true by construction. Not financial advice. Methodology disclosed.",
            "title": "Ai Summary Short"
          },
          "article_hk": {
            "description": "Stable article hash key (BK = SHA-256 of article_url).",
            "title": "Article Hk",
            "type": "string"
          },
          "mention_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "news_mention_sk surrogate key from fact_news_mention.",
            "title": "Mention Id"
          },
          "mentioned_tokens": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "Tokens mentioned in this article (coingecko_id slugs extracted by NER). Note: raw schema \u2014 not {entity, type, confidence} objects.",
            "title": "Mentioned Tokens"
          },
          "published_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "UTC publication timestamp.",
            "title": "Published At"
          },
          "sentiment_label": {
            "default": "neutral",
            "description": "Categorical sentiment: negative | neutral | positive.",
            "title": "Sentiment Label",
            "type": "string"
          },
          "sentiment_score": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "AI-generated sentiment score in [-1, 1]. null if NER not processed.",
            "title": "Sentiment Score"
          },
          "source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Editorial source name (e.g. 'CoinDesk', 'Reuters').",
            "title": "Source"
          },
          "source_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Source type (wire | newspaper | blog | regulator). Not yet available in dim_news_source \u2014 reserved for future enrichment.",
            "title": "Source Type"
          },
          "url": {
            "description": "Canonical article URL.",
            "title": "Url",
            "type": "string"
          }
        },
        "required": [
          "article_hk",
          "url"
        ],
        "title": "NewsArticle",
        "type": "object"
      },
      "NewsMeta": {
        "description": "Response metadata envelope.",
        "properties": {
          "asset_kind": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Asset Kind"
          },
          "count": {
            "title": "Count",
            "type": "integer"
          },
          "disclaimer": {
            "default": "Factual data only. Not financial advice. Not a fatwa. Methodology disclosed.",
            "title": "Disclaimer",
            "type": "string"
          },
          "listing_venue": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Listing Venue"
          },
          "since": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Since"
          },
          "symbol": {
            "title": "Symbol",
            "type": "string"
          },
          "total_available": {
            "title": "Total Available",
            "type": "integer"
          },
          "until": {
            "title": "Until",
            "type": "string"
          }
        },
        "required": [
          "symbol",
          "count",
          "until",
          "total_available"
        ],
        "title": "NewsMeta",
        "type": "object"
      },
      "NewsResponse": {
        "description": "Envelope for GET /v1/news/{symbol}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/NewsArticle"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/NewsMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "NewsResponse",
        "type": "object"
      },
      "NewsletterIssuePreview": {
        "description": "Response payload for generate-preview endpoint.",
        "properties": {
          "catalysts_found": {
            "description": "Actual number of catalysts found (may be < 10 if data is sparse).",
            "title": "Catalysts Found",
            "type": "integer"
          },
          "generated_at": {
            "format": "date-time",
            "title": "Generated At",
            "type": "string"
          },
          "issue_date": {
            "format": "date",
            "title": "Issue Date",
            "type": "string"
          },
          "issue_id": {
            "title": "Issue Id",
            "type": "integer"
          },
          "status": {
            "enum": [
              "draft",
              "preview",
              "sent",
              "failed"
            ],
            "title": "Status",
            "type": "string"
          },
          "subject_line": {
            "title": "Subject Line",
            "type": "string"
          },
          "top_catalysts": {
            "items": {
              "$ref": "#/components/schemas/CatalystItem"
            },
            "title": "Top Catalysts",
            "type": "array"
          }
        },
        "required": [
          "issue_id",
          "issue_date",
          "subject_line",
          "top_catalysts",
          "status",
          "generated_at",
          "catalysts_found"
        ],
        "title": "NewsletterIssuePreview",
        "type": "object"
      },
      "NewsletterSendResponse": {
        "description": "Response payload for the manual send endpoint.",
        "properties": {
          "issue_date": {
            "format": "date",
            "title": "Issue Date",
            "type": "string"
          },
          "issue_id": {
            "title": "Issue Id",
            "type": "integer"
          },
          "message": {
            "title": "Message",
            "type": "string"
          },
          "provider": {
            "description": "Email provider used (resend|brevo|mailgun|log_fallback).",
            "title": "Provider",
            "type": "string"
          },
          "recipients_count": {
            "title": "Recipients Count",
            "type": "integer"
          },
          "sent_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sent At"
          },
          "status": {
            "enum": [
              "draft",
              "preview",
              "sent",
              "failed"
            ],
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "issue_id",
          "issue_date",
          "status",
          "sent_at",
          "recipients_count",
          "provider",
          "message"
        ],
        "title": "NewsletterSendResponse",
        "type": "object"
      },
      "ObjectToProcessingRequest": {
        "description": "Body for POST /auth/me/object-to-processing.\n\nRGPD Art. 21: right to object to processing based on legitimate interest.\nApplies to processing categories: security_logs, cloudflare_logs, marketing.\n\n- marketing: disables user_email_preferences.subscribed (all marketing emails)\n- security_logs / cloudflare_logs: records declarative flag in user_objections\n  (security logs are retained for system integrity; behavioural analysis disabled)",
        "properties": {
          "processing_category": {
            "title": "Processing Category",
            "type": "string"
          }
        },
        "required": [
          "processing_category"
        ],
        "title": "ObjectToProcessingRequest",
        "type": "object"
      },
      "ObjectToProcessingResponse": {
        "description": "Response for POST /auth/me/object-to-processing.",
        "properties": {
          "message": {
            "title": "Message",
            "type": "string"
          },
          "processing_category": {
            "title": "Processing Category",
            "type": "string"
          },
          "status": {
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "status",
          "processing_category",
          "message"
        ],
        "title": "ObjectToProcessingResponse",
        "type": "object"
      },
      "OecdCountriesResponse": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/OecdCountryEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "OecdCountriesResponse",
        "type": "object"
      },
      "OecdCountryEntry": {
        "properties": {
          "iso3": {
            "title": "Iso3",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          }
        },
        "required": [
          "iso3",
          "name"
        ],
        "title": "OecdCountryEntry",
        "type": "object"
      },
      "OecdCountryMeta": {
        "properties": {
          "iso3": {
            "description": "ISO 3166-1 alpha-3 country code.",
            "title": "Iso3",
            "type": "string"
          },
          "name": {
            "description": "Country name.",
            "title": "Name",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "iso3",
          "name"
        ],
        "title": "OecdCountryMeta",
        "type": "object"
      },
      "OecdIndicatorEntry": {
        "properties": {
          "code": {
            "title": "Code",
            "type": "string"
          },
          "description": {
            "title": "Description",
            "type": "string"
          },
          "frequency": {
            "title": "Frequency",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "unit": {
            "title": "Unit",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "unit",
          "description",
          "frequency"
        ],
        "title": "OecdIndicatorEntry",
        "type": "object"
      },
      "OecdIndicatorMeta": {
        "properties": {
          "code": {
            "description": "Our logical OECD indicator code.",
            "title": "Code",
            "type": "string"
          },
          "frequency": {
            "description": "Data frequency: annual, quarterly, or monthly.",
            "title": "Frequency",
            "type": "string"
          },
          "name": {
            "description": "Human-readable indicator name.",
            "title": "Name",
            "type": "string"
          },
          "unit": {
            "description": "Unit of measurement.",
            "title": "Unit",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "unit",
          "frequency"
        ],
        "title": "OecdIndicatorMeta",
        "type": "object"
      },
      "OecdIndicatorsResponse": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/OecdIndicatorEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "OecdIndicatorsResponse",
        "type": "object"
      },
      "OecdObservation": {
        "description": "A single OECD macro observation.",
        "properties": {
          "period": {
            "description": "Observation period. Format depends on indicator frequency: '2024' (annual), '2024-Q3' (quarterly), '2024-11' (monthly).",
            "title": "Period",
            "type": "string"
          },
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unit of measurement (%, USD_millions, index, etc.).",
            "title": "Unit"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Observation value. Null if not available for this period.",
            "title": "Value"
          }
        },
        "required": [
          "period"
        ],
        "title": "OecdObservation",
        "type": "object"
      },
      "OecdSeriesMeta": {
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "country": {
            "$ref": "#/components/schemas/OecdCountryMeta"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "indicator": {
            "$ref": "#/components/schemas/OecdIndicatorMeta"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live OECD Stats API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of observations in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "total": {
            "description": "Total observations matching the query.",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "country",
          "indicator",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "OecdSeriesMeta",
        "type": "object"
      },
      "OecdSeriesResponse": {
        "description": "Response for GET /v1/macro/oecd/{country_iso3}/{indicator_code}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/OecdObservation"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/OecdSeriesMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "OecdSeriesResponse",
        "type": "object"
      },
      "OhlcvCandle": {
        "description": "Single daily OHLCV candle.\n\nopen/high/low are populated when ohlc_source='consensus' (sat_asset_ohlcv_consensus).\nThey are NULL when ohlc_source='vwap_close_only' (VWAP fallback \u2014 candle not yet\ncovered by OHLC consensus backfill, or intraday bougie non-cl\u00f4tur\u00e9e).\nNot financial advice. Factual market data.",
        "properties": {
          "candle_date": {
            "description": "Date of the candle (UTC close).",
            "format": "date",
            "title": "Candle Date",
            "type": "string"
          },
          "close_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Close price USD. Always populated when a candle exists.",
            "title": "Close Usd"
          },
          "exchanges_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Number of exchanges contributing to this candle (MAR transparency).",
            "title": "Exchanges Count"
          },
          "high_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "High price USD. NULL when ohlc_source='vwap_close_only'.",
            "title": "High Usd"
          },
          "low_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Low price USD. NULL when ohlc_source='vwap_close_only'.",
            "title": "Low Usd"
          },
          "ohlc_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "OHLC completeness indicator: 'consensus' (full open/high/low/close from sat_asset_ohlcv_consensus) or 'vwap_close_only' (close/vwap only \u2014 open/high/low are NULL).",
            "title": "Ohlc Source"
          },
          "open_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Open price USD. NULL when ohlc_source='vwap_close_only' (VWAP fallback \u2014 OHLC consensus not yet available for this candle).",
            "title": "Open Usd"
          },
          "source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Top-level data source: always 'vwap_consensus' (portfolIQ derived).",
            "title": "Source"
          },
          "volume_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total volume in USD across VWAP consensus exchanges.",
            "title": "Volume Usd"
          },
          "vwap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Volume-weighted average price USD. Computed from >= 3 exchange sources (COMITE-004). Methodology: methodology/vwap-consensus-v1.1.md. Not financial advice. Factual derived metric.",
            "title": "Vwap Usd"
          }
        },
        "required": [
          "candle_date"
        ],
        "title": "OhlcvCandle",
        "type": "object"
      },
      "OhlcvMeta": {
        "description": "Metadata for OHLCV responses \u2014 includes timeframe info (T-846).",
        "properties": {
          "notice": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable notice when served_timeframe differs from requested_timeframe.",
            "title": "Notice"
          },
          "requested_timeframe": {
            "description": "Timeframe requested by the client.",
            "title": "Requested Timeframe",
            "type": "string"
          },
          "served_timeframe": {
            "description": "Timeframe actually served (may differ if requested TF unavailable).",
            "title": "Served Timeframe",
            "type": "string"
          }
        },
        "required": [
          "requested_timeframe",
          "served_timeframe"
        ],
        "title": "OhlcvMeta",
        "type": "object"
      },
      "OhlcvRecord": {
        "description": "A single OHLCV record.",
        "properties": {
          "asset_hk": {
            "description": "Asset identifier (surrogate key).",
            "title": "Asset Hk",
            "type": "string"
          },
          "bucket_ts": {
            "description": "Candle date (day bucket for all TF).",
            "format": "date",
            "title": "Bucket Ts",
            "type": "string"
          },
          "close_price": {
            "anyOf": [
              {
                "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Close price.",
            "title": "Close Price"
          },
          "high_price": {
            "anyOf": [
              {
                "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "High price.",
            "title": "High Price"
          },
          "low_price": {
            "anyOf": [
              {
                "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Low price.",
            "title": "Low Price"
          },
          "open_price": {
            "anyOf": [
              {
                "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Open price.",
            "title": "Open Price"
          },
          "source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Data source identifier.",
            "title": "Source"
          },
          "timeframe": {
            "description": "Timeframe of this record (1h, 4h, 1d, 1w, 1M).",
            "title": "Timeframe",
            "type": "string"
          },
          "venue_hk": {
            "description": "Venue identifier (exchange/source surrogate key).",
            "title": "Venue Hk",
            "type": "string"
          },
          "volume": {
            "anyOf": [
              {
                "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Volume.",
            "title": "Volume"
          },
          "vwap": {
            "anyOf": [
              {
                "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "VWAP (available for 1d only).",
            "title": "Vwap"
          }
        },
        "required": [
          "asset_hk",
          "venue_hk",
          "bucket_ts",
          "timeframe"
        ],
        "title": "OhlcvRecord",
        "type": "object"
      },
      "OnchainMetricsResponse": {
        "description": "BTC on-chain realized metrics response.\n\nMetrics computed from bigquery-public-data.crypto_bitcoin (MIT licence).\nGrain: last available metric_date (LIMIT 1 DESC).\nCurrently available for Bitcoin (BTC) only.\n\nFactual descriptive metrics only. Not financial advice. Methodology disclosed.\nRequires scope: onchain:read (Growth tier and above).",
        "properties": {
          "asset_id": {
            "description": "Stable integer surrogate key for the asset (D-063).",
            "title": "Asset Id",
            "type": "integer"
          },
          "circulating_supply_btc": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Circulating supply in BTC derived from UTXO set.",
            "title": "Circulating Supply Btc"
          },
          "disclaimer": {
            "default": "Not financial advice. Not a fatwa. Methodology disclosed. Factual descriptive metrics only.",
            "description": "Mandatory AMF disclaimer. Always present in every response.",
            "title": "Disclaimer",
            "type": "string"
          },
          "hodl_waves": {
            "anyOf": [
              {
                "additionalProperties": {
                  "$ref": "#/components/schemas/HodlWaveBucket"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "HODL waves: distribution of BTC supply by age of last on-chain move. 10 age buckets (e.g. '1d', '1w', '1m', '3m', '6m', '1y', '2y', '3y', '5y', '5y+'). Factual UTXO age distribution. Not financial advice. Methodology disclosed.",
            "title": "Hodl Waves"
          },
          "market_cap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Market Cap USD: circulating supply * spot price at metric_date.",
            "title": "Market Cap Usd"
          },
          "methodology_version": {
            "description": "Methodology version used for this computation (e.g. 'onchain-realized-metrics-v1.0').",
            "title": "Methodology Version",
            "type": "string"
          },
          "metric_date": {
            "description": "Date of the on-chain metrics snapshot (UTC).",
            "format": "date",
            "title": "Metric Date",
            "type": "string"
          },
          "mvrv_ratio": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "MVRV ratio: Market Cap / Realized Cap. Factual ratio of market valuation to on-chain cost basis. Descriptive metric only \u2014 not financial advice. Methodology disclosed.",
            "title": "Mvrv Ratio"
          },
          "nupl": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Net Unrealized Profit/Loss (NUPL): (Market Cap - Realized Cap) / Market Cap. Factual aggregate of unrealized gains/losses in the UTXO set. Descriptive metric only \u2014 not financial advice. Methodology disclosed.",
            "title": "Nupl"
          },
          "price_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "BTC price source used for Realized Cap computation (e.g. 'kraken_csv', 'vwap_consensus', 'no_market'). Internal use \u2014 documents data lineage.",
            "title": "Price Source"
          },
          "realized_cap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Realized Cap USD: sum of each UTXO's value at its last transaction price. Factual aggregate of on-chain cost basis. Methodology: onchain-realized-metrics-v1.0.md \u00a73. Not financial advice.",
            "title": "Realized Cap Usd"
          },
          "realized_price_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Realized Price USD: Realized Cap / circulating supply. Average on-chain cost basis per BTC. Factual descriptive metric. Not financial advice.",
            "title": "Realized Price Usd"
          },
          "sopr": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Spent Output Profit Ratio (SOPR): ratio of value at spend / value at creation for all outputs spent on metric_date. Factual aggregate of on-chain transaction outcomes. Descriptive metric only \u2014 not financial advice. Methodology disclosed.",
            "title": "Sopr"
          }
        },
        "required": [
          "asset_id",
          "metric_date",
          "methodology_version"
        ],
        "title": "OnchainMetricsResponse",
        "type": "object"
      },
      "PortalResponse": {
        "description": "Successful customer portal session response.",
        "properties": {
          "portal_url": {
            "title": "Portal Url",
            "type": "string"
          }
        },
        "required": [
          "portal_url"
        ],
        "title": "PortalResponse",
        "type": "object"
      },
      "ProtocolSummary": {
        "description": "A single protocol entry for the list endpoint.",
        "properties": {
          "category": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "DeFi category.",
            "title": "Category"
          },
          "chain": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Primary chain.",
            "title": "Chain"
          },
          "display_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable protocol name.",
            "title": "Display Name"
          },
          "latest_snapshot_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Date of the most recent TVL snapshot in the DB.",
            "title": "Latest Snapshot Date"
          },
          "mcap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Latest market cap in USD.",
            "title": "Mcap Usd"
          },
          "slug": {
            "description": "DeFiLlama protocol slug.",
            "title": "Slug",
            "type": "string"
          },
          "tvl_change_24h_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Latest 24h TVL change in percent.",
            "title": "Tvl Change 24H Pct"
          },
          "tvl_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Latest TVL in USD.",
            "title": "Tvl Usd"
          }
        },
        "required": [
          "slug",
          "display_name",
          "latest_snapshot_date",
          "tvl_usd",
          "tvl_change_24h_pct",
          "mcap_usd",
          "chain",
          "category"
        ],
        "title": "ProtocolSummary",
        "type": "object"
      },
      "ProtocolsListMeta": {
        "description": "Metadata for GET /v1/defi/protocols.",
        "properties": {
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Data Quality"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "fetched_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Fetched At",
            "type": "string"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Dev Dataset"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "description": "Total number of protocols returned.",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "total",
          "fetched_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "ProtocolsListMeta",
        "type": "object"
      },
      "ProtocolsListResponse": {
        "description": "Response for GET /v1/defi/protocols.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/ProtocolSummary"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/ProtocolsListMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ProtocolsListResponse",
        "type": "object"
      },
      "RegisterAck": {
        "description": "202 Accepted response for POST /auth/register.\n\nT-395 Sprint 27 \u2014 anti-enumeration: always return 202 regardless of whether\nthe email is already registered. The actual account creation / \"already registered\"\nemail is dispatched as a background task.",
        "properties": {
          "message": {
            "default": "If this email is not registered, you will receive a confirmation email.",
            "title": "Message",
            "type": "string"
          }
        },
        "title": "RegisterAck",
        "type": "object"
      },
      "RegisterRequest": {
        "description": "Body for POST /auth/register.",
        "properties": {
          "consent_marketing": {
            "default": false,
            "title": "Consent Marketing",
            "type": "boolean"
          },
          "email": {
            "format": "email",
            "title": "Email",
            "type": "string"
          },
          "marketing_optin": {
            "default": false,
            "description": "RGPD opt-in marketing \u2014 persisted directly on api.users.marketing_optin (migration 042). DEFAULT False = no pre-consent (RGPD art.7). Payloads without this field are treated as False (r\u00e9trocompat).",
            "title": "Marketing Optin",
            "type": "boolean"
          },
          "password": {
            "title": "Password",
            "type": "string"
          }
        },
        "required": [
          "email",
          "password"
        ],
        "title": "RegisterRequest",
        "type": "object"
      },
      "ResendWebhookEvent": {
        "properties": {
          "event_type": {
            "pattern": "^email\\.(delivered|bounced|complained)$",
            "title": "Event Type",
            "type": "string"
          },
          "resend_id": {
            "title": "Resend Id",
            "type": "string"
          },
          "to_email": {
            "title": "To Email",
            "type": "string"
          }
        },
        "required": [
          "event_type",
          "resend_id",
          "to_email"
        ],
        "title": "ResendWebhookEvent",
        "type": "object"
      },
      "ResetPasswordRequest": {
        "description": "Body for POST /auth/reset-password.\n\ntoken: raw URL-safe token received via the reset email link\nnew_password: new password (min 8 characters)",
        "properties": {
          "new_password": {
            "title": "New Password",
            "type": "string"
          },
          "token": {
            "title": "Token",
            "type": "string"
          }
        },
        "required": [
          "token",
          "new_password"
        ],
        "title": "ResetPasswordRequest",
        "type": "object"
      },
      "ResetPasswordResponse": {
        "description": "Response for POST /auth/reset-password.",
        "properties": {
          "message": {
            "title": "Message",
            "type": "string"
          },
          "status": {
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "status",
          "message"
        ],
        "title": "ResetPasswordResponse",
        "type": "object"
      },
      "RestatementCreateRequest": {
        "description": "Body for POST /{snapshot_id}/restate.\n\napprover is extracted from the JWT (not in the body).",
        "properties": {
          "original_snapshot_id": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "raw.ai_analysis_runs.id of the snapshot being superseded. Omit when there is no prior snapshot to reference.",
            "title": "Original Snapshot Id"
          },
          "restatement_reason": {
            "description": "Human-readable audit reason for the restatement (minimum 10 chars).",
            "minLength": 10,
            "title": "Restatement Reason",
            "type": "string"
          }
        },
        "required": [
          "restatement_reason"
        ],
        "title": "RestatementCreateRequest",
        "type": "object"
      },
      "RestatementListResponse": {
        "description": "Paginated response for GET /restatements.",
        "properties": {
          "items": {
            "description": "Most-recent restatements first.",
            "items": {
              "$ref": "#/components/schemas/RestatementResponse"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opaque cursor for the next page. None when no further results.",
            "title": "Next Cursor"
          },
          "total_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total rows matching the query (best-effort, may be approximate).",
            "title": "Total Count"
          }
        },
        "title": "RestatementListResponse",
        "type": "object"
      },
      "RestatementResponse": {
        "description": "Response for a single restatement audit row.",
        "properties": {
          "approver": {
            "description": "Email or login of the human approver (extracted from JWT).",
            "title": "Approver",
            "type": "string"
          },
          "created_at": {
            "description": "UTC timestamp of the audit row insertion.",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "disclaimer": {
            "default": "Not financial advice. Not a fatwa. Methodology disclosed.",
            "description": "Mandatory AMF disclaimer.",
            "title": "Disclaimer",
            "type": "string"
          },
          "id": {
            "description": "Bigserial PK of dv.sat_ai_restatement_audit.",
            "title": "Id",
            "type": "integer"
          },
          "original_snapshot_id": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "raw.ai_analysis_runs.id of the superseded snapshot, if any.",
            "title": "Original Snapshot Id"
          },
          "restatement_reason": {
            "description": "Audit trail reason.",
            "title": "Restatement Reason",
            "type": "string"
          },
          "snapshot_id": {
            "description": "raw.ai_analysis_runs.id of the new/replacement snapshot.",
            "title": "Snapshot Id",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "snapshot_id",
          "restatement_reason",
          "approver",
          "created_at"
        ],
        "title": "RestatementResponse",
        "type": "object"
      },
      "RevokeKeyResponse": {
        "description": "Response for POST /auth/keys/{id}/revoke.",
        "properties": {
          "key_id": {
            "title": "Key Id",
            "type": "string"
          },
          "status": {
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "status",
          "key_id"
        ],
        "title": "RevokeKeyResponse",
        "type": "object"
      },
      "SanctionsData": {
        "properties": {
          "checked_at": {
            "description": "ISO 8601 timestamp of the cached screening result (load_ts)",
            "title": "Checked At",
            "type": "string"
          },
          "is_sanctioned": {
            "description": "True if entity appears on at least one sanctions list as of checked_at. False = clear at time of screening. Always check checked_at for staleness.",
            "title": "Is Sanctioned",
            "type": "boolean"
          },
          "last_listed_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Most recent listing date (ISO 8601 date). Null if not sanctioned.",
            "title": "Last Listed Date"
          },
          "legal_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Legal name from hub/sat (if available)",
            "title": "Legal Name"
          },
          "lei": {
            "description": "ISO 17442 LEI code (20 chars)",
            "title": "Lei",
            "type": "string"
          },
          "opensanctions_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "OpenSanctions entity ID (NK-xxx pattern). Null if OpenSanctions could not match this entity. Deep-link: https://www.opensanctions.org/entities/{id}/",
            "title": "Opensanctions Id"
          },
          "risk_score": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Risk score 0.00-100.00 (null if not provided by OpenSanctions). Do not treat null as low-risk \u2014 it means score was unavailable.",
            "title": "Risk Score"
          },
          "sanction_programs": {
            "description": "Specific sanction programs. Examples: ['IRAN-EO13599', 'RUSSIA-EO14024']",
            "items": {
              "type": "string"
            },
            "title": "Sanction Programs",
            "type": "array"
          },
          "sanctions_lists": {
            "description": "Sanctions lists on which entity appears. Empty list when is_sanctioned=false. Examples: ['OFAC SDN', 'EU CFSP', 'UK HMT', 'UN Security Council']",
            "items": {
              "type": "string"
            },
            "title": "Sanctions Lists",
            "type": "array"
          }
        },
        "required": [
          "lei",
          "is_sanctioned",
          "checked_at"
        ],
        "title": "SanctionsData",
        "type": "object"
      },
      "SanctionsMeta": {
        "properties": {
          "attribution": {
            "default": "Sanctions data sourced from OpenSanctions (opensanctions.org), licensed under CC-BY 4.0.",
            "title": "Attribution",
            "type": "string"
          },
          "disclaimer": {
            "default": "Sanctions data is provided for informational purposes only. It is NOT a substitute for licensed compliance services. PortfolIQ is not a licensed compliance vendor. Users must perform their own KYC/AML due diligence for regulated activities.",
            "title": "Disclaimer",
            "type": "string"
          },
          "fetched_at": {
            "description": "ISO 8601 timestamp of this API response",
            "title": "Fetched At",
            "type": "string"
          },
          "license": {
            "default": "CC-BY 4.0",
            "title": "License",
            "type": "string"
          },
          "lists_covered": {
            "items": {
              "type": "string"
            },
            "title": "Lists Covered",
            "type": "array"
          },
          "source": {
            "default": "OpenSanctions",
            "title": "Source",
            "type": "string"
          }
        },
        "required": [
          "fetched_at"
        ],
        "title": "SanctionsMeta",
        "type": "object"
      },
      "SanctionsResponse": {
        "properties": {
          "data": {
            "$ref": "#/components/schemas/SanctionsData"
          },
          "meta": {
            "$ref": "#/components/schemas/SanctionsMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "SanctionsResponse",
        "type": "object"
      },
      "SecFilingItem": {
        "properties": {
          "accession_number": {
            "title": "Accession Number",
            "type": "string"
          },
          "cik": {
            "title": "Cik",
            "type": "string"
          },
          "filing_date": {
            "format": "date",
            "title": "Filing Date",
            "type": "string"
          },
          "filing_type": {
            "title": "Filing Type",
            "type": "string"
          },
          "load_ts": {
            "format": "date-time",
            "title": "Load Ts",
            "type": "string"
          },
          "net_income_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Net income USD (null in MVP Sprint 96). Sprint 97+.",
            "title": "Net Income Usd"
          },
          "period_end_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period End Date"
          },
          "primary_document_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Primary Document Url"
          },
          "sections_extracted": {
            "anyOf": [
              {},
              {
                "type": "null"
              }
            ],
            "description": "Structured sections (null in MVP Sprint 96). Sprint 97+.",
            "title": "Sections Extracted"
          },
          "total_assets_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total assets USD (null in MVP Sprint 96). Sprint 97+.",
            "title": "Total Assets Usd"
          },
          "total_revenue_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total revenue USD (null in MVP Sprint 96). Sprint 97+.",
            "title": "Total Revenue Usd"
          }
        },
        "required": [
          "cik",
          "accession_number",
          "filing_type",
          "filing_date",
          "load_ts"
        ],
        "title": "SecFilingItem",
        "type": "object"
      },
      "SecFilingMeta": {
        "properties": {
          "disclaimer": {
            "default": "Factual data only. Not financial advice. Not a fatwa. Methodology disclosed.",
            "title": "Disclaimer",
            "type": "string"
          },
          "generated_at": {
            "format": "date-time",
            "title": "Generated At",
            "type": "string"
          },
          "source": {
            "default": "sec_edgar_submissions_v1",
            "title": "Source",
            "type": "string"
          }
        },
        "required": [
          "generated_at"
        ],
        "title": "SecFilingMeta",
        "type": "object"
      },
      "SecFilingResponse": {
        "properties": {
          "cik": {
            "title": "Cik",
            "type": "string"
          },
          "count": {
            "title": "Count",
            "type": "integer"
          },
          "filing_type": {
            "title": "Filing Type",
            "type": "string"
          },
          "filings": {
            "items": {
              "$ref": "#/components/schemas/SecFilingItem"
            },
            "title": "Filings",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/SecFilingMeta"
          }
        },
        "required": [
          "cik",
          "filing_type",
          "count",
          "filings",
          "meta"
        ],
        "title": "SecFilingResponse",
        "type": "object"
      },
      "SireneData": {
        "properties": {
          "activite_principale_naf": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "NAF/APE activity code (Nomenclature des Activit\u00e9s Fran\u00e7aises). French equivalent of SIC/NAICS. Example: 6419Z = Autres interm\u00e9diations mon\u00e9taires.",
            "title": "Activite Principale Naf"
          },
          "adresse_siege": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "Headquarter address as JSONB object. Keys: numero_voie, type_voie, libelle_voie, code_postal, libelle_commune, code_commune, pays_etranger.",
            "title": "Adresse Siege"
          },
          "annee_effectifs": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Reference year for tranche_effectifs",
            "title": "Annee Effectifs"
          },
          "categorie_juridique": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "INSEE legal category code. Examples: 5710=SA, 5720=SAS, 5800=SE (Societas Europaea), 5202=SCA, 1000=Entrepreneur individuel.",
            "title": "Categorie Juridique"
          },
          "date_creation_unite_legale": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Date of incorporation (ISO 8601 date)",
            "title": "Date Creation Unite Legale"
          },
          "denomination_unite_legale": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Official legal denomination of the unit\u00e9 l\u00e9gale",
            "title": "Denomination Unite Legale"
          },
          "etat_administratif": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Administrative status: A=Actif (active), C=Cess\u00e9 (ceased)",
            "title": "Etat Administratif"
          },
          "libelle_activite_principale": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable NAF activity label",
            "title": "Libelle Activite Principale"
          },
          "libelle_categorie_juridique": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable legal category label (e.g. 'Soci\u00e9t\u00e9 anonyme')",
            "title": "Libelle Categorie Juridique"
          },
          "nic_siege": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "NIC (Num\u00e9ro Interne de Classement) of si\u00e8ge social (5 chars)",
            "title": "Nic Siege"
          },
          "sigle_unite_legale": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Commercial short name / acronym (sigle)",
            "title": "Sigle Unite Legale"
          },
          "siren": {
            "description": "9-digit SIRENE identifier (SIREN of unit\u00e9 l\u00e9gale)",
            "title": "Siren",
            "type": "string"
          },
          "siret_siege": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "SIRET of registered headquarter (SIREN + NIC, 14 chars)",
            "title": "Siret Siege"
          },
          "tranche_effectifs": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "INSEE employee size band code. Examples: 11=0-9, 22=20-49, 43=200-249, 53=5000+, NN=non renseign\u00e9.",
            "title": "Tranche Effectifs"
          }
        },
        "required": [
          "siren"
        ],
        "title": "SireneData",
        "type": "object"
      },
      "SireneMeta": {
        "properties": {
          "api_version": {
            "default": "V3.11",
            "title": "Api Version",
            "type": "string"
          },
          "attribution": {
            "default": "Source: INSEE SIRENE \u2014 Etalab Open License 2.0 (equivalent CC-BY 4.0). https://www.sirene.fr/",
            "title": "Attribution",
            "type": "string"
          },
          "fetched_at": {
            "description": "ISO 8601 timestamp of this response",
            "title": "Fetched At",
            "type": "string"
          },
          "license": {
            "default": "Etalab Open License 2.0",
            "title": "License",
            "type": "string"
          },
          "record_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Seed record source identifier (e.g. 'insee_sirene_v3.11_2026-05-26')",
            "title": "Record Source"
          },
          "served_from": {
            "default": "db_cache",
            "title": "Served From",
            "type": "string"
          },
          "source": {
            "default": "INSEE SIRENE",
            "title": "Source",
            "type": "string"
          }
        },
        "required": [
          "fetched_at"
        ],
        "title": "SireneMeta",
        "type": "object"
      },
      "SireneResponse": {
        "properties": {
          "data": {
            "$ref": "#/components/schemas/SireneData"
          },
          "meta": {
            "$ref": "#/components/schemas/SireneMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "SireneResponse",
        "type": "object"
      },
      "SnapshotContent": {
        "description": "Content block for the latest AI analysis snapshot.",
        "properties": {
          "confidence": {
            "description": "Deterministic confidence score (COMITE-011 D3). NOT Claude self-report \u2014 computed from data completeness + source consensus.",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Confidence",
            "type": "number"
          },
          "key_claims": {
            "description": "Structured list of factual claims extracted from the analysis.",
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "title": "Key Claims",
            "type": "array"
          },
          "sentiment_score": {
            "anyOf": [
              {
                "maximum": 1.0,
                "minimum": -1.0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Sentiment score [-1.0, 1.0]. Factual aggregate \u2014 not a recommendation.",
            "title": "Sentiment Score"
          },
          "sources": {
            "description": "List of data sources used to generate this analysis.",
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "title": "Sources",
            "type": "array"
          },
          "summary": {
            "description": "AI-generated narrative summary. Factual only \u2014 no price target.",
            "title": "Summary",
            "type": "string"
          }
        },
        "required": [
          "summary",
          "confidence"
        ],
        "title": "SnapshotContent",
        "type": "object"
      },
      "SnapshotFreshness": {
        "description": "Freshness status block for the latest snapshot.",
        "properties": {
          "next_refresh_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "UTC deadline for the next refresh (tier-dependent).",
            "title": "Next Refresh At"
          },
          "status": {
            "description": "Freshness status: fresh | stale | expired.",
            "enum": [
              "fresh",
              "stale",
              "expired"
            ],
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "status"
        ],
        "title": "SnapshotFreshness",
        "type": "object"
      },
      "SnapshotImmutability": {
        "description": "Immutability block \u2014 content_hash is the portfolIQ moat.\n\ncontent_hash format: 'sha256:<64-hex>' or '' for pre-backfill rows.\nClients should test content_hash != '' before relying on immutability.",
        "properties": {
          "content_hash": {
            "description": "'sha256:<64-hex>' of canonical JSON, or '' for pre-backfill rows.",
            "title": "Content Hash",
            "type": "string"
          },
          "hash_algorithm": {
            "const": "sha256",
            "default": "sha256",
            "description": "Hash algorithm \u2014 always 'sha256'.",
            "title": "Hash Algorithm",
            "type": "string"
          },
          "signed": {
            "default": false,
            "description": "Whether the hash is cryptographically signed. Always false at current scale.",
            "title": "Signed",
            "type": "boolean"
          }
        },
        "required": [
          "content_hash"
        ],
        "title": "SnapshotImmutability",
        "type": "object"
      },
      "SnapshotProvenance": {
        "description": "Provenance block for the latest snapshot.\n\nMirrors AIAnalysisProvenanceSchema from ai_analysis.py but typed strictly\nfor the /latest response (non-optional fields required by the DB row).",
        "properties": {
          "data_window_from": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start of data window used to generate the analysis (UTC).",
            "title": "Data Window From"
          },
          "data_window_to": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End of data window used to generate the analysis (UTC).",
            "title": "Data Window To"
          },
          "input_tokens": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Input tokens billed for this generation.",
            "title": "Input Tokens"
          },
          "methodology_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable methodology label (e.g. 'market-context-v1.2'). ai:lineage only.",
            "title": "Methodology Version"
          },
          "model_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Anthropic model used (e.g. 'claude-haiku-4-5').",
            "title": "Model Id"
          },
          "output_tokens": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Output tokens billed for this generation.",
            "title": "Output Tokens"
          },
          "prompt_hash": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "sha256:<hex> of effective prompt \u2014 Growth (ai:lineage) only.",
            "title": "Prompt Hash"
          },
          "prompt_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opaque prompt version string from the prompt registry.",
            "title": "Prompt Version"
          }
        },
        "title": "SnapshotProvenance",
        "type": "object"
      },
      "SqlCredentialsCreateResponse": {
        "description": "Response for POST /v1/billing/sql-credentials.\n\nThe plaintext password is returned exactly once. It cannot be retrieved later.",
        "properties": {
          "database": {
            "description": "Database name",
            "title": "Database",
            "type": "string"
          },
          "expires_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Credential expiry timestamp. null = no expiry (revoke manually via DELETE).",
            "title": "Expires At"
          },
          "host": {
            "description": "PostgreSQL host for SQL access",
            "title": "Host",
            "type": "string"
          },
          "note": {
            "default": "Save this password \u2014 it cannot be retrieved later",
            "description": "Reminder that the password is shown only once.",
            "title": "Note",
            "type": "string"
          },
          "password": {
            "description": "Plaintext password \u2014 save it now, cannot be retrieved later",
            "title": "Password",
            "type": "string"
          },
          "port": {
            "description": "PostgreSQL port for SQL access",
            "title": "Port",
            "type": "integer"
          },
          "schema": {
            "description": "Schema to connect to (star_public)",
            "title": "Schema",
            "type": "string"
          },
          "username": {
            "description": "PostgreSQL login username (sql_user_<8chars>)",
            "title": "Username",
            "type": "string"
          }
        },
        "required": [
          "host",
          "port",
          "database",
          "schema",
          "username",
          "password"
        ],
        "title": "SqlCredentialsCreateResponse",
        "type": "object"
      },
      "SqlCredentialsListItem": {
        "description": "Item in the list response for GET /v1/billing/sql-credentials.\n\npassword_hash is intentionally absent \u2014 never returned by any endpoint.",
        "properties": {
          "created_at": {
            "description": "When this credential was provisioned",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "last_connected_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Last observed connection from this username (updated by Dagster monitor). null if never connected.",
            "title": "Last Connected At"
          },
          "pg_username": {
            "description": "PostgreSQL login username",
            "title": "Pg Username",
            "type": "string"
          }
        },
        "required": [
          "pg_username",
          "created_at"
        ],
        "title": "SqlCredentialsListItem",
        "type": "object"
      },
      "StockAIAnalysis": {
        "description": "AI analysis payload for a single stock ticker.\n\nPopulated by the LLM (Haiku 4.5 or Sonnet 4.6) using prompt v2.0-multi-asset.\nhalal_inputs_summary is only populated for analysis_type=halal_screening.\nNo halal verdict \u2014 PIQ exposes screening inputs only.\n\nDisclaimer: Not financial advice. Not a fatwa. Methodology disclosed.",
        "properties": {
          "analysis_type": {
            "description": "Analysis type: 'fundamental' | 'halal_screening' | 'sector_context'. Determines model routing and prompt section.",
            "title": "Analysis Type",
            "type": "string"
          },
          "generated_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "UTC timestamp of generation (or cache retrieval timestamp).",
            "title": "Generated At"
          },
          "halal_inputs_summary": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Summary of factual halal screening inputs (AAOIFI/DJIM ratios). Populated only for analysis_type='halal_screening'. PIQ exposes inputs only \u2014 no halal/haram verdict.",
            "title": "Halal Inputs Summary"
          },
          "key_metrics": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/StockKeyMetrics"
              },
              {
                "type": "null"
              }
            ],
            "description": "Key financial metrics extracted by the LLM. Null if not applicable."
          },
          "model_used": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Anthropic model used: 'claude-haiku-4-5' (default) or 'claude-sonnet-4-6' (for halal_screening or payload > 1800 tokens).",
            "title": "Model Used"
          },
          "prompt_version": {
            "default": "v2.0-multi-asset",
            "description": "Prompt version identifier for audit trail.",
            "title": "Prompt Version",
            "type": "string"
          },
          "summary": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "AI-generated 3-4 sentence factual summary. AMF guard: no price target, no investment recommendation. Null if generation failed.",
            "title": "Summary"
          },
          "ticker": {
            "description": "Stock ticker (uppercase, e.g. 'AAPL').",
            "title": "Ticker",
            "type": "string"
          }
        },
        "required": [
          "ticker",
          "analysis_type"
        ],
        "title": "StockAIAnalysis",
        "type": "object"
      },
      "StockBatchMeta": {
        "description": "Metadata envelope for batch response.",
        "properties": {
          "computed_at": {
            "format": "date-time",
            "title": "Computed At",
            "type": "string"
          },
          "data_quality": {
            "title": "Data Quality",
            "type": "string"
          },
          "disclaimer": {
            "default": "Factual data only. Not financial advice. Methodology disclosed.",
            "title": "Disclaimer",
            "type": "string"
          },
          "licensed_for_commercial_use": {
            "default": true,
            "title": "Licensed For Commercial Use",
            "type": "boolean"
          },
          "source_primary": {
            "default": "edgar:batch",
            "title": "Source Primary",
            "type": "string"
          },
          "total_found": {
            "title": "Total Found",
            "type": "integer"
          },
          "total_not_found": {
            "title": "Total Not Found",
            "type": "integer"
          },
          "total_requested": {
            "title": "Total Requested",
            "type": "integer"
          }
        },
        "required": [
          "total_requested",
          "total_found",
          "total_not_found",
          "computed_at",
          "data_quality"
        ],
        "title": "StockBatchMeta",
        "type": "object"
      },
      "StockBatchRequest": {
        "description": "Request body for POST /v1/instruments/stock/batch.\n\nMax 100 tickers per request \u2014 premium feature (tier: standard minimum).\nOptional field projection via `fields` (model_dump(include=...) \u2014 no dynamic SQL).",
        "example": {
          "fields": [
            "symbol",
            "name",
            "sector",
            "market_cap_usd"
          ],
          "tickers": [
            "AAPL",
            "MSFT",
            "GOOGL"
          ]
        },
        "properties": {
          "fields": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional field projection. If provided, only these fields are included in each result item. Valid values: symbol, name, listing_venue, isin, sector, country, fiscal_year_end, figi, price_usd, market_cap_usd.",
            "title": "Fields"
          },
          "tickers": {
            "description": "List of ticker symbols. Max 100. Each max 20 chars.",
            "items": {
              "type": "string"
            },
            "maxItems": 100,
            "minItems": 1,
            "title": "Tickers",
            "type": "array"
          }
        },
        "required": [
          "tickers"
        ],
        "title": "StockBatchRequest",
        "type": "object"
      },
      "StockBatchResponse": {
        "description": "Full batch response envelope for POST /v1/instruments/stock/batch.",
        "properties": {
          "data": {
            "items": {},
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/StockBatchMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "StockBatchResponse",
        "type": "object"
      },
      "StockCatalogItem": {
        "description": "Single stock item in catalog response.",
        "properties": {
          "country_iso2": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 3166-1 alpha-2 country code",
            "title": "Country Iso2"
          },
          "enrichment_level": {
            "default": "listing_only",
            "description": "Enrichment quality level: 'full' (EDGAR-enriched, name+ISIN+sector available) or 'listing_only' (ticker only, no metadata). Use ?enriched=true to filter to 'full' only.",
            "title": "Enrichment Level",
            "type": "string"
          },
          "exchange": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "MIC exchange code (e.g. XNAS, XNYS, XLON)",
            "title": "Exchange"
          },
          "industry_gics": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "GICS industry group name",
            "title": "Industry Gics"
          },
          "is_enriched": {
            "default": false,
            "description": "True if this ticker has been enriched via EDGAR (name, ISIN, sector available). False = listing_only (ticker exists in hub_asset but no sat_stock_enriched row). ~2163/2733 tickers are NOT enriched in prod as of Sprint 104.",
            "title": "Is Enriched",
            "type": "boolean"
          },
          "isin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISIN identifier (12 chars)",
            "title": "Isin"
          },
          "lei": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 17442 LEI (available for ~47 entities in prod)",
            "title": "Lei"
          },
          "market_cap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Market capitalisation in USD (NULL for most stocks \u2014 curated top 100 only)",
            "title": "Market Cap Usd"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Company name",
            "title": "Name"
          },
          "sector_gics": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "GICS sector name",
            "title": "Sector Gics"
          },
          "staleness_hours": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Hours elapsed since updated_at (NOW() - updated_at in hours, rounded to 2 decimal places). Null when updated_at is null (stock has no enrichment and no market cap record). CAVEAT: anchored on load_ts (technical timestamp, NOT a market close timestamp). Sensitive to dbt full-refresh \u2014 may reset to ~0 after a full satellite rebuild. NOT comparable to crypto staleness_hours (which is anchored on candle_ts). staleness_anchor field in meta.caveats describes this limitation explicitly.",
            "title": "Staleness Hours"
          },
          "ticker": {
            "description": "Exchange ticker symbol (e.g. AAPL)",
            "title": "Ticker",
            "type": "string"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 8601 timestamp of the last meaningful data change for this stock (GREATEST of enriched metadata change_ts and market_cap snapshot_month). CAVEAT: anchored on load_ts (technical timestamp, NOT a market close timestamp). Null for stocks with no enrichment and no market cap record.",
            "title": "Updated At"
          }
        },
        "required": [
          "ticker"
        ],
        "title": "StockCatalogItem",
        "type": "object"
      },
      "StockCatalogMeta": {
        "properties": {
          "cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opaque base64 keyset cursor (high-water mark of this page). Pass as ?since= in the next request to pull incremental changes. Present only when ?since= / ?updated_after= was used or a delta page was returned. None in full-list mode (no ?since= param).",
            "title": "Cursor"
          },
          "data_quality": {
            "enum": [
              "fresh",
              "partial",
              "empty"
            ],
            "title": "Data Quality",
            "type": "string"
          },
          "data_source": {
            "title": "Data Source",
            "type": "string"
          },
          "freshness": {
            "title": "Freshness",
            "type": "string"
          },
          "is_dev_dataset": {
            "title": "Is Dev Dataset",
            "type": "boolean"
          },
          "staleness_anchor": {
            "default": "load_ts (technical \u2014 not market close). Sensitive to full-refresh.",
            "description": "Describes the timestamp used to compute staleness_hours for stocks. Stocks have no intraday market close timestamp \u2014 staleness is anchored on load_ts (dbt insert timestamp), NOT on a market close candle_ts. NOT comparable to crypto staleness_hours (anchored on candle_ts). Sensitive to dbt full-refresh: a hard satellite rebuild resets load_ts to NOW().",
            "title": "Staleness Anchor",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "data_source",
          "freshness",
          "is_dev_dataset",
          "data_quality"
        ],
        "title": "StockCatalogMeta",
        "type": "object"
      },
      "StockCatalogPagination": {
        "properties": {
          "has_more": {
            "title": "Has More",
            "type": "boolean"
          },
          "limit": {
            "title": "Limit",
            "type": "integer"
          },
          "offset": {
            "title": "Offset",
            "type": "integer"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "total",
          "offset",
          "limit",
          "has_more"
        ],
        "title": "StockCatalogPagination",
        "type": "object"
      },
      "StockCatalogResponse": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/StockCatalogItem"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/StockCatalogMeta"
          },
          "pagination": {
            "$ref": "#/components/schemas/StockCatalogPagination"
          }
        },
        "required": [
          "data",
          "pagination",
          "meta"
        ],
        "title": "StockCatalogResponse",
        "type": "object"
      },
      "StockFundamentals": {
        "description": "Stock fundamentals response schema \u2014 brief HS \u00a74.1 DJIM inputs bruts.\n\nSprint 30 Lane R \u2014 T-480. Sprint 111 T-864: DJIM numerators now populated.\n\nPIQ fournit les num\u00e9rateurs/d\u00e9nominateurs bruts SANS calcul de ratios DJIM.\nLes ratios (totalInterestBearingDebt/marketCapAvg24m, etc.) sont calcul\u00e9s\nc\u00f4t\u00e9 HalalStack (D-070 arbitrage 2).\n\nSource: dv.sat_stock_fundamentals (dbt wide pivot view, Sprint 111 T-864).\nGrain: (asset_hk, period_end_date, filing_type, accession_number).\nmarketCapAvg24m: mart.mart_market_cap_avg_24m (dbt table, T-530).\nmarketCapCurrent: commonSharesOutstanding \u00d7 last_close_price (always None Wave 1 \u2014 no live price).\n\nColumns available in dbt view (Sprint 111):\n  asset_hk, period_end_date, filing_type, accession_number, cik,\n  revenue_usd, net_income_usd, total_assets_usd, total_liabilities_usd,\n  equity_usd, eps_basic, cash_equivalents_usd, total_debt_usd,\n  shares_outstanding, currency, load_ts, hashdiff, record_source.\n\nFields NOT available (always None):\n  - interestBearingSecurities (not in EDGAR XBRL pivot)\n  - accountsReceivableNet     (not in EDGAR XBRL pivot)\n  - marketCapCurrent          (no live price integration Wave 1)\n\nLEGAL: SEC EDGAR = public domain US (17 CFR \u00a7200.80). licensed_for_commercial_use = True.\nDISCLAIMER: Factual data only. Not financial advice. Not a fatwa. Methodology disclosed.",
        "properties": {
          "accountsReceivableNet": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Accountsreceivablenet"
          },
          "cashAndCashEquivalents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cashandcashequivalents"
          },
          "commonSharesOutstanding": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Commonsharesoutstanding"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Currency"
          },
          "epsBasic": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Epsbasic"
          },
          "equityUsd": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Equityusd"
          },
          "filing_standard": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Filing Standard"
          },
          "interestBearingSecurities": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Interestbearingsecurities"
          },
          "leaseLiabilitiesIfrs16": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "IFRS 16 lease liabilities \u2014 separate field, NEVER aggregated into total_debt. total_debt = financial debt excluding leases (scholar HS GATE-IFRS16-R3). EU assets only (mig 296 / T-895). Always null for US EDGAR assets. null = concept absent after cascade exhaustion. Doctrine D-154: null != 0.",
            "title": "Leaseliabilitiesifrs16"
          },
          "listing_venue": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Listing Venue"
          },
          "marketCapAvg24m": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Marketcapavg24M"
          },
          "marketCapCurrent": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Marketcapcurrent"
          },
          "netIncomeUsd": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Netincomeusd"
          },
          "nonPermissibleRevenue": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Nonpermissiblerevenue"
          },
          "period": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period"
          },
          "record_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Record Source"
          },
          "sharesOutstanding": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Shares outstanding (integer). Source: AMF Art. 223-16 (Etalab 2.0) for EU; EDGAR XBRL for US (commonSharesOutstanding). EU path: mig 296 shares_outstanding NUMERIC(20,0). null = declaration not yet available for this issuer. Doctrine D-154: null != 0.",
            "title": "Sharesoutstanding"
          },
          "ticker": {
            "title": "Ticker",
            "type": "string"
          },
          "totalAssets": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total assets \u2014 balance sheet total (IFRS ifrs-full:Assets). EU assets only (mig 296 / T-895). Always null for US EDGAR assets. null = concept absent or not yet captured. Doctrine D-154: null != 0. NOT financial advice. Methodology disclosed.",
            "title": "Totalassets"
          },
          "totalAssetsUsd": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Totalassetsusd"
          },
          "totalInterestBearingDebt": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Totalinterestbearingdebt"
          },
          "totalLiabilitiesUsd": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Totalliabilitiesusd"
          },
          "totalRevenue": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Totalrevenue"
          }
        },
        "required": [
          "ticker"
        ],
        "title": "StockFundamentals",
        "type": "object"
      },
      "StockKeyMetrics": {
        "description": "Key metrics extracted from the LLM response for a stock analysis.",
        "properties": {
          "debt_to_equity_note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Factual note on debt metrics from the LLM. PIQ never computes ratios \u2014 consumer-side.",
            "title": "Debt To Equity Note"
          },
          "eps_ttm": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Trailing twelve-month EPS. Null if not provided.",
            "title": "Eps Ttm"
          },
          "pe_ratio_ttm": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Trailing twelve-month PE ratio. Null if not provided in payload.",
            "title": "Pe Ratio Ttm"
          },
          "revenue_growth_yoy": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Year-over-year revenue growth as a decimal (e.g. 0.04 = 4%).",
            "title": "Revenue Growth Yoy"
          }
        },
        "title": "StockKeyMetrics",
        "type": "object"
      },
      "StockPriceMeta": {
        "properties": {
          "adj_note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Adj Note"
          },
          "cache_hit": {
            "default": false,
            "title": "Cache Hit",
            "type": "boolean"
          },
          "computed_at": {
            "title": "Computed At",
            "type": "string"
          },
          "confidence_score_avg": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Confidence Score Avg"
          },
          "data_methodology": {
            "title": "Data Methodology",
            "type": "string"
          },
          "data_quality": {
            "default": "full",
            "title": "Data Quality",
            "type": "string"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "licensed_for_commercial_use": {
            "title": "Licensed For Commercial Use",
            "type": "boolean"
          },
          "market_cap_note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Market Cap Note"
          },
          "methodology_url": {
            "title": "Methodology Url",
            "type": "string"
          },
          "price_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Source"
          },
          "price_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Status"
          },
          "price_status_note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Status Note"
          },
          "price_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Type"
          },
          "redistribution_flag": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Redistribution Flag"
          },
          "source_count_avg": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Source Count Avg"
          }
        },
        "required": [
          "data_methodology",
          "methodology_url",
          "licensed_for_commercial_use",
          "computed_at",
          "disclaimer"
        ],
        "title": "StockPriceMeta",
        "type": "object"
      },
      "StockPriceResponse": {
        "properties": {
          "data": {
            "additionalProperties": true,
            "title": "Data",
            "type": "object"
          },
          "meta": {
            "$ref": "#/components/schemas/StockPriceMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "StockPriceResponse",
        "type": "object"
      },
      "SubscribeRequest": {
        "properties": {
          "assets": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "maxItems": 500,
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Assets"
          },
          "events": {
            "items": {
              "type": "string"
            },
            "maxItems": 10,
            "minItems": 1,
            "title": "Events",
            "type": "array"
          },
          "url": {
            "maxLength": 2048,
            "title": "Url",
            "type": "string"
          }
        },
        "required": [
          "url",
          "events"
        ],
        "title": "SubscribeRequest",
        "type": "object"
      },
      "SubscribeResponse": {
        "properties": {
          "secret": {
            "title": "Secret",
            "type": "string"
          },
          "subscription_id": {
            "title": "Subscription Id",
            "type": "string"
          }
        },
        "required": [
          "subscription_id",
          "secret"
        ],
        "title": "SubscribeResponse",
        "type": "object"
      },
      "SukukData": {
        "properties": {
          "coupon_frequency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "semi_annual | quarterly | annual. NULL if not disclosed.",
            "title": "Coupon Frequency"
          },
          "coupon_rate_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Rate of return (NOT interest/riba). NULL if not publicly disclosed.",
            "title": "Coupon Rate Pct"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 4217 currency code",
            "title": "Currency"
          },
          "face_value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total issuance size in currency units",
            "title": "Face Value"
          },
          "isin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 6166 ISIN (12 chars). NULL for private placements.",
            "title": "Isin"
          },
          "issue_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Issue date (ISO 8601 date)",
            "title": "Issue Date"
          },
          "issuer_country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 3166-1 alpha-2 issuer country",
            "title": "Issuer Country"
          },
          "issuer_lei": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "GLEIF LEI (20 chars) if available",
            "title": "Issuer Lei"
          },
          "issuer_name": {
            "description": "Issuing entity name",
            "title": "Issuer Name",
            "type": "string"
          },
          "listing_exchange": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "MIC code of listing exchange",
            "title": "Listing Exchange"
          },
          "maturity_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Maturity date (ISO 8601 date). NULL for perpetual sukuk (e.g. AT1).",
            "title": "Maturity Date"
          },
          "rating_fitch": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Fitch rating. NULL if not rated or not public.",
            "title": "Rating Fitch"
          },
          "rating_moodys": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Moody's rating. NULL if not rated or not public.",
            "title": "Rating Moodys"
          },
          "rating_sp": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "S&P rating. NULL if not rated or not public.",
            "title": "Rating Sp"
          },
          "sharia_board": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Name of certifying Sharia board",
            "title": "Sharia Board"
          },
          "sukuk_code": {
            "description": "Internal unique code, e.g. 'MY-WAKALA-USD-2024'",
            "title": "Sukuk Code",
            "type": "string"
          },
          "sukuk_name": {
            "description": "Full human-readable sukuk name",
            "title": "Sukuk Name",
            "type": "string"
          },
          "sukuk_type": {
            "description": "AAOIFI Standard 17 sukuk type",
            "title": "Sukuk Type",
            "type": "string"
          },
          "underlying_asset": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Description of underlying asset structure",
            "title": "Underlying Asset"
          }
        },
        "required": [
          "sukuk_code",
          "sukuk_name",
          "issuer_name",
          "sukuk_type"
        ],
        "title": "SukukData",
        "type": "object"
      },
      "SukukListResponse": {
        "properties": {
          "count": {
            "title": "Count",
            "type": "integer"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/SukukData"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/SukukMeta"
          }
        },
        "required": [
          "data",
          "meta",
          "count"
        ],
        "title": "SukukListResponse",
        "type": "object"
      },
      "SukukMeta": {
        "properties": {
          "attribution": {
            "default": "Sources: Wikipedia CC-BY-SA 4.0, IIFM Annual Sukuk Report (public), sovereign issuer press releases (public domain)",
            "title": "Attribution",
            "type": "string"
          },
          "disclaimer": {
            "default": "Not financial advice. Not a fatwa. Methodology disclosed. portfoliq.io",
            "title": "Disclaimer",
            "type": "string"
          },
          "fetched_at": {
            "description": "ISO 8601 timestamp of response",
            "title": "Fetched At",
            "type": "string"
          },
          "source": {
            "default": "portfoliq-curated",
            "title": "Source",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "fetched_at"
        ],
        "title": "SukukMeta",
        "type": "object"
      },
      "SukukResponse": {
        "properties": {
          "data": {
            "$ref": "#/components/schemas/SukukData"
          },
          "meta": {
            "$ref": "#/components/schemas/SukukMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "SukukResponse",
        "type": "object"
      },
      "SukukTypeEntry": {
        "properties": {
          "aaoifi_standard": {
            "description": "Governing AAOIFI Sharia Standard(s)",
            "title": "Aaoifi Standard",
            "type": "string"
          },
          "description": {
            "description": "Plain-language description of the structure",
            "title": "Description",
            "type": "string"
          },
          "type": {
            "description": "AAOIFI sukuk type identifier",
            "title": "Type",
            "type": "string"
          }
        },
        "required": [
          "type",
          "aaoifi_standard",
          "description"
        ],
        "title": "SukukTypeEntry",
        "type": "object"
      },
      "SukukTypesResponse": {
        "properties": {
          "count": {
            "title": "Count",
            "type": "integer"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/SukukTypeEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/SukukMeta"
          }
        },
        "required": [
          "data",
          "meta",
          "count"
        ],
        "title": "SukukTypesResponse",
        "type": "object"
      },
      "TreasuryCatalogResponse": {
        "description": "Response for GET /v1/macro/us-treasury/catalog.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/TreasuryDatasetEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total_datasets": {
            "title": "Total Datasets",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total_datasets",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "TreasuryCatalogResponse",
        "type": "object"
      },
      "TreasuryDatasetEntry": {
        "description": "A dataset entry in the catalogue.",
        "properties": {
          "dataset_code": {
            "title": "Dataset Code",
            "type": "string"
          },
          "description": {
            "title": "Description",
            "type": "string"
          },
          "frequency": {
            "title": "Frequency",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "series": {
            "items": {
              "$ref": "#/components/schemas/TreasurySeriesEntry"
            },
            "title": "Series",
            "type": "array"
          }
        },
        "required": [
          "dataset_code",
          "name",
          "description",
          "frequency",
          "series"
        ],
        "title": "TreasuryDatasetEntry",
        "type": "object"
      },
      "TreasuryObservation": {
        "description": "A single US Treasury data observation.",
        "properties": {
          "observation_date": {
            "description": "Observation date (ISO-8601: YYYY-MM-DD).",
            "title": "Observation Date",
            "type": "string"
          },
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unit of measurement (%, USD, USD millions, etc.).",
            "title": "Unit"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Observation value. Null if not available.",
            "title": "Value"
          }
        },
        "required": [
          "observation_date"
        ],
        "title": "TreasuryObservation",
        "type": "object"
      },
      "TreasurySeriesEntry": {
        "description": "A series within a dataset in the catalogue.",
        "properties": {
          "name": {
            "title": "Name",
            "type": "string"
          },
          "series_id": {
            "title": "Series Id",
            "type": "string"
          },
          "unit": {
            "title": "Unit",
            "type": "string"
          }
        },
        "required": [
          "series_id",
          "name",
          "unit"
        ],
        "title": "TreasurySeriesEntry",
        "type": "object"
      },
      "TreasurySeriesMeta": {
        "description": "Response metadata for a dataset/series query.",
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "dataset_code": {
            "description": "Treasury dataset code.",
            "title": "Dataset Code",
            "type": "string"
          },
          "dataset_name": {
            "description": "Human-readable dataset name.",
            "title": "Dataset Name",
            "type": "string"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End date filter applied (YYYY-MM-DD).",
            "title": "End Date"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live US Treasury Fiscal Data API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of observations in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "series_id": {
            "description": "Series identifier within the dataset.",
            "title": "Series Id",
            "type": "string"
          },
          "series_name": {
            "description": "Human-readable series name.",
            "title": "Series Name",
            "type": "string"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start date filter applied (YYYY-MM-DD).",
            "title": "Start Date"
          },
          "total": {
            "description": "Total observations matching the query.",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "dataset_code",
          "dataset_name",
          "series_id",
          "series_name",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_date",
          "end_date",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "TreasurySeriesMeta",
        "type": "object"
      },
      "TreasurySeriesResponse": {
        "description": "Response for GET /v1/macro/us-treasury/{dataset_code}/{series_id}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/TreasuryObservation"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/TreasurySeriesMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "TreasurySeriesResponse",
        "type": "object"
      },
      "TrialStartResponse": {
        "properties": {
          "message": {
            "title": "Message",
            "type": "string"
          },
          "trial_calls_cap": {
            "title": "Trial Calls Cap",
            "type": "integer"
          },
          "trial_expires_at": {
            "format": "date-time",
            "title": "Trial Expires At",
            "type": "string"
          },
          "trial_started_at": {
            "format": "date-time",
            "title": "Trial Started At",
            "type": "string"
          }
        },
        "required": [
          "trial_started_at",
          "trial_expires_at",
          "trial_calls_cap",
          "message"
        ],
        "title": "TrialStartResponse",
        "type": "object"
      },
      "TvlMeta": {
        "description": "Response metadata for a protocol TVL query.",
        "properties": {
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End date filter applied.",
            "title": "End Date"
          },
          "fetched_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Fetched At",
            "type": "string"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live DeFiLlama API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "protocol_slug": {
            "description": "DeFiLlama protocol slug.",
            "title": "Protocol Slug",
            "type": "string"
          },
          "returned": {
            "description": "Number of snapshots in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_date": {
            "anyOf": [
              {
                "format": "date",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start date filter applied.",
            "title": "Start Date"
          },
          "total": {
            "description": "Total TVL snapshots available.",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "protocol_slug",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_date",
          "end_date",
          "fetched_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "TvlMeta",
        "type": "object"
      },
      "TvlResponse": {
        "description": "Response for GET /v1/defi/protocol/{slug}/tvl.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/TvlSnapshot"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/TvlMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "TvlResponse",
        "type": "object"
      },
      "TvlSnapshot": {
        "description": "A single TVL snapshot for a DeFi protocol.",
        "properties": {
          "category": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "DeFi category (e.g. 'Lending', 'DEX', 'Liquid Staking'). Null if unavailable.",
            "title": "Category"
          },
          "chain": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Primary blockchain chain (e.g. 'Ethereum', 'Solana'). Null if unavailable.",
            "title": "Chain"
          },
          "mcap_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Protocol market cap in USD. Null if unavailable (e.g. non-token protocols).",
            "title": "Mcap Usd"
          },
          "snapshot_date": {
            "description": "Date of the TVL snapshot.",
            "format": "date",
            "title": "Snapshot Date",
            "type": "string"
          },
          "tvl_change_24h_pct": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "24-hour TVL change in percent. Null if unavailable.",
            "title": "Tvl Change 24H Pct"
          },
          "tvl_usd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total Value Locked in USD.",
            "title": "Tvl Usd"
          }
        },
        "required": [
          "snapshot_date"
        ],
        "title": "TvlSnapshot",
        "type": "object"
      },
      "TwseEodMeta": {
        "description": "Response metadata for a TWSE EOD query.",
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "End date filter applied (ISO 8601).",
            "title": "End Date"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live TWSE open data. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "listing_venue": {
            "default": "XTAI",
            "description": "MIC code for TWSE.",
            "title": "Listing Venue",
            "type": "string"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of records in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "start_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start date filter applied (ISO 8601).",
            "title": "Start Date"
          },
          "ticker": {
            "description": "TWSE 4-digit ticker.",
            "title": "Ticker",
            "type": "string"
          },
          "total": {
            "description": "Total EOD records matching the query.",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "ticker",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_date",
          "end_date",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "TwseEodMeta",
        "type": "object"
      },
      "TwseEodRecord": {
        "description": "A single TWSE EOD price record.",
        "properties": {
          "close_twd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Closing price in TWD.",
            "title": "Close Twd"
          },
          "currency": {
            "default": "TWD",
            "description": "Currency (always TWD).",
            "title": "Currency",
            "type": "string"
          },
          "high_twd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Daily high price in TWD.",
            "title": "High Twd"
          },
          "low_twd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Daily low price in TWD.",
            "title": "Low Twd"
          },
          "observation_date": {
            "description": "Trading date (ISO 8601).",
            "format": "date",
            "title": "Observation Date",
            "type": "string"
          },
          "open_twd": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Opening price in TWD (New Taiwan Dollar).",
            "title": "Open Twd"
          },
          "transactions_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total number of transactions (order fills) on this date.",
            "title": "Transactions Count"
          },
          "volume": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total shares (lots) traded.",
            "title": "Volume"
          }
        },
        "required": [
          "observation_date"
        ],
        "title": "TwseEodRecord",
        "type": "object"
      },
      "TwseEodResponse": {
        "description": "Response for GET /v1/stock/{ticker}/twse-eod.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/TwseEodRecord"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/TwseEodMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "TwseEodResponse",
        "type": "object"
      },
      "UnsubscribeRequest": {
        "properties": {
          "subscription_id": {
            "title": "Subscription Id",
            "type": "string"
          }
        },
        "required": [
          "subscription_id"
        ],
        "title": "UnsubscribeRequest",
        "type": "object"
      },
      "UpsellMarker": {
        "description": "Upsell marker \u2014 present on gated fields when scope is absent.\n\nSignals to the API consumer that this block is available on a higher tier.\nNever silently absent \u2014 always either populated or replaced with upsell marker.",
        "properties": {
          "scope": {
            "description": "The scope required to access this block (e.g. 'ai:read').",
            "title": "Scope",
            "type": "string"
          },
          "upgrade_url": {
            "description": "URL to the pricing page. Always 'https://portfoliq.io/pricing'.",
            "title": "Upgrade Url",
            "type": "string"
          }
        },
        "required": [
          "scope",
          "upgrade_url"
        ],
        "title": "UpsellMarker",
        "type": "object"
      },
      "UsadObservation": {
        "description": "A single USDA NASS annual observation.",
        "properties": {
          "observation_period": {
            "description": "Encoded period. Format: 'YEAR-YYYY' (e.g. 'YEAR-2024').",
            "title": "Observation Period",
            "type": "string"
          },
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unit of measurement (BU, $ / BU, ACRES, LB, CWT, etc.).",
            "title": "Unit"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Observation value. Null if USDA NASS has no data for this combination (e.g. AREA_HARVESTED for livestock, EXPORTS for OATS).",
            "title": "Value"
          }
        },
        "required": [
          "observation_period"
        ],
        "title": "UsadObservation",
        "type": "object"
      },
      "UsageResponse": {
        "description": "Response for GET /auth/usage.",
        "properties": {
          "total_24h": {
            "title": "Total 24H",
            "type": "integer"
          },
          "windows": {
            "items": {
              "$ref": "#/components/schemas/UsageWindow"
            },
            "title": "Windows",
            "type": "array"
          }
        },
        "required": [
          "windows",
          "total_24h"
        ],
        "title": "UsageResponse",
        "type": "object"
      },
      "UsageWindow": {
        "description": "A single hourly usage window.",
        "properties": {
          "key_id": {
            "title": "Key Id",
            "type": "string"
          },
          "key_label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Key Label"
          },
          "requests_count": {
            "title": "Requests Count",
            "type": "integer"
          },
          "window_start": {
            "format": "date-time",
            "title": "Window Start",
            "type": "string"
          }
        },
        "required": [
          "window_start",
          "requests_count",
          "key_id",
          "key_label"
        ],
        "title": "UsageWindow",
        "type": "object"
      },
      "UsdaCatalogResponse": {
        "description": "Response for GET /v1/commodity/usda/catalog.",
        "properties": {
          "commodities": {
            "items": {
              "$ref": "#/components/schemas/UsdaCommodityEntry"
            },
            "title": "Commodities",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "statistics": {
            "items": {
              "$ref": "#/components/schemas/UsdaStatisticEntry"
            },
            "title": "Statistics",
            "type": "array"
          },
          "total_commodities": {
            "title": "Total Commodities",
            "type": "integer"
          },
          "total_statistics": {
            "title": "Total Statistics",
            "type": "integer"
          }
        },
        "required": [
          "commodities",
          "statistics",
          "total_commodities",
          "total_statistics",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "UsdaCatalogResponse",
        "type": "object"
      },
      "UsdaCommodityEntry": {
        "description": "A single commodity entry in the catalogue.",
        "properties": {
          "category": {
            "title": "Category",
            "type": "string"
          },
          "code": {
            "title": "Code",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "category"
        ],
        "title": "UsdaCommodityEntry",
        "type": "object"
      },
      "UsdaCommodityMeta": {
        "description": "Commodity metadata embedded in response.",
        "properties": {
          "category": {
            "description": "Commodity category (grains, oilseeds, fiber, livestock).",
            "title": "Category",
            "type": "string"
          },
          "code": {
            "description": "Commodity code (uppercase).",
            "title": "Code",
            "type": "string"
          },
          "name": {
            "description": "Human-readable commodity name.",
            "title": "Name",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "category"
        ],
        "title": "UsdaCommodityMeta",
        "type": "object"
      },
      "UsdaSeriesMeta": {
        "description": "Response metadata for a commodity/statistic query.",
        "properties": {
          "commodity": {
            "$ref": "#/components/schemas/UsdaCommodityMeta"
          },
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live USDA NASS API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "location_code": {
            "description": "Geographic scope ('US' = national).",
            "title": "Location Code",
            "type": "string"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of observations in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "source": {
            "description": "Data source attribution.",
            "title": "Source",
            "type": "string"
          },
          "statistic": {
            "$ref": "#/components/schemas/UsdaStatisticMeta"
          },
          "total": {
            "description": "Total observations matching the query.",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "commodity",
          "statistic",
          "location_code",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "UsdaSeriesMeta",
        "type": "object"
      },
      "UsdaSeriesResponse": {
        "description": "Response for GET /v1/commodity/usda/{commodity}/{statistic}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/UsadObservation"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/UsdaSeriesMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "UsdaSeriesResponse",
        "type": "object"
      },
      "UsdaStatisticEntry": {
        "description": "A single statistic entry in the catalogue.",
        "properties": {
          "code": {
            "title": "Code",
            "type": "string"
          },
          "description": {
            "title": "Description",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "description"
        ],
        "title": "UsdaStatisticEntry",
        "type": "object"
      },
      "UsdaStatisticMeta": {
        "description": "Statistic metadata embedded in response.",
        "properties": {
          "code": {
            "description": "Statistic code (uppercase).",
            "title": "Code",
            "type": "string"
          },
          "name": {
            "description": "Human-readable statistic name.",
            "title": "Name",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name"
        ],
        "title": "UsdaStatisticMeta",
        "type": "object"
      },
      "UserObjectionsResponse": {
        "description": "Response for GET /auth/me/object-to-processing.\n\nReturns the list of active objections for the authenticated user.",
        "properties": {
          "objections": {
            "items": {
              "type": "string"
            },
            "title": "Objections",
            "type": "array"
          }
        },
        "required": [
          "objections"
        ],
        "title": "UserObjectionsResponse",
        "type": "object"
      },
      "UserProfile": {
        "description": "Embedded user profile returned in auth responses.",
        "properties": {
          "email": {
            "title": "Email",
            "type": "string"
          },
          "id": {
            "title": "Id",
            "type": "string"
          },
          "tier": {
            "title": "Tier",
            "type": "string"
          }
        },
        "required": [
          "id",
          "email",
          "tier"
        ],
        "title": "UserProfile",
        "type": "object"
      },
      "ValidationError": {
        "properties": {
          "ctx": {
            "title": "Context",
            "type": "object"
          },
          "input": {
            "title": "Input"
          },
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "title": "Location",
            "type": "array"
          },
          "msg": {
            "title": "Message",
            "type": "string"
          },
          "type": {
            "title": "Error Type",
            "type": "string"
          }
        },
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError",
        "type": "object"
      },
      "VersionResponse": {
        "description": "Response model for GET /v1/health/version.\n\nSprint 28 T-410 \u2014 enriched with coverage dict for HS auto-discovery.\nCOMITE-021 \u2014 adds 'capabilities' (DAT-NNN keyed) and 'contract_sha_observed'.",
        "properties": {
          "built_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Built At"
          },
          "capabilities": {
            "additionalProperties": {
              "$ref": "#/components/schemas/ContractCapability"
            },
            "title": "Capabilities",
            "type": "object"
          },
          "contract_sha_observed": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Contract Sha Observed"
          },
          "coverage": {
            "additionalProperties": {
              "$ref": "#/components/schemas/CoverageCapability"
            },
            "title": "Coverage",
            "type": "object"
          },
          "environment": {
            "default": "production",
            "title": "Environment",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "version",
          "coverage",
          "capabilities"
        ],
        "title": "VersionResponse",
        "type": "object"
      },
      "VwapByPairRecord": {
        "description": "Aggregated VWAP by pair.",
        "properties": {
          "asset_count": {
            "title": "Asset Count",
            "type": "integer"
          },
          "avg_vwap": {
            "anyOf": [
              {
                "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Avg Vwap"
          },
          "loaded_at": {
            "format": "date-time",
            "title": "Loaded At",
            "type": "string"
          },
          "pair": {
            "title": "Pair",
            "type": "string"
          },
          "total_volume_pair": {
            "anyOf": [
              {
                "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Total Volume Pair"
          },
          "ts": {
            "format": "date-time",
            "title": "Ts",
            "type": "string"
          }
        },
        "required": [
          "pair",
          "ts",
          "asset_count",
          "avg_vwap",
          "total_volume_pair",
          "loaded_at"
        ],
        "title": "VwapByPairRecord",
        "type": "object"
      },
      "VwapByPairResponse": {
        "description": "Response for /v1/vwap/by-pair.",
        "properties": {
          "count": {
            "title": "Count",
            "type": "integer"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/VwapByPairRecord"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "default": "VWAP consensus price data \u2014 derived data computed by portfolIQ from multiple exchange sources. Not financial advice. Not an investment recommendation. Methodology disclosed at /v1/methodology.",
            "title": "Disclaimer",
            "type": "string"
          }
        },
        "required": [
          "data",
          "count"
        ],
        "title": "VwapByPairResponse",
        "type": "object"
      },
      "VwapMeta": {
        "description": "Metadata for VWAP responses \u2014 includes timeframe info (T-846).",
        "properties": {
          "notice": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable notice when served_timeframe differs from requested_timeframe.",
            "title": "Notice"
          },
          "requested_timeframe": {
            "description": "Timeframe requested by the client.",
            "title": "Requested Timeframe",
            "type": "string"
          },
          "served_timeframe": {
            "description": "Timeframe actually served (may differ if requested TF unavailable).",
            "title": "Served Timeframe",
            "type": "string"
          }
        },
        "required": [
          "requested_timeframe",
          "served_timeframe"
        ],
        "title": "VwapMeta",
        "type": "object"
      },
      "VwapRecord": {
        "description": "A single VWAP consensus record.",
        "properties": {
          "asset_hk": {
            "description": "Asset identifier (surrogate key).",
            "title": "Asset Hk",
            "type": "string"
          },
          "confidence": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Data confidence level (high/medium/low/unknown).",
            "title": "Confidence"
          },
          "exchange_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Number of exchanges contributing.",
            "title": "Exchange Count"
          },
          "methodology_version": {
            "description": "VWAP methodology version.",
            "title": "Methodology Version",
            "type": "string"
          },
          "pair": {
            "description": "Trading pair (e.g. 'CRYPTO/USD').",
            "title": "Pair",
            "type": "string"
          },
          "price_derivation": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Price derivation method. 'direct' = standard market quote. 'inverse_pair' = price derived by USDT inversion (LEGAL-007 C6). NULL only for legacy rows predating vwap-consensus-v1.2.",
            "title": "Price Derivation"
          },
          "source_exchanges": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "List of exchanges included.",
            "title": "Source Exchanges"
          },
          "timeframe": {
            "description": "Timeframe of this VWAP record (1h, 4h, 1d, 1w, 1M).",
            "title": "Timeframe",
            "type": "string"
          },
          "total_volume": {
            "anyOf": [
              {
                "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total volume across exchanges.",
            "title": "Total Volume"
          },
          "ts": {
            "description": "Timestamp of the VWAP snapshot (UTC).",
            "format": "date-time",
            "title": "Ts",
            "type": "string"
          },
          "vwap_price": {
            "description": "VWAP price (derived, redistributable).",
            "pattern": "^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$",
            "title": "Vwap Price",
            "type": "string"
          }
        },
        "required": [
          "asset_hk",
          "pair",
          "ts",
          "timeframe",
          "vwap_price",
          "methodology_version"
        ],
        "title": "VwapRecord",
        "type": "object"
      },
      "VwapResponse": {
        "description": "Response for VWAP endpoints (T-846: meta includes timeframe info).",
        "properties": {
          "benchmark_notice": {
            "default": "Informational only. Not a benchmark under Regulation (EU) 2016/1011 (BMR). Must not be used as a settlement reference for any financial instrument.",
            "title": "Benchmark Notice",
            "type": "string"
          },
          "count": {
            "description": "Number of records returned.",
            "title": "Count",
            "type": "integer"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/VwapRecord"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "default": "VWAP consensus price data \u2014 derived data computed by portfolIQ from multiple exchange sources. Not financial advice. Not an investment recommendation. Methodology disclosed at /v1/methodology.",
            "title": "Disclaimer",
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/VwapMeta",
            "description": "Timeframe metadata (T-846)."
          }
        },
        "required": [
          "data",
          "count",
          "meta"
        ],
        "title": "VwapResponse",
        "type": "object"
      },
      "WbCountriesResponse": {
        "description": "Response for GET /v1/macro/worldbank/countries.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/WbCountryEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "WbCountriesResponse",
        "type": "object"
      },
      "WbCountryEntry": {
        "description": "A single country entry in the countries catalogue.",
        "properties": {
          "iso2": {
            "title": "Iso2",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          }
        },
        "required": [
          "iso2",
          "name"
        ],
        "title": "WbCountryEntry",
        "type": "object"
      },
      "WbCountryMeta": {
        "description": "Country metadata embedded in response.",
        "properties": {
          "iso2": {
            "description": "ISO 3166-1 alpha-2 country code.",
            "title": "Iso2",
            "type": "string"
          },
          "name": {
            "description": "Country name.",
            "title": "Name",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "iso2",
          "name"
        ],
        "title": "WbCountryMeta",
        "type": "object"
      },
      "WbIndicatorEntry": {
        "description": "A single indicator entry in the indicators catalogue.",
        "properties": {
          "code": {
            "title": "Code",
            "type": "string"
          },
          "description": {
            "title": "Description",
            "type": "string"
          },
          "name": {
            "title": "Name",
            "type": "string"
          },
          "unit": {
            "title": "Unit",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "unit",
          "description"
        ],
        "title": "WbIndicatorEntry",
        "type": "object"
      },
      "WbIndicatorMeta": {
        "description": "Indicator metadata embedded in response.",
        "properties": {
          "code": {
            "description": "World Bank indicator code.",
            "title": "Code",
            "type": "string"
          },
          "name": {
            "description": "Human-readable indicator name.",
            "title": "Name",
            "type": "string"
          },
          "unit": {
            "description": "Unit of measurement.",
            "title": "Unit",
            "type": "string"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "code",
          "name",
          "unit"
        ],
        "title": "WbIndicatorMeta",
        "type": "object"
      },
      "WbIndicatorsResponse": {
        "description": "Response for GET /v1/macro/worldbank/indicators.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/WbIndicatorEntry"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "license": {
            "title": "License",
            "type": "string"
          },
          "source": {
            "title": "Source",
            "type": "string"
          },
          "total": {
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "data",
          "total",
          "source",
          "license",
          "disclaimer"
        ],
        "title": "WbIndicatorsResponse",
        "type": "object"
      },
      "WbObservation": {
        "description": "A single World Bank annual observation.",
        "properties": {
          "unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unit of measurement (USD, %, count, etc.).",
            "title": "Unit"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Observation value. Null if not available for this country/year.",
            "title": "Value"
          },
          "year": {
            "description": "Calendar year of observation.",
            "title": "Year",
            "type": "integer"
          }
        },
        "required": [
          "year"
        ],
        "title": "WbObservation",
        "type": "object"
      },
      "WbSeriesMeta": {
        "description": "Response metadata for a country/indicator query.",
        "properties": {
          "computed_at": {
            "description": "ISO-8601 timestamp when this response was generated.",
            "title": "Computed At",
            "type": "string"
          },
          "country": {
            "$ref": "#/components/schemas/WbCountryMeta"
          },
          "data_quality": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "'full' | 'partial' | None. Quality indicator for this response.",
            "title": "Data Quality"
          },
          "disclaimer": {
            "description": "Legal disclaimer (English).",
            "title": "Disclaimer",
            "type": "string"
          },
          "disclaimer_fr": {
            "description": "Legal disclaimer (French).",
            "title": "Disclaimer Fr",
            "type": "string"
          },
          "end_year": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "End year filter applied.",
            "title": "End Year"
          },
          "has_next": {
            "description": "True if more pages are available.",
            "title": "Has Next",
            "type": "boolean"
          },
          "indicator": {
            "$ref": "#/components/schemas/WbIndicatorMeta"
          },
          "is_dev_dataset": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "True when data originates from a curated/fallback seed (non-production). False when sourced from live World Bank API. None = provenance unknown.",
            "title": "Is Dev Dataset"
          },
          "license": {
            "description": "Data license.",
            "title": "License",
            "type": "string"
          },
          "limit": {
            "description": "Page size used.",
            "title": "Limit",
            "type": "integer"
          },
          "page": {
            "description": "Current page (1-indexed).",
            "title": "Page",
            "type": "integer"
          },
          "returned": {
            "description": "Number of observations in this response.",
            "title": "Returned",
            "type": "integer"
          },
          "source": {
            "description": "Data source attribution (CC BY 4.0).",
            "title": "Source",
            "type": "string"
          },
          "start_year": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start year filter applied.",
            "title": "Start Year"
          },
          "total": {
            "description": "Total observations matching the query.",
            "title": "Total",
            "type": "integer"
          },
          "version": {
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "country",
          "indicator",
          "total",
          "returned",
          "has_next",
          "page",
          "limit",
          "start_year",
          "end_year",
          "computed_at",
          "source",
          "license",
          "disclaimer",
          "disclaimer_fr"
        ],
        "title": "WbSeriesMeta",
        "type": "object"
      },
      "WbSeriesResponse": {
        "description": "Response for GET /v1/macro/worldbank/{country_iso2}/{indicator_code}.",
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/WbObservation"
            },
            "title": "Data",
            "type": "array"
          },
          "meta": {
            "$ref": "#/components/schemas/WbSeriesMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "WbSeriesResponse",
        "type": "object"
      },
      "WebhookSubscription": {
        "properties": {
          "asset_filters": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Asset Filters"
          },
          "created_at": {
            "title": "Created At",
            "type": "string"
          },
          "delivery_count": {
            "title": "Delivery Count",
            "type": "integer"
          },
          "events": {
            "items": {
              "type": "string"
            },
            "title": "Events",
            "type": "array"
          },
          "failure_count": {
            "title": "Failure Count",
            "type": "integer"
          },
          "is_active": {
            "title": "Is Active",
            "type": "boolean"
          },
          "last_delivered_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Delivered At"
          },
          "subscription_id": {
            "title": "Subscription Id",
            "type": "string"
          },
          "url": {
            "title": "Url",
            "type": "string"
          }
        },
        "required": [
          "subscription_id",
          "url",
          "events",
          "asset_filters",
          "created_at",
          "last_delivered_at",
          "delivery_count",
          "failure_count",
          "is_active"
        ],
        "title": "WebhookSubscription",
        "type": "object"
      },
      "WikidataData": {
        "properties": {
          "ceo_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Current CEO name (P169, no end date)",
            "title": "Ceo Name"
          },
          "country_iso2": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 3166-1 alpha-2 country code (P17 \u2192 P297)",
            "title": "Country Iso2"
          },
          "employees_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Number of employees (P1128)",
            "title": "Employees Count"
          },
          "employees_year": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Reference year for employees_count",
            "title": "Employees Year"
          },
          "headquarters_location": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Headquarters location label (P159, en)",
            "title": "Headquarters Location"
          },
          "inception_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Company founding date (P571), ISO 8601 date",
            "title": "Inception Date"
          },
          "industry_label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable industry label (P452, en)",
            "title": "Industry Label"
          },
          "industry_qid": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Wikidata QID of the industry category (P452)",
            "title": "Industry Qid"
          },
          "isin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISIN code, 12 chars (P946)",
            "title": "Isin"
          },
          "legal_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Official legal name from Wikidata rdfs:label",
            "title": "Legal Name"
          },
          "lei": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "LEI code, 20 chars (P1278). Cross-reference to GLEIF /v1/legal-entity/{lei}.",
            "title": "Lei"
          },
          "official_website": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Official website URL (P856)",
            "title": "Official Website"
          },
          "parent_company_qid": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Wikidata QID of the parent company (P749)",
            "title": "Parent Company Qid"
          },
          "stock_exchange_qid": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Wikidata QID of the primary stock exchange (P414)",
            "title": "Stock Exchange Qid"
          },
          "subsidiaries_qids": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "List of Wikidata QIDs for subsidiaries (P355)",
            "title": "Subsidiaries Qids"
          },
          "wikidata_qid": {
            "description": "Wikidata entity QID (e.g. 'Q312' for Apple Inc.)",
            "title": "Wikidata Qid",
            "type": "string"
          }
        },
        "required": [
          "wikidata_qid"
        ],
        "title": "WikidataData",
        "type": "object"
      },
      "WikidataMeta": {
        "properties": {
          "attribution": {
            "default": "Wikidata \u2014 wikidata.org (CC0 1.0 Universal). Data may be outdated \u2014 snapshot from seed date.",
            "title": "Attribution",
            "type": "string"
          },
          "fetched_at": {
            "description": "ISO 8601 timestamp of this response",
            "title": "Fetched At",
            "type": "string"
          },
          "license": {
            "default": "CC0",
            "title": "License",
            "type": "string"
          },
          "record_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Seed record source identifier",
            "title": "Record Source"
          },
          "served_from": {
            "default": "db_cache",
            "title": "Served From",
            "type": "string"
          },
          "source": {
            "default": "Wikidata",
            "title": "Source",
            "type": "string"
          },
          "sparql_endpoint": {
            "default": "https://query.wikidata.org/sparql",
            "title": "Sparql Endpoint",
            "type": "string"
          }
        },
        "required": [
          "fetched_at"
        ],
        "title": "WikidataMeta",
        "type": "object"
      },
      "WikidataResponse": {
        "properties": {
          "data": {
            "$ref": "#/components/schemas/WikidataData"
          },
          "meta": {
            "$ref": "#/components/schemas/WikidataMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "WikidataResponse",
        "type": "object"
      },
      "YieldCurveResponse": {
        "description": "Response payload for GET /v1/analytics/yield-curve.",
        "properties": {
          "as_of": {
            "format": "date",
            "title": "As Of",
            "type": "string"
          },
          "days_since_inversion": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Days since the curve was last inverted (uninversion clock). None if never inverted in 1Y window.",
            "title": "Days Since Inversion"
          },
          "interpretation": {
            "description": "Plain-English interpretation (factual, methodology-disclosed).",
            "title": "Interpretation",
            "type": "string"
          },
          "is_inverted": {
            "description": "True when spread_10y_2y < 0 (recession leading indicator).",
            "title": "Is Inverted",
            "type": "boolean"
          },
          "meta": {
            "$ref": "#/components/schemas/ApiMeta"
          },
          "methodology_version": {
            "default": "yield-curve-v1.0",
            "title": "Methodology Version",
            "type": "string"
          },
          "spread_10y_2y": {
            "description": "DGS10 - DGS2 in percentage points.",
            "title": "Spread 10Y 2Y",
            "type": "number"
          },
          "treasury_10y": {
            "description": "DGS10 \u2014 10-year Treasury yield (%).",
            "title": "Treasury 10Y",
            "type": "number"
          },
          "treasury_2y": {
            "description": "DGS2 \u2014 2-year Treasury yield (%).",
            "title": "Treasury 2Y",
            "type": "number"
          }
        },
        "required": [
          "treasury_2y",
          "treasury_10y",
          "spread_10y_2y",
          "is_inverted",
          "interpretation",
          "as_of",
          "meta"
        ],
        "title": "YieldCurveResponse",
        "type": "object"
      },
      "ZakatBreakdownItem": {
        "description": "Per-asset-class breakdown entry.",
        "properties": {
          "note": {
            "description": "Methodology note for this asset class.",
            "title": "Note",
            "type": "string"
          },
          "skipped": {
            "default": false,
            "description": "True when the holding is below its per-asset nisab threshold.",
            "title": "Skipped",
            "type": "boolean"
          },
          "value": {
            "description": "Market value in request currency.",
            "title": "Value",
            "type": "number"
          },
          "zakat": {
            "description": "Zakat amount due for this asset class (in request currency).",
            "title": "Zakat",
            "type": "number"
          }
        },
        "required": [
          "value",
          "zakat",
          "note"
        ],
        "title": "ZakatBreakdownItem",
        "type": "object"
      },
      "ZakatData": {
        "description": "Core calculation result.",
        "properties": {
          "breakdown": {
            "additionalProperties": {
              "$ref": "#/components/schemas/ZakatBreakdownItem"
            },
            "title": "Breakdown",
            "type": "object"
          },
          "calendar_mode": {
            "title": "Calendar Mode",
            "type": "string"
          },
          "disclaimer": {
            "title": "Disclaimer",
            "type": "string"
          },
          "nisab_met": {
            "title": "Nisab Met",
            "type": "boolean"
          },
          "nisab_reference": {
            "title": "Nisab Reference",
            "type": "string"
          },
          "nisab_threshold": {
            "title": "Nisab Threshold",
            "type": "number"
          },
          "rate": {
            "title": "Rate",
            "type": "number"
          },
          "total_wealth": {
            "title": "Total Wealth",
            "type": "number"
          },
          "zakat_due": {
            "title": "Zakat Due",
            "type": "number"
          },
          "zakat_due_currency": {
            "title": "Zakat Due Currency",
            "type": "string"
          }
        },
        "required": [
          "zakat_due",
          "zakat_due_currency",
          "rate",
          "calendar_mode",
          "nisab_reference",
          "nisab_threshold",
          "nisab_met",
          "total_wealth",
          "breakdown",
          "disclaimer"
        ],
        "title": "ZakatData",
        "type": "object"
      },
      "ZakatHolding": {
        "description": "Single asset holding to include in the Zakat calculation.",
        "properties": {
          "asset_kind": {
            "description": "Asset class.",
            "enum": [
              "stock",
              "crypto",
              "cash",
              "gold_grams",
              "silver_grams"
            ],
            "title": "Asset Kind",
            "type": "string"
          },
          "currency": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "ISO 4217 currency code. Must be null for gold_grams/silver_grams.",
            "title": "Currency"
          },
          "ticker": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Ticker symbol \u2014 informational, not used in calculation.",
            "title": "Ticker"
          },
          "value": {
            "description": "For cash/stock/crypto: monetary value in `currency`. For gold_grams/silver_grams: quantity in grams (currency field must be null).",
            "minimum": 0.0,
            "title": "Value",
            "type": "number"
          },
          "venue": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Exchange MIC code \u2014 informational, not used in calculation.",
            "title": "Venue"
          }
        },
        "required": [
          "asset_kind",
          "value"
        ],
        "title": "ZakatHolding",
        "type": "object"
      },
      "ZakatMeta": {
        "description": "Response metadata.",
        "properties": {
          "calculation_id": {
            "title": "Calculation Id",
            "type": "string"
          },
          "computed_at": {
            "title": "Computed At",
            "type": "string"
          },
          "fx_rate_source": {
            "title": "Fx Rate Source",
            "type": "string"
          },
          "metals_spot_source": {
            "title": "Metals Spot Source",
            "type": "string"
          },
          "methodology_version": {
            "title": "Methodology Version",
            "type": "string"
          }
        },
        "required": [
          "calculation_id",
          "computed_at",
          "methodology_version",
          "metals_spot_source",
          "fx_rate_source"
        ],
        "title": "ZakatMeta",
        "type": "object"
      },
      "ZakatRequest": {
        "description": "Request body for POST /v1/zakat/calculate.",
        "properties": {
          "calendar_mode": {
            "default": "lunar",
            "description": "Lunar (Hijri, 354 days) \u2192 2.5%; Solar (Gregorian) \u2192 2.575%.",
            "enum": [
              "lunar",
              "solar"
            ],
            "title": "Calendar Mode",
            "type": "string"
          },
          "currency": {
            "description": "Output currency for all monetary values in the response. Supported: AED, EUR, GBP, MYR, USD.",
            "title": "Currency",
            "type": "string"
          },
          "holdings": {
            "description": "List of asset holdings to evaluate.",
            "items": {
              "$ref": "#/components/schemas/ZakatHolding"
            },
            "title": "Holdings",
            "type": "array"
          },
          "metals_spot": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/MetalsSpot"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional caller-supplied metals spot prices (USD/gram). If omitted, static fallback values are used."
          },
          "nisab_reference": {
            "default": "silver",
            "description": "Nisab benchmark: silver (612.36 g) or gold (87.48 g).",
            "enum": [
              "silver",
              "gold"
            ],
            "title": "Nisab Reference",
            "type": "string"
          }
        },
        "required": [
          "currency"
        ],
        "title": "ZakatRequest",
        "type": "object"
      },
      "ZakatResponse": {
        "description": "Full response envelope for POST /v1/zakat/calculate.",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/ZakatData"
          },
          "meta": {
            "$ref": "#/components/schemas/ZakatMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "title": "ZakatResponse",
        "type": "object"
      },
      "api__routers__ohlcv__OhlcvResponse": {
        "description": "Response for OHLCV endpoints (T-846: meta includes timeframe info).",
        "properties": {
          "count": {
            "description": "Number of records returned.",
            "title": "Count",
            "type": "integer"
          },
          "data": {
            "items": {
              "$ref": "#/components/schemas/OhlcvRecord"
            },
            "title": "Data",
            "type": "array"
          },
          "disclaimer": {
            "default": "OHLCV market data \u2014 derived aggregates computed by portfolIQ from multiple public exchange sources. Not financial advice. Not an investment recommendation. Methodology disclosed at /v1/methodology.",
            "title": "Disclaimer",
            "type": "string"
          },
          "meta": {
            "$ref": "#/components/schemas/OhlcvMeta",
            "description": "Timeframe metadata (T-846)."
          }
        },
        "required": [
          "data",
          "count",
          "meta"
        ],
        "title": "OhlcvResponse",
        "type": "object"
      },
      "api__schemas__ohlcv__OhlcvResponse": {
        "description": "OHLCV/VWAP daily price series response.\n\nReturns daily candles for the given asset, filtered by tier (via scopes):\n  - Free: J-1 only (1 candle).\n  - Starter: rolling 365-day window.\n  - Growth: full available history (~3 years).\n\nNot financial advice. Methodology disclosed.",
        "properties": {
          "asset_id": {
            "description": "Stable integer surrogate key for the asset (D-063).",
            "title": "Asset Id",
            "type": "integer"
          },
          "candles": {
            "description": "List of OHLCV candles, ordered by date descending.",
            "items": {
              "$ref": "#/components/schemas/OhlcvCandle"
            },
            "title": "Candles",
            "type": "array"
          },
          "disclaimer": {
            "default": "Not financial advice. Methodology disclosed.",
            "description": "AMF disclaimer \u2014 always present.",
            "title": "Disclaimer",
            "type": "string"
          },
          "history_filter": {
            "description": "Applied history filter based on tier scope: 'j1_only' (Free), '1y' (Starter), 'full' (Growth+).",
            "title": "History Filter",
            "type": "string"
          },
          "timeframe": {
            "default": "daily",
            "description": "Timeframe of candles. 'daily' in Sprint 9. Intraday deferred to Sprint 10.",
            "title": "Timeframe",
            "type": "string"
          }
        },
        "required": [
          "asset_id",
          "candles",
          "history_filter"
        ],
        "title": "OhlcvResponse",
        "type": "object"
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "description": "API key header (piq_live_...). Pass as: X-API-Key: <your_key>. Generate at /dashboard/keys.",
        "in": "header",
        "name": "X-API-Key",
        "type": "apiKey"
      },
      "BearerAuth": {
        "bearerFormat": "JWT",
        "description": "JWT issued by POST /auth/login. Used for dashboard & user-scoped endpoints (/billing/*).",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "description": "European financial data platform enriched by AI \u2014 Star Schema dbt package included.",
    "title": "finance-data-api",
    "version": "1.0.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/api/status-metrics": {
      "get": {
        "description": "Returns real latency percentiles from Prometheus when PROMETHEUS_STATUS_URL is configured, or mock data with is_mock=true otherwise. Cached 60 s client-side. Consumed by the /status page (T-714). No auth required. T-711 Sprint 95.",
        "operationId": "status_metrics_api_status_metrics_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Platform status metrics (latency p50/p95/p99 + uptime + infra health)",
        "tags": [
          "status",
          "status"
        ]
      }
    },
    "/auth/confirm": {
      "get": {
        "description": "Validate an email confirmation token and return JWT + api_key.\n\nT-412 Sprint 28 \u2014 magic link pattern (Stripe-style).\n\nFlow:\n1. Compute SHA-256(token).\n2. Look up in email_confirmation_tokens WHERE hash matches, not used, not expired.\n3. If not found \u2192 400 \"Invalid or expired confirmation link\".\n4. If already used \u2192 400 (same message \u2014 no oracle for token existence).\n5. Mark token as used (used_at = NOW()), set email_confirmed_at on user.\n6. Fetch JWT + api_key from api.users / api.api_keys.\n7. Return 200 { access_token, api_key, ... }.\n\nIdempotent: once used_at is set, subsequent calls with the same token return 400.\nA new JWT is always generated fresh (the old one may have been revoked).\n\nRGPD: this endpoint is transactional (auth context) \u2014 no opt-in required.",
        "operationId": "confirm_email_auth_confirm_get",
        "parameters": [
          {
            "in": "query",
            "name": "token",
            "required": true,
            "schema": {
              "title": "Token",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailConfirmResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Confirm Email",
        "tags": [
          "auth"
        ]
      }
    },
    "/auth/forgot-password": {
      "post": {
        "description": "Initiate a password reset flow.\n\nSprint 14 T-202 \u2014 complete implementation (replaces Sprint 12 T-140 stub).\n\nRate limited: 5 attempts / 60 min per IP (T-161 Sprint 13).\nAnti-enumeration: always returns 200 with the same message, regardless of\nwhether the email exists (OWASP ASVS V2.5.6).\n\nFlow:\n1. Look up user by email (soft-deleted users excluded)\n2. Generate a cryptographic token (secrets.token_urlsafe)\n3. Invalidate any pending reset tokens for this user\n4. Persist the new token hash in api.password_reset_tokens (TTL 1h)\n5. Send reset email via Resend (fallback log if RESEND_API_KEY absent)\n\nRGPD: token hash is personal data. TTL = 1h. Purge planned Sprint 15.\nNot financial advice.",
        "operationId": "forgot_password_auth_forgot_password_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ForgotPasswordRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ForgotPasswordResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Forgot Password",
        "tags": [
          "auth"
        ]
      }
    },
    "/auth/keys": {
      "post": {
        "description": "Create a new API key for the authenticated user.\n\nFree tier: max 2 active keys. Raw key returned once.",
        "operationId": "create_key_auth_keys_post",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateKeyRequest",
                "default": {}
              }
            }
          }
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreatedResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Create Key",
        "tags": [
          "auth"
        ]
      }
    },
    "/auth/keys/{key_id}/revoke": {
      "post": {
        "description": "Revoke (deactivate) an API key.\n\nReturns 403 (not 404) if the key belongs to another user \u2014 anti-enumeration.",
        "operationId": "revoke_key_auth_keys__key_id__revoke_post",
        "parameters": [
          {
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "title": "Key Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RevokeKeyResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Revoke Key",
        "tags": [
          "auth"
        ]
      }
    },
    "/auth/login": {
      "post": {
        "description": "Authenticate with email + password, return JWT.\n\nError messages are deliberately generic (anti-enumeration).\nRate limited: 10 attempts / 15 min per IP (T-161 Sprint 13).",
        "operationId": "login_auth_login_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Login",
        "tags": [
          "auth"
        ]
      }
    },
    "/auth/me": {
      "delete": {
        "description": "RGPD Article 17 \u2014 right to erasure.\n\nT-165 Sprint 13.\nT-394 Sprint 27 \u2014 JWT JTI is added to the revocation blocklist post-deletion.\n\nSoft deletes the authenticated user:\n1. Revokes all active API keys.\n2. Cancels the Stripe subscription (non-blocking on error).\n3. Anonymizes email to deleted_{user_id}@portfoliq.invalid.\n4. Overwrites password_hash with an invalid bcrypt hash.\n5. Clears Stripe customer_id and subscription_id.\n6. Sets deleted_at + deletion_reason.\n7. Revokes the current JWT JTI in api.revoked_jwts (TTL 7d) \u2014 T-394.",
        "operationId": "delete_me_auth_me_delete",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteMeResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Delete Me",
        "tags": [
          "auth"
        ]
      },
      "get": {
        "description": "Return the authenticated user's profile, active keys, and current usage.",
        "operationId": "me_auth_me_get",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Me",
        "tags": [
          "auth"
        ]
      }
    },
    "/auth/me/export": {
      "get": {
        "description": "Returns a complete JSON archive of all personal data portfolIQ holds about the authenticated user. Covers: profile, API keys metadata (no raw secret), billing identifiers, last 6 months of email events, last 90 days of audit logs, SQL credentials (Enterprise), consent state, and Art. 21 objections.\n\nThe response is served with Content-Disposition: attachment so browsers trigger a file download (portfoliq-export-{user_id}-{date}.json).\n\nRGPD Art. 15: right of access. Art. 20: right to data portability.\nAudit logs are limited to 1000 rows (performance guard) and 90-day window.\nEmail events are limited to the last 6 months.\nAPI key hashes are never exposed; only last 4 chars are returned for reference.",
        "operationId": "me_export_auth_me_export_get",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeExportResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "RGPD Art. 15 + Art. 20 \u2014 Export all personal data",
        "tags": [
          "auth"
        ]
      }
    },
    "/auth/me/object-to-processing": {
      "get": {
        "description": "Return active RGPD Art. 21 objections for the authenticated user.\n\nP2-8 Sprint 36 \u2014 used by the Privacy dashboard page to show current objection state.",
        "operationId": "get_objections_auth_me_object_to_processing_get",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserObjectionsResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get Objections",
        "tags": [
          "auth"
        ]
      },
      "post": {
        "description": "RGPD Art. 21 \u2014 right to object to legitimate-interest processing (self-service).\n\nP2-8 Sprint 36 \u2014 LIA-001 \u00a7droits-des-personnes condition CLOSED.\n\nAccepted processing_category values:\n- 'marketing'       \u2192 disables all marketing email (user_email_preferences.subscribed = false)\n- 'security_logs'   \u2192 records declarative objection flag (logs kept for system security)\n- 'cloudflare_logs' \u2192 records declarative objection flag (CF logs kept by Cloudflare ToS)\n\nSecurity/Cloudflare objections are declarative flags: we cannot technically suppress\ninfrastructure logs, but we commit not to use them for behavioural analysis.\nThis is disclosed in the privacy policy.\n\nThe objection is idempotent \u2014 re-submitting the same category is a no-op (200 returned).",
        "operationId": "object_to_processing_auth_me_object_to_processing_post",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ObjectToProcessingRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ObjectToProcessingResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Object To Processing",
        "tags": [
          "auth"
        ]
      }
    },
    "/auth/register": {
      "post": {
        "description": "Initiate account registration.\n\nT-395 Sprint 27 \u2014 anti-enumeration fix.\n\nAlways returns 202 Accepted with a generic message, regardless of whether the\nemail is already registered. Account creation happens in a background task.\n\nAnti-enumeration: an attacker cannot determine if an email exists by observing\nthe response code or body.\n\nTiming-safe: a random sleep of 200\u2013400ms is applied before returning to prevent\ntiming attacks (measuring latency to infer email existence).\n\nRate limited: 5 attempts / 60 min per IP (T-161 Sprint 13).\n\nNOTE: This change alters the signup UX. Callers no longer receive a JWT +\nAPI key immediately. A confirmation email flow (T-395 / Sprint 28) will deliver\ncredentials. Until then, the background task creates the account but the JWT\nis not returned synchronously. Document in dev_report (U5 deviation).",
        "operationId": "register_auth_register_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterAck"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Register",
        "tags": [
          "auth"
        ]
      }
    },
    "/auth/reset-password": {
      "post": {
        "description": "Validate a reset token and update the user's password.\n\nSprint 14 T-202.\n\nRate limited: same bucket as forgot-password (5/h per IP).\n\nFlow:\n1. Hash the incoming raw token\n2. Look up the token in api.password_reset_tokens (must be unused, not expired)\n3. Verify user exists and is not deleted\n4. Update password hash in api.users\n5. Mark token as used (used_at = NOW())\n\nReturns 400 if token is invalid, expired, or already used.\nReturns 200 on success.\n\nRGPD: new password hash replaces the old one. Not financial advice.",
        "operationId": "reset_password_auth_reset_password_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResetPasswordRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResetPasswordResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Reset Password",
        "tags": [
          "auth"
        ]
      }
    },
    "/auth/usage": {
      "get": {
        "description": "Return 24h usage windows for all keys of the authenticated user.",
        "operationId": "usage_auth_usage_get",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Usage",
        "tags": [
          "auth"
        ]
      }
    },
    "/billing/checkout": {
      "post": {
        "description": "Create a Stripe Checkout Session for tier upgrade.\n\nReturns 503 with a human-readable message if Stripe is not configured.",
        "operationId": "checkout_billing_checkout_post",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/CheckoutResponse"
                    },
                    {
                      "$ref": "#/components/schemas/CheckoutUnavailableResponse"
                    }
                  ],
                  "title": "Response Checkout Billing Checkout Post"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Checkout",
        "tags": [
          "billing"
        ]
      }
    },
    "/billing/portal": {
      "post": {
        "description": "Create a Stripe Customer Portal session for the authenticated user.\n\nReturns 503 if Stripe is not configured.\nReturns 400 if the user has no Stripe customer ID (never subscribed).\n\nThe portal allows the user to manage their subscription, update payment\nmethods, and view invoice history.",
        "operationId": "customer_portal_billing_portal_post",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Customer Portal",
        "tags": [
          "billing"
        ]
      }
    },
    "/billing/webhook": {
      "post": {
        "description": "Handle incoming Stripe webhook events.\n\nExempt from ApiKeyMiddleware and JWT auth.\nStripe-Signature header is always verified.",
        "operationId": "webhook_billing_webhook_post",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Webhook",
        "tags": [
          "billing"
        ]
      }
    },
    "/health": {
      "get": {
        "description": "Liveness and readiness check.\n\nPerforms a real DB ping (SELECT 1) to detect connectivity issues.\n\nReturns:\n    200 {\"status\": \"ok\", \"db\": \"ok\", ...} \u2014 all systems operational\n    503 {\"status\": \"degraded\", \"db\": \"error\", ...} \u2014 DB unreachable",
        "operationId": "health_health_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Health",
        "tags": [
          "health"
        ]
      }
    },
    "/internal/email-log": {
      "post": {
        "description": "Persist an email send record from the Next.js BFF.\n\nAuth is enforced via Depends(require_internal_token) BEFORE body parsing (SEC-AUDIT M2).\n\nIdempotent on resend_id (T-327): DB-level UNIQUE INDEX (migration 041) guarantees\natomicity. ON CONFLICT (resend_id) WHERE resend_id IS NOT NULL DO NOTHING replaces\nthe former applicative SELECT-then-INSERT guard.\n\nReturns:\n    {\"ok\": True, \"inserted\": True}  \u2014 new row persisted.\n    {\"ok\": True, \"inserted\": False} \u2014 duplicate resend_id, silently skipped.",
        "operationId": "log_email_internal_email_log_post",
        "parameters": [
          {
            "in": "header",
            "name": "x-internal-token",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Internal-Token"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailLogEntry"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response Log Email Internal Email Log Post",
                  "type": "object"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Log Email",
        "tags": [
          "internal"
        ]
      }
    },
    "/internal/webhook/resend-event": {
      "post": {
        "description": "Update email_log status + propagate bounced/complained to users.\n\nAuth is enforced via Depends(require_internal_token) BEFORE body parsing (SEC-AUDIT M2).\n\nAtomic transaction:\n- Updates email_log.status for the given resend_id.\n- On bounced: sets users.email_status = 'bounced'.\n- On complained: sets users.email_status = 'complained' + unsubscribes all\n  + inserts into email_unsubscribe_log (RGPD audit trail).",
        "operationId": "webhook_resend_event_internal_webhook_resend_event_post",
        "parameters": [
          {
            "in": "header",
            "name": "x-internal-token",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Internal-Token"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResendWebhookEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response Webhook Resend Event Internal Webhook Resend Event Post",
                  "type": "object"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Webhook Resend Event",
        "tags": [
          "internal"
        ]
      }
    },
    "/v1/account": {
      "delete": {
        "description": "Canonical /v1/account path for the RGPD account deletion (tests-catalog K2). Delegates to DELETE /auth/me cascade logic:\n1. Revokes all active API keys.\n2. Cancels Stripe subscription (non-blocking on error).\n3. Anonymizes email to deleted_{user_id}@portfoliq.invalid.\n4. Overwrites password_hash with an invalid placeholder.\n5. Clears Stripe IDs and sets deleted_at.\n6. Purges PII from satellite tables (newsletter, objections, email prefs,    halal_signups, digest subscribers).\n7. Revokes current JWT JTI in the SQL blocklist (TTL 7d, T-394).\n8. Writes user.delete audit event.\n\nRGPD Art. 17: right to erasure.",
        "operationId": "account_delete_v1_account_delete",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteMeResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "RGPD Art. 17 \u2014 Delete account and cascade PII (v1/account alias)",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/account/export": {
      "get": {
        "description": "Canonical /v1/account path for the RGPD data export (tests-catalog K1). Returns the same payload as GET /auth/me/export: profile, API keys metadata (hashes never returned), billing identifiers, email events, audit logs, SQL credentials, consent state, and Art. 21 objections.\n\nContent-Disposition: attachment triggers browser file download.\nRGPD Art. 15 (right of access) + Art. 20 (right to portability).",
        "operationId": "account_export_v1_account_export_get",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeExportResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "RGPD Art. 15 + Art. 20 \u2014 Export all user data (v1/account alias)",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/admin/ai-analysis/restatements": {
      "get": {
        "description": "Returns paginated restatement events from dv.sat_ai_restatement_audit. Ordered by created_at DESC. Cursor-based pagination via `cursor` param. Scope required: admin:restate. LEGAL: Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "list_restatements_v1_admin_ai_analysis_restatements_get",
        "parameters": [
          {
            "description": "Max items per page (1\u2013200).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Max items per page (1\u2013200).",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Opaque pagination cursor from previous response.next_cursor.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Opaque pagination cursor from previous response.next_cursor.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestatementListResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List restatement audit rows (admin:restate)",
        "tags": [
          "admin-restatements"
        ]
      }
    },
    "/v1/admin/ai-analysis/{snapshot_id}/restate": {
      "post": {
        "description": "Records a RESTATEMENT event for the given snapshot. Inserts into dv.sat_ai_restatement_audit and schedules a best-effort AI re-run with restatement_of marker (asyncio.create_task, fire-and-forget). Returns 202 immediately with the audit row \u2014 re-run is asynchronous. Scope required: admin:restate. 404 if snapshot_id is unknown. 422 if reason < 10 chars. LEGAL: Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "trigger_restatement_v1_admin_ai_analysis__snapshot_id__restate_post",
        "parameters": [
          {
            "description": "raw.ai_analysis_runs.id of the snapshot to restate.",
            "in": "path",
            "name": "snapshot_id",
            "required": true,
            "schema": {
              "description": "raw.ai_analysis_runs.id of the snapshot to restate.",
              "title": "Snapshot Id",
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RestatementCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestatementResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Trigger AI analysis restatement (admin:restate)",
        "tags": [
          "admin-restatements"
        ]
      }
    },
    "/v1/admin/newsletter/generate-preview/{month}": {
      "post": {
        "description": "Queries marts.fact_ai_analysis for the top 10 catalysts by confidence within the last 30 days and stores the result as a 'preview' issue. Requires scope admin:newsletter (Pro tier admin only). Garde-fou: no email is sent at this step.",
        "operationId": "generate_preview_v1_admin_newsletter_generate_preview__month__post",
        "parameters": [
          {
            "in": "path",
            "name": "month",
            "required": true,
            "schema": {
              "title": "Month",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_NewsletterIssuePreview_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Generate newsletter preview for a given month",
        "tags": [
          "admin-newsletter"
        ]
      }
    },
    "/v1/admin/newsletter/send/{issue_id}": {
      "post": {
        "description": "Sends the newsletter issue to all active subscribers. Requires scope admin:newsletter. Garde-fou: issue must be in 'preview' status before sending. No auto-send: this endpoint must be called explicitly by an admin.",
        "operationId": "send_issue_v1_admin_newsletter_send__issue_id__post",
        "parameters": [
          {
            "in": "path",
            "name": "issue_id",
            "required": true,
            "schema": {
              "title": "Issue Id",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_NewsletterSendResponse_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Send a newsletter issue (manual \u2014 human-in-the-loop)",
        "tags": [
          "admin-newsletter"
        ]
      }
    },
    "/v1/ai-analysis/bulk-history": {
      "post": {
        "description": "Fetch AI analysis history for up to 50 symbols in a single request. **Sync** (\u226410 symbols): HTTP 200 with `results[]` direct. **Async** (>10 symbols): HTTP 202 with deterministic `job_id` (no queue \u2014 Sprint 91). **Partial failure** (some symbols fail): HTTP 207 Multi-Status. Tier window: Free \u2264 90 days, Starter+ \u2264 3 years. Scope required: `ai:read`. LEGAL: Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "post_bulk_history_v1_ai_analysis_bulk_history_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkHistoryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Synchronous batch \u2014 all rows returned directly."
          },
          "202": {
            "description": "Accepted \u2014 job_id returned for large batches (>10 symbols)."
          },
          "207": {
            "description": "Partial success \u2014 some symbols failed, others succeeded."
          },
          "403": {
            "description": "Forbidden \u2014 ai:read scope required."
          },
          "422": {
            "description": "Validation error \u2014 bad input or all symbols failed."
          }
        },
        "summary": "AI analysis \u2014 bulk history batch (BRICK-AI-08 v2)",
        "tags": [
          "ai-analysis-bulk"
        ]
      }
    },
    "/v1/ai-analysis/changes": {
      "get": {
        "description": "Paginated cross-asset feed of AI analysis changes. Returns assets whose analysis snapshot changed within the queried window. Cursor-based pagination: pass `cursor` from the previous response's `next_cursor`. Entitlement: `ai:read` scope (Starter+ tier). LEGAL: Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_ai_analysis_changes_v1_ai_analysis_changes_get",
        "parameters": [
          {
            "description": "Analysis type filter (halal_analysis | market_context | regime). Required.",
            "in": "query",
            "name": "type",
            "required": true,
            "schema": {
              "description": "Analysis type filter (halal_analysis | market_context | regime). Required.",
              "title": "Type",
              "type": "string"
            }
          },
          {
            "description": "ISO 8601 lower bound on computed_at (UTC). Required.",
            "in": "query",
            "name": "from",
            "required": true,
            "schema": {
              "description": "ISO 8601 lower bound on computed_at (UTC). Required.",
              "format": "date-time",
              "title": "From",
              "type": "string"
            }
          },
          {
            "description": "ISO 8601 upper bound on computed_at (UTC). Required.",
            "in": "query",
            "name": "to",
            "required": true,
            "schema": {
              "description": "ISO 8601 upper bound on computed_at (UTC). Required.",
              "format": "date-time",
              "title": "To",
              "type": "string"
            }
          },
          {
            "description": "Filter by change type (DATA_REFRESH | MODEL_UPGRADE | METHODOLOGY_CHANGE | RESTATEMENT).",
            "in": "query",
            "name": "change_type",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "DATA_REFRESH",
                    "MODEL_UPGRADE",
                    "METHODOLOGY_CHANGE",
                    "RESTATEMENT"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by change type (DATA_REFRESH | MODEL_UPGRADE | METHODOLOGY_CHANGE | RESTATEMENT).",
              "title": "Change Type"
            }
          },
          {
            "description": "Opaque base64 pagination cursor from a previous response's next_cursor.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Opaque base64 pagination cursor from a previous response's next_cursor.",
              "title": "Cursor"
            }
          },
          {
            "description": "Max results per page (1\u2013200). Default: 50.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Max results per page (1\u2013200). Default: 50.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AIAnalysisChangesResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "AI analysis \u2014 cross-asset changes feed (BRICK-AI-08)",
        "tags": [
          "ai-analysis",
          "ai-analysis"
        ]
      }
    },
    "/v1/ai-analysis/stream": {
      "get": {
        "description": "Stream AI analysis snapshots as NDJSON. Each line is an independent JSON object \u2014 parse line-by-line. Use `cursor=` to resume a partially completed stream. Designed for dbt pack bulk seeding (1000 tokens \u00d7 365 days). **Tier window**: Free \u2264 90 days, Starter+ \u2264 3 years. **Limit**: max 5000 rows per stream call. Use cursor pagination for more. **Scope required**: `ai:read`. LEGAL: Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_ai_analysis_stream_v1_ai_analysis_stream_get",
        "parameters": [
          {
            "description": "Response format. Only 'ndjson' is supported in this version.",
            "in": "query",
            "name": "format",
            "required": false,
            "schema": {
              "const": "ndjson",
              "default": "ndjson",
              "description": "Response format. Only 'ndjson' is supported in this version.",
              "title": "Format",
              "type": "string"
            }
          },
          {
            "description": "Analysis type filter (market_context | halal_analysis | regime).",
            "in": "query",
            "name": "type",
            "required": true,
            "schema": {
              "description": "Analysis type filter (market_context | halal_analysis | regime).",
              "title": "Type",
              "type": "string"
            }
          },
          {
            "description": "Start of the date window (ISO 8601, UTC).",
            "in": "query",
            "name": "from",
            "required": true,
            "schema": {
              "description": "Start of the date window (ISO 8601, UTC).",
              "format": "date-time",
              "title": "From",
              "type": "string"
            }
          },
          {
            "description": "End of the date window (ISO 8601, UTC).",
            "in": "query",
            "name": "to",
            "required": true,
            "schema": {
              "description": "End of the date window (ISO 8601, UTC).",
              "format": "date-time",
              "title": "To",
              "type": "string"
            }
          },
          {
            "description": "CSV of asset identifiers to filter on (optional). Max 50 symbols. Example: 'bitcoin,ethereum,solana'.",
            "in": "query",
            "name": "symbols",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "CSV of asset identifiers to filter on (optional). Max 50 symbols. Example: 'bitcoin,ethereum,solana'.",
              "title": "Symbols"
            }
          },
          {
            "description": "Max rows to stream. Default 1000, max 5000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 1000,
              "description": "Max rows to stream. Default 1000, max 5000.",
              "maximum": 5000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Opaque cursor token for stream resume. Use the cursor_token from the last received StreamRow.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Opaque cursor token for stream resume. Use the cursor_token from the last received StreamRow.",
              "title": "Cursor"
            }
          },
          {
            "description": "DB fetch batch size (default 1000). Operator-tunable.",
            "in": "query",
            "name": "chunk_size",
            "required": false,
            "schema": {
              "default": 1000,
              "description": "DB fetch batch size (default 1000). Operator-tunable.",
              "maximum": 5000,
              "minimum": 1,
              "title": "Chunk Size",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              },
              "application/x-ndjson": {}
            },
            "description": "NDJSON stream \u2014 one JSON line per snapshot row."
          },
          "403": {
            "description": "Forbidden \u2014 ai:read scope required."
          },
          "422": {
            "description": "Validation error \u2014 invalid format, from >= to, window too large for tier, or limit > 5000."
          }
        },
        "summary": "AI analysis \u2014 NDJSON streaming (BRICK-AI-08 v2)",
        "tags": [
          "ai-analysis-stream"
        ]
      }
    },
    "/v1/ai/methodology": {
      "get": {
        "description": "Return the latest published AI-enrichment evaluation report.\n\nThe report exposes the five evaluation metrics (hallucination, consistency,\ncoverage, recency, abstention) plus the AMF forbidden-key guard, with their\ngate thresholds and pass/fail status \u2014 measured on a fixed golden set.\n\nA ``status`` of ``\"seed\"`` means the figures are illustrative seed values\n(deterministic metrics measured, LLM-judge metrics pending the first full\ncampaign). ``\"measured\"`` means a full campaign has run.",
        "operationId": "get_ai_methodology_v1_ai_methodology_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Latest AI-enrichment evaluation metrics (M1-M5 + AMF guard)."
          }
        },
        "summary": "AI enrichment evaluation report (public, machine-readable)",
        "tags": [
          "ai-methodology"
        ]
      }
    },
    "/v1/analytics/btc-cycle": {
      "get": {
        "description": "Compute days since last BTC halving + projected next halving + cycle phase.\n\nMethodology v1.0 \u2014 calendar-based cycle position. Historical pattern\nis provided as descriptive context, NOT a prediction.",
        "operationId": "get_btc_cycle_v1_analytics_btc_cycle_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BtcCycleResponse"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Bitcoin halving cycle position",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/compare": {
      "get": {
        "description": "Hypothetical investment outcome across N assets.\n\nNOT financial advice. Past performance is no guarantee of future results.",
        "operationId": "get_compare_v1_analytics_compare_get",
        "parameters": [
          {
            "description": "Comma-separated list of 'kind:symbol'. Ex: crypto:bitcoin,fred:SP500,fred:NASDAQCOM.",
            "in": "query",
            "name": "assets",
            "required": true,
            "schema": {
              "description": "Comma-separated list of 'kind:symbol'. Ex: crypto:bitcoin,fred:SP500,fred:NASDAQCOM.",
              "examples": [
                "crypto:bitcoin,fred:SP500"
              ],
              "title": "Assets",
              "type": "string"
            }
          },
          {
            "description": "Hypothetical investment budget.",
            "in": "query",
            "name": "budget",
            "required": false,
            "schema": {
              "default": 1000.0,
              "description": "Hypothetical investment budget.",
              "exclusiveMinimum": 0,
              "maximum": 1000000000,
              "title": "Budget",
              "type": "number"
            }
          },
          {
            "description": "Investment start date (YYYY-MM-DD).",
            "in": "query",
            "name": "start_date",
            "required": true,
            "schema": {
              "description": "Investment start date (YYYY-MM-DD).",
              "format": "date",
              "title": "Start Date",
              "type": "string"
            }
          },
          {
            "description": "End date (default: today).",
            "in": "query",
            "name": "end_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date (default: today).",
              "title": "End Date"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompareResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Hypothetical investment comparator across assets",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/correlations/matrix": {
      "get": {
        "description": "Return NxN correlation matrix as a flat list of (asset_a, asset_b) pairs.\n\nData comes from marts.mart_correlations_cross_asset (computed by data-engineer).\nPairs without data return null pearson/spearman + count under missing_pairs.",
        "operationId": "get_correlations_matrix_v1_analytics_correlations_matrix_get",
        "parameters": [
          {
            "description": "Comma-separated 'kind:symbol' list. Max 8 assets to keep payload reasonable.",
            "in": "query",
            "name": "assets",
            "required": true,
            "schema": {
              "description": "Comma-separated 'kind:symbol' list. Max 8 assets to keep payload reasonable.",
              "examples": [
                "crypto:BTC,crypto:ETH,stock:AAPL"
              ],
              "title": "Assets",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "period",
            "required": false,
            "schema": {
              "default": "90d",
              "enum": [
                "30d",
                "90d",
                "1y"
              ],
              "title": "Period",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CorrelationMatrixResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "NxN correlation matrix across a list of assets",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/macro-regime": {
      "get": {
        "description": "Classify current macro regime from FRED signals.\n\nMethodology v1.0 \u2014 deterministic rule-based on VIX percentiles + yield\ncurve spread + S&P 500 momentum. Sources: FRED (DFF, DGS2, DGS10, VIXCLS,\nSP500, DEXUSEU). Methodology fully disclosed; no black box ML.",
        "operationId": "get_macro_regime_v1_analytics_macro_regime_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MacroRegimeResponse"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Macro regime detector \u2014 risk-on / risk-off / stagflation / neutral",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/analytics/yield-curve": {
      "get": {
        "description": "Return current 10Y-2Y spread + days-since-inversion clock.\n\nSource: FRED DGS2, DGS10 (public domain). Methodology v1.0.",
        "operationId": "get_yield_curve_v1_analytics_yield_curve_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/YieldCurveResponse"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "US Treasury yield curve (DGS10 - DGS2) \u2014 recession indicator",
        "tags": [
          "analytics"
        ]
      }
    },
    "/v1/api-keys": {
      "get": {
        "description": "List active API keys for the authenticated user.\n\nRaw key is never returned \u2014 only key_prefix for identification.",
        "operationId": "list_api_keys_v1_api_keys_get",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyListResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List Api Keys",
        "tags": [
          "api-keys"
        ]
      },
      "post": {
        "description": "Generate a new API key for the authenticated user.\n\n- Key format: \"piq_\" + secrets.token_urlsafe(32).\n- Raw key returned once \u2014 never stored. SHA-256 hash persisted in DB.\n- Max 5 active keys per user. Returns HTTP 422 if limit reached.\n- key_prefix (first 8 chars of raw_key) stored for dashboard display.",
        "operationId": "create_api_key_v1_api_keys_post",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiKeyCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreateResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Create Api Key",
        "tags": [
          "api-keys"
        ]
      }
    },
    "/v1/api-keys/{key_id}": {
      "delete": {
        "description": "Revoke an API key (soft delete \u2014 is_active = FALSE).\n\nReturns 404 if the key is not found or does not belong to the caller \u2014\nno oracle on key existence for other users.",
        "operationId": "revoke_api_key_v1_api_keys__key_id__delete",
        "parameters": [
          {
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "title": "Key Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Revoke Api Key",
        "tags": [
          "api-keys"
        ]
      }
    },
    "/v1/asset/{symbol}/identifiers": {
      "get": {
        "description": "Returns Bloomberg FIGI + cross-reference identifiers (ISIN, CUSIP, SEDOL, WKN) for a financial instrument identified by ticker symbol. Queries local DB cache first; falls back to live OpenFIGI API on cache miss. Secondary identifiers are jurisdiction-specific: CUSIP=US/CA only, SEDOL=UK/IE only, WKN=DE only, ISIN=when provided by OpenFIGI. Source: Bloomberg OpenFIGI (open standard, redistribution permitted).",
        "operationId": "get_asset_identifiers_v1_asset__symbol__identifiers_get",
        "parameters": [
          {
            "in": "path",
            "name": "symbol",
            "required": true,
            "schema": {
              "title": "Symbol",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentifierResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get cross-reference identifiers for an asset",
        "tags": [
          "identifiers"
        ]
      }
    },
    "/v1/asset/{symbol}/wikidata": {
      "get": {
        "description": "Return Wikidata-sourced business metadata for a financial instrument identified by its ticker symbol. Data served from DB cache only (populated by seed-wikidata-top-stocks.py). Fields: CEO, employees, industry, inception date, ISIN, LEI cross-ref, parent company, subsidiaries. Source: Wikidata CC0.",
        "operationId": "get_asset_wikidata_v1_asset__symbol__wikidata_get",
        "parameters": [
          {
            "in": "path",
            "name": "symbol",
            "required": true,
            "schema": {
              "title": "Symbol",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WikidataResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get Wikidata business metadata for an asset",
        "tags": [
          "wikidata"
        ]
      }
    },
    "/v1/asset/{ticker}/companies-house": {
      "get": {
        "description": "Return Companies House UK legal registry attributes for an XLON-listed asset. Covers: company_number, company_type (PLC/Ltd/LLP), company_status (active/liquidation/dissolved), date_of_creation, UK SIC codes, registered office address, annual filings URL. Data served from DB cache (populated by seed-companies-house-xlon.py). Source: Companies House UK \u2014 Open Government Licence v3.0 (OGL v3, commercial-friendly).",
        "operationId": "get_asset_companies_house_v1_asset__ticker__companies_house_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompaniesHouseResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get Companies House UK legal registry data for an XLON asset",
        "tags": [
          "companies_house"
        ]
      }
    },
    "/v1/asset/{ticker}/edinet-filings": {
      "get": {
        "description": "Returns EDINET filing metadata for a Japan Exchange Group (XJPX) stock. Covers top 20 XJPX stocks: Toyota (7203), Sony (6758), SoftBank (9984), Mitsubishi UFJ (8306), Recruit (6098), Lasertec (6920), Japan Tobacco (2914), Tokyo Electron (8035), Keyence (6861), Nintendo (7974), Shin-Etsu (4063), Mitsui (8031), Honda (7267), Hitachi (6501), Chugai (4519), Seven & i (3382), NTT (9432), Daikin (6367), SMFG (8316), JR Tokai (9022). Source: EDINET (FSA Japan). License: PDL 1.0.",
        "operationId": "get_edinet_filings_v1_asset__ticker__edinet_filings_get",
        "parameters": [
          {
            "description": "TSE 4-digit ticker (XJPX). E.g. '7203' for Toyota.",
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "description": "TSE 4-digit ticker (XJPX). E.g. '7203' for Toyota.",
              "examples": {
                "toyota": {
                  "value": "7203"
                }
              },
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Maximum filings to return. Default: 20, max: 200.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Maximum filings to return. Default: 20, max: 200.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          },
          {
            "description": "Only return filings on or after this date (YYYY-MM-DD).",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only return filings on or after this date (YYYY-MM-DD).",
              "examples": {
                "one_year": {
                  "value": "2024-01-01"
                }
              },
              "title": "Since"
            }
          },
          {
            "description": "Filter by document type: 'Annual', 'Quarterly', 'Semi-annual', 'Other'. Default: all types.",
            "in": "query",
            "name": "doc_type",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by document type: 'Annual', 'Quarterly', 'Semi-annual', 'Other'. Default: all types.",
              "examples": {
                "annual_only": {
                  "value": "Annual"
                }
              },
              "title": "Doc Type"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EdinetFilingsResponse"
                }
              }
            },
            "description": "Filings returned successfully."
          },
          "404": {
            "description": "Unknown ticker or no filings found."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "EDINET filings for a XJPX stock",
        "tags": [
          "edinet"
        ]
      }
    },
    "/v1/asset/{ticker}/legal-entity": {
      "get": {
        "description": "Return the primary issuer legal entity for a financial instrument identified by ticker. Requires the asset to be in dv.hub_asset and linked via dv.link_asset_legal_entity (populated by seed script or discover endpoint). Source: GLEIF CC0.",
        "operationId": "get_asset_legal_entity_v1_asset__ticker__legal_entity_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegalEntityResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get legal entity for an asset",
        "tags": [
          "legal-entity"
        ]
      }
    },
    "/v1/asset/{ticker}/sirene": {
      "get": {
        "description": "Return INSEE SIRENE French legal registry attributes for an XPAR-listed asset. Covers: SIREN/SIRET, forme juridique (SA/SAS/SE/SCA), code NAF (French SIC equivalent), adresse si\u00e8ge social, date de cr\u00e9ation, \u00e9tat administratif. Data served from DB cache (populated by seed-insee-sirene-xpar.py). Source: INSEE SIRENE API V3.11 \u2014 Etalab Open License 2.0 (commercial-friendly).",
        "operationId": "get_asset_sirene_v1_asset__ticker__sirene_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SireneResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get INSEE SIRENE legal registry data for a French XPAR asset",
        "tags": [
          "sirene"
        ]
      }
    },
    "/v1/assets": {
      "get": {
        "description": "List crypto assets with optional tier filter (1=top 50, 2=top 200, 3=top 1000). Returns basic market data (ticker, name, price, market cap, 24h change). Free tier: no scope gate (ohlcv:daily implicit). Not financial advice. Methodology disclosed.",
        "operationId": "list_assets_v1_assets_get",
        "parameters": [
          {
            "description": "Filter by tier (1-3)",
            "in": "query",
            "name": "tier",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maximum": 3,
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by tier (1-3)",
              "title": "Tier"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_AssetCard__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List assets",
        "tags": [
          "assets"
        ]
      }
    },
    "/v1/assets/{asset_id}/ai-analysis/history": {
      "get": {
        "description": "Returns paginated AI analysis history for a financial asset. Supports bi-temporal querying via `?as_of=<RFC3339>`. Quarter shorthand accepted: `2025-Q4` \u2192 2025-12-31T23:59:59Z. **Entitlement**: Free (halal_analysis only, top-200, 90d); Starter (all types, top-1000, 3yr); Growth (+ data_lineage). Constant-time response \u2265 100ms (Brumley-Boneh 2003 mitigation). LEGAL: Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_ai_analysis_history_v1_assets__asset_id__ai_analysis_history_get",
        "parameters": [
          {
            "description": "Asset identifier \u2014 coingecko slug (e.g. 'bitcoin', 'ethereum'). Type: string. NOT the integer asset_id from /v1/star/dim/assets/. SDK generators: treat as string, not integer.",
            "in": "path",
            "name": "asset_id",
            "required": true,
            "schema": {
              "description": "Asset identifier \u2014 coingecko slug (e.g. 'bitcoin', 'ethereum'). Type: string. NOT the integer asset_id from /v1/star/dim/assets/. SDK generators: treat as string, not integer.",
              "title": "Asset Id",
              "type": "string"
            }
          },
          {
            "description": "Analysis type: halal_analysis | market_context | regime",
            "in": "query",
            "name": "type",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/AiAnalysisType",
              "description": "Analysis type: halal_analysis | market_context | regime"
            }
          },
          {
            "description": "Bi-temporal filter. RFC 3339 datetime or quarter shorthand (e.g. 2025-Q4). If absent, returns the most recent analyses. Future dates are rejected (HTTP 400).",
            "in": "query",
            "name": "as_of",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Bi-temporal filter. RFC 3339 datetime or quarter shorthand (e.g. 2025-Q4). If absent, returns the most recent analyses. Future dates are rejected (HTTP 400).",
              "title": "As Of"
            }
          },
          {
            "description": "Max number of results (1\u201350).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 10,
              "description": "Max number of results (1\u201350).",
              "maximum": 50,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiAnalysisHistoryResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "AI analysis history \u2014 bi-temporal (AI-ACT-06)",
        "tags": [
          "ai-analysis",
          "ai-analysis"
        ]
      }
    },
    "/v1/assets/{asset_id}/ai-analysis/history/diff": {
      "get": {
        "description": "Compares two AI analysis snapshots within a [from, to] time window. Returns structured field-level changes. **Raw text diffs are never exposed** (AMF \u00a75.3) \u2014 text changes are indicated by `text_changed` (bool) and `cosine_similarity` (float) only. Entitlement: `ai:read` scope (Starter+ tier). LEGAL: Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_ai_analysis_diff_v1_assets__asset_id__ai_analysis_history_diff_get",
        "parameters": [
          {
            "description": "Asset identifier (e.g. 'bitcoin', 'ethereum').",
            "in": "path",
            "name": "asset_id",
            "required": true,
            "schema": {
              "description": "Asset identifier (e.g. 'bitcoin', 'ethereum').",
              "title": "Asset Id",
              "type": "string"
            }
          },
          {
            "description": "ISO 8601 start datetime (UTC). Resolves snapshot_before = most recent generated_at \u2264 from.",
            "in": "query",
            "name": "from",
            "required": true,
            "schema": {
              "description": "ISO 8601 start datetime (UTC). Resolves snapshot_before = most recent generated_at \u2264 from.",
              "format": "date-time",
              "title": "From",
              "type": "string"
            }
          },
          {
            "description": "ISO 8601 end datetime (UTC). Resolves snapshot_after = most recent generated_at \u2264 to.",
            "in": "query",
            "name": "to",
            "required": true,
            "schema": {
              "description": "ISO 8601 end datetime (UTC). Resolves snapshot_after = most recent generated_at \u2264 to.",
              "format": "date-time",
              "title": "To",
              "type": "string"
            }
          },
          {
            "description": "Analysis type: halal_analysis | market_context | regime.",
            "in": "query",
            "name": "type",
            "required": true,
            "schema": {
              "description": "Analysis type: halal_analysis | market_context | regime.",
              "enum": [
                "halal_analysis",
                "market_context",
                "regime"
              ],
              "title": "Type",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AIAnalysisDiffResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "detail": "No snapshot found for asset 'bitcoin' in the requested time range.",
                  "status": 404,
                  "title": "Not Found",
                  "type": "https://portfoliq.io/problems/not-found"
                }
              }
            },
            "description": "Asset or snapshot not found (RFC 7807 problem detail)."
          },
          "422": {
            "description": "Validation error (invalid params, from > to, unknown type)."
          }
        },
        "summary": "AI analysis \u2014 snapshot diff (BRICK-AI-08)",
        "tags": [
          "ai-analysis",
          "ai-analysis"
        ]
      }
    },
    "/v1/assets/{asset_id}/ai-analysis/latest": {
      "get": {
        "description": "Returns the most recent AI analysis snapshot for the given asset and analysis type. Entitlement: `ai:read` scope (Starter+ tier). Growth tier (`ai:lineage` scope) additionally exposes `provenance.prompt_hash`. **Freshness** thresholds: fresh (<36h), stale (36\u201372h), expired (>72h). **confidence** is deterministic (T-648) \u2014 not Claude self-report. LEGAL: Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_ai_analysis_latest_v1_assets__asset_id__ai_analysis_latest_get",
        "parameters": [
          {
            "description": "Asset identifier (e.g. 'bitcoin', 'ethereum').",
            "in": "path",
            "name": "asset_id",
            "required": true,
            "schema": {
              "description": "Asset identifier (e.g. 'bitcoin', 'ethereum').",
              "title": "Asset Id",
              "type": "string"
            }
          },
          {
            "description": "Analysis type: halal_analysis | market_context | regime.",
            "in": "query",
            "name": "type",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/AiAnalysisType",
              "description": "Analysis type: halal_analysis | market_context | regime."
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AIAnalysisLatestResponse"
                }
              }
            },
            "description": "Snapshot found, or asset known but never analysed (coverage block)."
          },
          "404": {
            "description": "Asset not found."
          },
          "422": {
            "description": "Invalid query parameter."
          }
        },
        "summary": "AI analysis \u2014 latest snapshot (BRICK-AI-08)",
        "tags": [
          "ai-analysis"
        ]
      }
    },
    "/v1/assets/{coingecko_id}/ai": {
      "get": {
        "description": "Returns the latest AI-generated analysis for the given asset. If scope ai:read is absent, returns null fields + _upsell marker. If scope is present but no analysis exists, returns empty block. Requires scope: ai:read (Starter tier and above). Not financial advice. AI-generated analysis. Methodology disclosed.",
        "operationId": "get_asset_ai_v1_assets__coingecko_id__ai_get",
        "parameters": [
          {
            "in": "path",
            "name": "coingecko_id",
            "required": true,
            "schema": {
              "title": "Coingecko Id",
              "type": "string"
            }
          },
          {
            "description": "Analysis type filter. When provided, returns that specific analysis type from the DB directly (no LLM call). Must be in the allowed set. Extended types: growth_analysis, valuation_analysis, competitive_moat, risk_assessment, catalysts_outlook, narrative_thesis, tokenomics_deep_dive, peer_comparison. Legacy types: token_classification, fundamental_summary, etc. Returns 404 if the type is not applicable to crypto assets.",
            "in": "query",
            "name": "type",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Analysis type filter. When provided, returns that specific analysis type from the DB directly (no LLM call). Must be in the allowed set. Extended types: growth_analysis, valuation_analysis, competitive_moat, risk_assessment, catalysts_outlook, narrative_thesis, tokenomics_deep_dive, peer_comparison. Legacy types: token_classification, fundamental_summary, etc. Returns 404 if the type is not applicable to crypto assets.",
              "title": "Type"
            }
          },
          {
            "description": "Requested locale for AI analysis: 'en' (default), 'fr' (Pro tier), 'ar' (Enterprise tier). Falls back to Accept-Language header, then 'en'. If requested locale has no data, EN is served and meta.fallback_used=true.",
            "in": "query",
            "name": "lang",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Requested locale for AI analysis: 'en' (default), 'fr' (Pro tier), 'ar' (Enterprise tier). Falls back to Accept-Language header, then 'en'. If requested locale has no data, EN is served and meta.fallback_used=true.",
              "title": "Lang"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_AiAnalysisBlock_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get AI-generated analysis for an asset",
        "tags": [
          "assets",
          "ai"
        ],
        "x-required-scope": "ai:read"
      }
    },
    "/v1/assets/{coingecko_id}/fundamentals": {
      "get": {
        "description": "Returns the latest P/S (Price-to-Sales) and P/R (Price-to-Revenue) valuation ratios for the given asset, computed from DeFiLlama protocol fees data (MIT licence). Ratios are NULL if no DeFiLlama protocol is linked to the asset or fees data is unavailable. Requires scope: fundamentals:read (Growth tier and above). Not financial advice. Factual valuation metrics only. Methodology disclosed.",
        "operationId": "get_asset_fundamentals_v1_assets__coingecko_id__fundamentals_get",
        "parameters": [
          {
            "in": "path",
            "name": "coingecko_id",
            "required": true,
            "schema": {
              "title": "Coingecko Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_FundamentalsResponse_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get asset fundamental valuation ratios (P/S, P/R)",
        "tags": [
          "assets",
          "fundamentals"
        ],
        "x-required-scope": "fundamentals:read"
      }
    },
    "/v1/assets/{coingecko_id}/ohlcv": {
      "get": {
        "description": "Returns the daily VWAP price series for the given asset. Free tier: J-1 only (single candle). Starter tier: rolling 365-day window. Growth tier: full available history (~3 years). Source: VWAP consensus multi-exchange (methodology/vwap-consensus-v1.3.md). If no VWAP data exists (DEX-only token), returns empty candles list with 200. Not financial advice. Methodology disclosed.",
        "operationId": "get_asset_ohlcv_v1_assets__coingecko_id__ohlcv_get",
        "parameters": [
          {
            "in": "path",
            "name": "coingecko_id",
            "required": true,
            "schema": {
              "title": "Coingecko Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_OhlcvResponse_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get OHLCV/VWAP daily price series",
        "tags": [
          "assets",
          "ohlcv"
        ]
      }
    },
    "/v1/assets/{coingecko_id}/onchain": {
      "get": {
        "description": "Returns the latest BTC on-chain metrics computed from the public Bitcoin blockchain (bigquery-public-data.crypto_bitcoin, MIT licence). Metrics: Realized Cap, MVRV ratio, SOPR, NUPL, HODL waves (10 age buckets). These are factual descriptive metrics \u2014 not financial advice. Methodology: methodology/onchain-realized-metrics-v1.0.md. Requires scope: onchain:read (Growth tier and above). Currently available for Bitcoin (BTC) only. Not financial advice. Methodology disclosed.",
        "operationId": "get_asset_onchain_v1_assets__coingecko_id__onchain_get",
        "parameters": [
          {
            "in": "path",
            "name": "coingecko_id",
            "required": true,
            "schema": {
              "title": "Coingecko Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_OnchainMetricsResponse_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get BTC on-chain realized metrics (MVRV, SOPR, NUPL, HODL waves)",
        "tags": [
          "assets",
          "onchain"
        ],
        "x-required-scope": "onchain:read"
      }
    },
    "/v1/assets/{ticker}": {
      "get": {
        "description": "Returns a single asset card identified by ticker (e.g. 'BTC', 'ETH'). The path parameter is matched case-insensitively against the ticker field. Free tier: no scope gate. Returns basic market data. Not financial advice. Methodology disclosed.",
        "operationId": "get_asset_v1_assets__ticker__get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_AssetCard_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get asset by coingecko_id",
        "tags": [
          "assets"
        ]
      }
    },
    "/v1/billing/crypto/checkout": {
      "post": {
        "description": "Creates a hosted payment charge via the active processor (CoinGate by default). Returns the hosted payment URL. Settlement in EUR \u2014 PIQ never holds crypto. Returns 503 if CRYPTO_BILLING_ENABLED=false (default \u2014 feature dormant). Tier is activated on payment confirmation via /v1/billing/crypto/webhook.",
        "operationId": "crypto_checkout_v1_billing_crypto_checkout_post",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CryptoCheckoutRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CryptoCheckoutResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Create a crypto checkout session (multi-crypto, EUR settlement, prepaid)",
        "tags": [
          "billing-crypto"
        ]
      }
    },
    "/v1/billing/sql-credentials": {
      "get": {
        "description": "Returns the list of active (non-revoked) SQL credentials for the current API key. The password and password_hash are never returned. Requires scope star:agg (Growth+ tier). Response is wrapped in ApiResponse envelope: {data: [...], meta: {...}}.",
        "operationId": "list_sql_credentials_v1_billing_sql_credentials_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_SqlCredentialsListItem__"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "List active SQL credentials (Growth+)",
        "tags": [
          "billing-sql"
        ]
      },
      "post": {
        "description": "Creates a PostgreSQL login user with read-only access to the star_public schema. The plaintext password is returned exactly once and cannot be retrieved again. Limit: 5 active credentials per API key. Requires scope star:agg (Growth+ tier).",
        "operationId": "create_sql_credential_v1_billing_sql_credentials_post",
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SqlCredentialsCreateResponse"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Provision a PostgreSQL SQL credential (Growth+)",
        "tags": [
          "billing-sql"
        ]
      }
    },
    "/v1/billing/sql-credentials/{username}": {
      "delete": {
        "description": "Revokes a PostgreSQL SQL credential belonging to the current API key. The PostgreSQL user is dropped and the credential is marked as revoked. Returns 403 if the credential does not belong to the current API key. Returns 404 if the credential does not exist or is already revoked.",
        "operationId": "revoke_sql_credential_v1_billing_sql_credentials__username__delete",
        "parameters": [
          {
            "in": "path",
            "name": "username",
            "required": true,
            "schema": {
              "title": "Username",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Revoke a SQL credential (Growth+)",
        "tags": [
          "billing-sql"
        ]
      }
    },
    "/v1/catalog/cryptos": {
      "get": {
        "description": "Returns a paginated, ordered list of crypto assets from dv.hub_asset enriched with portfolIQ VWAP consensus price (derived, redistribuable) and CoinGecko metadata (name, symbol, rank, circulating_supply). Only assets with CoinGecko metadata are returned; price_usd is null when VWAP consensus is insufficient (< 3 exchanges). Use case: HS build-time pre-analysis of top-1000 cryptos (P0). Attribution: Powered by CoinGecko (metadata). Price: portfolIQ VWAP consensus. Scope: catalog:read.",
        "operationId": "list_crypto_catalog_v1_catalog_cryptos_get",
        "parameters": [
          {
            "description": "Sort order: 'market_cap_desc' (default) = largest market cap first, 'symbol_asc' = alphabetical by ticker, 'name_asc' = alphabetical by name.",
            "in": "query",
            "name": "order",
            "required": false,
            "schema": {
              "default": "market_cap_desc",
              "description": "Sort order: 'market_cap_desc' (default) = largest market cap first, 'symbol_asc' = alphabetical by ticker, 'name_asc' = alphabetical by name.",
              "enum": [
                "market_cap_desc",
                "symbol_asc",
                "name_asc"
              ],
              "title": "Order",
              "type": "string"
            }
          },
          {
            "description": "Number of results per page. Min: 1, max: 1000, default: 100.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Number of results per page. Min: 1, max: 1000, default: 100.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset (number of records to skip). Default: 0.",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset (number of records to skip). Default: 0.",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          },
          {
            "description": "Category filter. Values: 'stable', 'defi', 'infrastructure'. NOTE: category columns not yet populated (DAT-008 scope). Setting this parameter returns an empty result set.",
            "in": "query",
            "name": "filter",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "stable",
                    "defi",
                    "infrastructure"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Category filter. Values: 'stable', 'defi', 'infrastructure'. NOTE: category columns not yet populated (DAT-008 scope). Setting this parameter returns an empty result set.",
              "title": "Filter"
            }
          },
          {
            "description": "Minimum market capitalisation filter in USD. Optional.",
            "in": "query",
            "name": "min_market_cap_usd",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "minimum": 0,
                  "type": "number"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Minimum market capitalisation filter in USD. Optional.",
              "title": "Min Market Cap Usd"
            }
          },
          {
            "description": "COMIT\u00c9-028 \u2014 Opaque base64 keyset cursor from a previous meta.cursor. When provided, returns only cryptos whose updated_at > cursor. Overrides ?updated_after= when both are present.",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "COMIT\u00c9-028 \u2014 Opaque base64 keyset cursor from a previous meta.cursor. When provided, returns only cryptos whose updated_at > cursor. Overrides ?updated_after= when both are present.",
              "title": "Since"
            }
          },
          {
            "description": "COMIT\u00c9-028 \u2014 ISO 8601 datetime lower bound on updated_at (exclusive). Convenience alias for ?since= without a cursor. Example: 2026-01-15T12:00:00Z",
            "in": "query",
            "name": "updated_after",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "COMIT\u00c9-028 \u2014 ISO 8601 datetime lower bound on updated_at (exclusive). Convenience alias for ?since= without a cursor. Example: 2026-01-15T12:00:00Z",
              "title": "Updated After"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CryptoCatalogResponse"
                }
              }
            },
            "description": "Catalog returned successfully."
          },
          "400": {
            "description": "Invalid query parameter."
          },
          "403": {
            "description": "Missing required scope 'catalog:read'."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "Paginated list of crypto assets with aggregated market data",
        "tags": [
          "catalog",
          "catalog"
        ]
      }
    },
    "/v1/catalog/etfs": {
      "get": {
        "description": "Returns a paginated list of ETFs from dv.hub_asset (asset_kind='etf'), enriched with certification metadata (board, methodology, url) from dv.sat_etf_islamic_certification. Dataset: 17 unique entries (Sprint 94 CAT-003 curated seed). Certification metadata sourced from public sponsor factsheets \u2014 not affiliated with certifying boards. Scope: catalog:read.",
        "operationId": "list_etf_catalog_v1_catalog_etfs_get",
        "parameters": [
          {
            "description": "Comma-separated MIC exchange codes (e.g. XLON,XNAS,XNYS,XETR,OTC). Case-sensitive.",
            "in": "query",
            "name": "exchange",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 500,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Comma-separated MIC exchange codes (e.g. XLON,XNAS,XNYS,XETR,OTC). Case-sensitive.",
              "title": "Exchange"
            }
          },
          {
            "description": "Sort order: ticker_asc (default) | name_asc",
            "in": "query",
            "name": "order",
            "required": false,
            "schema": {
              "default": "ticker_asc",
              "description": "Sort order: ticker_asc (default) | name_asc",
              "title": "Order",
              "type": "string"
            }
          },
          {
            "description": "Number of results per page (1-1000, default 100).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Number of results per page (1-1000, default 100).",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset.",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset.",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          },
          {
            "description": "COMIT\u00c9-028 \u2014 Opaque base64 keyset cursor from a previous meta.cursor. When provided, returns only ETFs whose updated_at > cursor. Note: ETFs without a certification record (updated_at NULL) are excluded from delta.",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "COMIT\u00c9-028 \u2014 Opaque base64 keyset cursor from a previous meta.cursor. When provided, returns only ETFs whose updated_at > cursor. Note: ETFs without a certification record (updated_at NULL) are excluded from delta.",
              "title": "Since"
            }
          },
          {
            "description": "COMIT\u00c9-028 \u2014 ISO 8601 datetime lower bound on updated_at (exclusive). Convenience alias for ?since= without a cursor. Example: 2026-01-15T12:00:00Z",
            "in": "query",
            "name": "updated_after",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "COMIT\u00c9-028 \u2014 ISO 8601 datetime lower bound on updated_at (exclusive). Convenience alias for ?since= without a cursor. Example: 2026-01-15T12:00:00Z",
              "title": "Updated After"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EtfCatalogResponse"
                }
              }
            },
            "description": "Catalog returned successfully."
          },
          "403": {
            "description": "Missing required scope 'catalog:read'."
          },
          "422": {
            "description": "Invalid query parameter."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "Paginated list of ETFs with optional Islamic certification filter",
        "tags": [
          "catalog",
          "catalog"
        ]
      }
    },
    "/v1/catalog/index/{index_code}/constituents": {
      "get": {
        "description": "Returns the current snapshot of constituents for a supported market index. Data sourced from Wikidata SPARQL (CC0 1.0 \u2014 free for commercial use) with curated static fallback when Wikidata returns 0 rows. Supported: SP500, CAC40, DAX, NIKKEI225, FTSE100, HSI, ASX200, EUROSTOXX50.",
        "operationId": "get_index_constituents_v1_catalog_index__index_code__constituents_get",
        "parameters": [
          {
            "in": "path",
            "name": "index_code",
            "required": true,
            "schema": {
              "title": "Index Code",
              "type": "string"
            }
          },
          {
            "description": "Max rows to return (1\u20131000)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Max rows to return (1\u20131000)",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          },
          {
            "description": "If false (default), only return constituents matched in hub_asset. If true, include orphan constituents (asset_hk = null).",
            "in": "query",
            "name": "include_unmatched",
            "required": false,
            "schema": {
              "default": false,
              "description": "If false (default), only return constituents matched in hub_asset. If true, include orphan constituents (asset_hk = null).",
              "title": "Include Unmatched",
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IndexConstituentsResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "400": {
            "description": "Unsupported index code"
          },
          "404": {
            "description": "Index not found or no snapshot available"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get index constituents",
        "tags": [
          "catalog"
        ]
      }
    },
    "/v1/catalog/stocks": {
      "get": {
        "description": "Return a paginated, filterable list of stocks from the PIQ catalog (2168 entries, Sprint 65 coverage Top 100 US+EU enriched). Supports filtering by exchange MIC, GICS sector, country, and minimum market cap. market_cap_usd is NULL for most stocks \u2014 only curated top-100 US+EU have values. Scope: catalog:read.",
        "operationId": "list_stocks_v1_catalog_stocks_get",
        "parameters": [
          {
            "description": "Comma-separated MIC exchange codes to filter by (e.g. XNYS,XNAS,XLON,XPAR,XETR,XSWX). Case-sensitive.",
            "in": "query",
            "name": "exchange",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 500,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Comma-separated MIC exchange codes to filter by (e.g. XNYS,XNAS,XLON,XPAR,XETR,XSWX). Case-sensitive.",
              "title": "Exchange"
            }
          },
          {
            "description": "GICS sector name filter (e.g. 'Information Technology', 'Financials')",
            "in": "query",
            "name": "sector_gics",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 200,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "GICS sector name filter (e.g. 'Information Technology', 'Financials')",
              "title": "Sector Gics"
            }
          },
          {
            "description": "ISO 3166-1 alpha-2 country code filter (e.g. US, GB, FR)",
            "in": "query",
            "name": "country_iso2",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 2,
                  "minLength": 2,
                  "pattern": "^[A-Z]{2}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "ISO 3166-1 alpha-2 country code filter (e.g. US, GB, FR)",
              "title": "Country Iso2"
            }
          },
          {
            "description": "Sort order: market_cap_desc | ticker_asc | name_asc",
            "in": "query",
            "name": "order",
            "required": false,
            "schema": {
              "default": "market_cap_desc",
              "description": "Sort order: market_cap_desc | ticker_asc | name_asc",
              "title": "Order",
              "type": "string"
            }
          },
          {
            "description": "Number of results to return (1-1000, default 100)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Number of results to return (1-1000, default 100)",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          },
          {
            "description": "Minimum market cap filter in USD (optional)",
            "in": "query",
            "name": "min_market_cap_usd",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "minimum": 0,
                  "type": "number"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Minimum market cap filter in USD (optional)",
              "title": "Min Market Cap Usd"
            }
          },
          {
            "description": "COMIT\u00c9-028 \u2014 Opaque base64 keyset cursor from a previous meta.cursor. When provided, returns only stocks whose updated_at > cursor. Overrides ?updated_after= when both are present.",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "COMIT\u00c9-028 \u2014 Opaque base64 keyset cursor from a previous meta.cursor. When provided, returns only stocks whose updated_at > cursor. Overrides ?updated_after= when both are present.",
              "title": "Since"
            }
          },
          {
            "description": "COMIT\u00c9-028 \u2014 ISO 8601 datetime lower bound on updated_at (exclusive). Convenience alias for ?since= without a cursor. Example: 2026-01-15T12:00:00Z",
            "in": "query",
            "name": "updated_after",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "COMIT\u00c9-028 \u2014 ISO 8601 datetime lower bound on updated_at (exclusive). Convenience alias for ?since= without a cursor. Example: 2026-01-15T12:00:00Z",
              "title": "Updated After"
            }
          },
          {
            "description": "T-842 \u2014 Filter to enriched tickers only (is_enriched=true). enriched=true returns only tickers with complete metadata (name, ISIN, sector). enriched=false or omitted returns all tickers (default). ~570/2733 tickers are enriched via EDGAR in prod (Sprint 104 estimate).",
            "in": "query",
            "name": "enriched",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "null"
                }
              ],
              "description": "T-842 \u2014 Filter to enriched tickers only (is_enriched=true). enriched=true returns only tickers with complete metadata (name, ISIN, sector). enriched=false or omitted returns all tickers (default). ~570/2733 tickers are enriched via EDGAR in prod (Sprint 104 estimate).",
              "title": "Enriched"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StockCatalogResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List stocks catalog",
        "tags": [
          "catalog",
          "catalog"
        ]
      }
    },
    "/v1/commodities/search": {
      "get": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use GET /v1/instruments/commodity instead. Returns the same payload with a Link header pointing to the canonical URL. Not financial advice. Methodology disclosed.",
        "operationId": "search_commodities_alias_v1_commodities_search_get",
        "parameters": [
          {
            "description": "Search query",
            "in": "query",
            "name": "q",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Search query",
              "title": "Q"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Search Commodities Alias V1 Commodities Search Get"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Search commodities (alias \u2014 deprecated)",
        "tags": [
          "commodities-alias"
        ]
      }
    },
    "/v1/commodities/{symbol}": {
      "get": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use GET /v1/instruments/commodity/{symbol} instead. Returns the same payload with an additional Link header pointing to the canonical URL. Pattern: Stripe /charges \u2194 /payment_intents. Symbols: XAU, XAG, CL, BZ, NG, HG, ZW, ZC, KC, SB, CC (T-456 core set). Not financial advice. Methodology disclosed.",
        "operationId": "get_commodity_alias_v1_commodities__symbol__get",
        "parameters": [
          {
            "in": "path",
            "name": "symbol",
            "required": true,
            "schema": {
              "title": "Symbol",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Commodity Alias V1 Commodities  Symbol  Get"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get commodity by symbol (alias \u2014 deprecated)",
        "tags": [
          "commodities-alias"
        ]
      }
    },
    "/v1/commodities/{symbol}/prices": {
      "get": {
        "description": "Historical prices for commodity symbols. Sources: FRED public domain (CL/BZ/NG/HG/ZW/ZC/KC/SB/CC) + metals.dev paid plan (XAU/XAG). No scope gate \u2014 free wave 1. Range default 1y. Granularity: daily|monthly. 404 for unsupported symbols (returns valid list). Cache: Redis TTL 24h. FRED attribution required. Not financial advice.",
        "operationId": "get_commodity_prices_v1_commodities__symbol__prices_get",
        "parameters": [
          {
            "in": "path",
            "name": "symbol",
            "required": true,
            "schema": {
              "title": "Symbol",
              "type": "string"
            }
          },
          {
            "description": "1d|7d|30d|90d|1y|2y (default 1y)",
            "in": "query",
            "name": "range",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "default": "1y",
              "description": "1d|7d|30d|90d|1y|2y (default 1y)",
              "title": "Range"
            }
          },
          {
            "description": "daily | monthly",
            "in": "query",
            "name": "granularity",
            "required": false,
            "schema": {
              "default": "daily",
              "description": "daily | monthly",
              "title": "Granularity",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "From Date"
            }
          },
          {
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "To Date"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommodityPriceResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Commodity price history \u2014 FRED / metals.dev (T-528)",
        "tags": [
          "prices-commodities"
        ]
      }
    },
    "/v1/commodity/usda/catalog": {
      "get": {
        "description": "Returns all supported commodities (10) and statistics (5) for USDA NASS data. Served from in-memory catalogue \u2014 no DB query. Source: USDA NASS. Public Domain.",
        "operationId": "get_usda_catalog_v1_commodity_usda_catalog_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsdaCatalogResponse"
                }
              }
            },
            "description": "Catalogue returned successfully."
          }
        },
        "summary": "USDA NASS commodities and statistics catalogue",
        "tags": [
          "commodity-usda"
        ]
      }
    },
    "/v1/commodity/usda/{commodity}/{statistic}": {
      "get": {
        "description": "Returns annual observations from USDA NASS for one commodity and statistic. Supported commodities: WHEAT, CORN, SOYBEANS, COTTON, RICE, OATS, BARLEY, SORGHUM, CATTLE, HOGS. Supported statistics: PRODUCTION, PRICE_RECEIVED, AREA_HARVESTED, YIELD, EXPORTS. Some combinations return null values (e.g. AREA_HARVESTED for livestock). Location: US national level only. Source: USDA NASS. Public Domain.",
        "operationId": "get_usda_series_v1_commodity_usda__commodity___statistic__get",
        "parameters": [
          {
            "description": "Commodity code (case-insensitive). E.g. 'WHEAT', 'corn', 'Soybeans'.",
            "in": "path",
            "name": "commodity",
            "required": true,
            "schema": {
              "description": "Commodity code (case-insensitive). E.g. 'WHEAT', 'corn', 'Soybeans'.",
              "examples": {
                "default": {
                  "value": "WHEAT"
                }
              },
              "title": "Commodity",
              "type": "string"
            }
          },
          {
            "description": "Statistic code (case-insensitive). E.g. 'PRODUCTION', 'price_received'.",
            "in": "path",
            "name": "statistic",
            "required": true,
            "schema": {
              "description": "Statistic code (case-insensitive). E.g. 'PRODUCTION', 'price_received'.",
              "examples": {
                "default": {
                  "value": "PRODUCTION"
                }
              },
              "title": "Statistic",
              "type": "string"
            }
          },
          {
            "description": "Maximum observations to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum observations to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsdaSeriesResponse"
                }
              }
            },
            "description": "Observations returned successfully."
          },
          "404": {
            "description": "Unknown commodity or statistic code."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "USDA NASS commodity statistic observations",
        "tags": [
          "commodity-usda"
        ]
      }
    },
    "/v1/compliance/sec-filing/{cik}/{filing_type}": {
      "get": {
        "description": "Returns last `limit` filings for a given CIK and filing type (10-K, 10-Q, 8-K, DEF 14A). MVP Sprint 96: metadata only (filing_date, period_end_date, primary_document_url). Structured sections and financials = Sprint 97+.",
        "operationId": "get_sec_filings_v1_compliance_sec_filing__cik___filing_type__get",
        "parameters": [
          {
            "in": "path",
            "name": "cik",
            "required": true,
            "schema": {
              "title": "Cik",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "filing_type",
            "required": true,
            "schema": {
              "title": "Filing Type",
              "type": "string"
            }
          },
          {
            "description": "Max filings returned (1-20)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 5,
              "description": "Max filings returned (1-20)",
              "maximum": 20,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SecFilingResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "SEC EDGAR filings metadata",
        "tags": [
          "compliance"
        ]
      }
    },
    "/v1/correlations": {
      "get": {
        "description": "Returns Pearson + Spearman rolling correlation between two assets from different asset classes. Requires `correlations:read` scope (Growth tier). Correlation computed on log returns over the requested rolling window. Disclaimer: Not financial advice. Methodology disclosed.",
        "operationId": "get_correlation_v1_correlations_get",
        "parameters": [
          {
            "description": "Source asset. Format: {kind}:{symbol} (e.g. crypto:BTC, stock:AAPL).",
            "in": "query",
            "name": "from",
            "required": true,
            "schema": {
              "description": "Source asset. Format: {kind}:{symbol} (e.g. crypto:BTC, stock:AAPL).",
              "examples": [
                "crypto:BTC",
                "stock:AAPL",
                "commodity:GOLD"
              ],
              "title": "From",
              "type": "string"
            }
          },
          {
            "description": "Target asset. Format: {kind}:{symbol}.",
            "in": "query",
            "name": "to",
            "required": true,
            "schema": {
              "description": "Target asset. Format: {kind}:{symbol}.",
              "examples": [
                "stock:AAPL",
                "crypto:ETH",
                "commodity:SILVER"
              ],
              "title": "To",
              "type": "string"
            }
          },
          {
            "description": "Rolling window. 30d = 30 days, 90d = 90 days, 1y = 252 trading days.",
            "in": "query",
            "name": "period",
            "required": false,
            "schema": {
              "default": "90d",
              "description": "Rolling window. 30d = 30 days, 90d = 90 days, 1y = 252 trading days.",
              "enum": [
                "30d",
                "90d",
                "1y"
              ],
              "title": "Period",
              "type": "string"
            }
          },
          {
            "description": "Snapshot date ISO (YYYY-MM-DD). Defaults to latest available.",
            "in": "query",
            "name": "snapshot_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Snapshot date ISO (YYYY-MM-DD). Defaults to latest available.",
              "title": "Snapshot Date"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CorrelationResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Cross-asset pair correlation",
        "tags": [
          "correlations"
        ]
      }
    },
    "/v1/coverage": {
      "get": {
        "description": "Returns the complete list of instruments covered by portfolIQ. Supports ?format=csv for spreadsheet download, and optional filters ?asset_class, ?tier, ?has_ai. No auth required. Rate-limited to 100 requests per IP per day.",
        "operationId": "coverage_manifest_v1_coverage_get",
        "parameters": [
          {
            "description": "Response format.",
            "in": "query",
            "name": "format",
            "required": false,
            "schema": {
              "default": "json",
              "description": "Response format.",
              "enum": [
                "json",
                "csv"
              ],
              "title": "Format",
              "type": "string"
            }
          },
          {
            "description": "Filter by asset class.",
            "in": "query",
            "name": "asset_class",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by asset class.",
              "title": "Asset Class"
            }
          },
          {
            "description": "Filter by tier (tier1/tier2/tier3).",
            "in": "query",
            "name": "tier",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by tier (tier1/tier2/tier3).",
              "title": "Tier"
            }
          },
          {
            "description": "Filter by AI analysis availability.",
            "in": "query",
            "name": "has_ai",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by AI analysis availability.",
              "title": "Has Ai"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CoverageResponse"
                }
              },
              "text/csv": {
                "example": "ticker,asset_class,tier,data_sources,ohlcv,fundamentals,ai_analysis\nBTC,crypto,tier1,coingecko,true,false,true",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "JSON (default) or CSV when ?format=csv."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          },
          "429": {
            "description": "Rate limit exceeded (100 req/day/IP)."
          },
          "503": {
            "description": "Coverage DB temporarily unavailable."
          }
        },
        "summary": "Coverage manifest \u2014 full instrument catalogue",
        "tags": [
          "coverage"
        ]
      }
    },
    "/v1/coverage/{asset_class}": {
      "get": {
        "description": "Returns instruments for a specific asset class (e.g. 'crypto', 'stock', 'etf', 'commodity'). Supports the same query params as the root endpoint.",
        "operationId": "coverage_by_asset_class_v1_coverage__asset_class__get",
        "parameters": [
          {
            "in": "path",
            "name": "asset_class",
            "required": true,
            "schema": {
              "title": "Asset Class",
              "type": "string"
            }
          },
          {
            "description": "Response format.",
            "in": "query",
            "name": "format",
            "required": false,
            "schema": {
              "default": "json",
              "description": "Response format.",
              "enum": [
                "json",
                "csv"
              ],
              "title": "Format",
              "type": "string"
            }
          },
          {
            "description": "Filter by tier.",
            "in": "query",
            "name": "tier",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by tier.",
              "title": "Tier"
            }
          },
          {
            "description": "Filter by AI analysis availability.",
            "in": "query",
            "name": "has_ai",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by AI analysis availability.",
              "title": "Has Ai"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CoverageResponse"
                }
              },
              "text/csv": {
                "example": "ticker,asset_class,tier,data_sources,ohlcv,fundamentals,ai_analysis\nBTC,crypto,tier1,coingecko,true,false,true",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "JSON (default) or CSV when ?format=csv."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          },
          "429": {
            "description": "Rate limit exceeded (100 req/day/IP)."
          },
          "503": {
            "description": "Coverage DB temporarily unavailable."
          }
        },
        "summary": "Coverage manifest \u2014 filtered by asset class",
        "tags": [
          "coverage"
        ]
      }
    },
    "/v1/coverage/{asset_class}/{ticker}": {
      "get": {
        "description": "Returns coverage details for a single instrument identified by asset class + ticker. 404 if not found in the catalogue.",
        "operationId": "coverage_single_v1_coverage__asset_class___ticker__get",
        "parameters": [
          {
            "in": "path",
            "name": "asset_class",
            "required": true,
            "schema": {
              "title": "Asset Class",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CoverageResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "404": {
            "description": "Instrument not found in the catalogue."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          },
          "429": {
            "description": "Rate limit exceeded (100 req/day/IP)."
          },
          "503": {
            "description": "Coverage DB temporarily unavailable."
          }
        },
        "summary": "Coverage manifest \u2014 single instrument detail",
        "tags": [
          "coverage"
        ]
      }
    },
    "/v1/crypto/{coingecko_id}/tokenomics": {
      "get": {
        "description": "Returns tokenomics (supply, yield type, lending) and descriptive attributes for a crypto-asset. Data from CoinGecko Demo + curated references. Covers top-30 MVP. Not financial advice. Methodology disclosed.",
        "operationId": "get_crypto_tokenomics_v1_crypto__coingecko_id__tokenomics_get",
        "parameters": [
          {
            "in": "path",
            "name": "coingecko_id",
            "required": true,
            "schema": {
              "title": "Coingecko Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Tokenomics data found."
          },
          "404": {
            "description": "Asset not found in tokenomics DB."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          },
          "503": {
            "description": "DB unavailable."
          }
        },
        "summary": "Get tokenomics & descriptive data for a crypto-asset",
        "tags": [
          "crypto-tokenomics"
        ],
        "x-required-scope": "crypto:read"
      }
    },
    "/v1/defi/protocol/{slug}/tvl": {
      "get": {
        "description": "Returns TVL snapshots for a DeFi protocol identified by its DeFiLlama slug. Supports pagination and optional date-range filtering. Only returns active records (load_end_ts IS NULL \u2014 current SCD2 snapshot per day). Source: DeFiLlama (api.llama.fi). Seeded by scripts/seed-defillama-top20.py. Known slugs: lido, aave, makerdao, uniswap-v3, curve-dex, compound-v3, eigenlayer, ether.fi, pendle, jito, marinade, ondo-finance, rocket-pool, sky, spark, morpho, gmx, jupiter, dydx, balancer.",
        "operationId": "get_protocol_tvl_v1_defi_protocol__slug__tvl_get",
        "parameters": [
          {
            "description": "DeFiLlama protocol slug. Examples: lido, aave, makerdao, uniswap-v3, curve-dex, compound-v3, eigenlayer, ether.fi, pendle, jito, marinade, ondo-finance, rocket-pool, sky, spark, morpho, gmx, jupiter, dydx, balancer.",
            "in": "path",
            "name": "slug",
            "required": true,
            "schema": {
              "description": "DeFiLlama protocol slug. Examples: lido, aave, makerdao, uniswap-v3, curve-dex, compound-v3, eigenlayer, ether.fi, pendle, jito, marinade, ondo-finance, rocket-pool, sky, spark, morpho, gmx, jupiter, dydx, balancer.",
              "examples": {
                "default": {
                  "value": "lido"
                }
              },
              "title": "Slug",
              "type": "string"
            }
          },
          {
            "description": "Start date (inclusive), format: YYYY-MM-DD. Default: no lower bound.",
            "in": "query",
            "name": "start_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date (inclusive), format: YYYY-MM-DD. Default: no lower bound.",
              "examples": {
                "default": {
                  "value": "2026-05-01"
                }
              },
              "title": "Start Date"
            }
          },
          {
            "description": "End date (inclusive), format: YYYY-MM-DD. Default: no upper bound.",
            "in": "query",
            "name": "end_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date (inclusive), format: YYYY-MM-DD. Default: no upper bound.",
              "examples": {
                "default": {
                  "value": "2026-05-26"
                }
              },
              "title": "End Date"
            }
          },
          {
            "description": "Maximum snapshots to return. Default: 30, max: 365.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 30,
              "description": "Maximum snapshots to return. Default: 30, max: 365.",
              "maximum": 365,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TvlResponse"
                }
              }
            },
            "description": "TVL snapshots returned successfully."
          },
          "400": {
            "description": "Invalid slug format."
          },
          "404": {
            "description": "Protocol not found in database \u2014 not yet seeded or unknown slug."
          },
          "422": {
            "description": "Invalid query parameters (e.g. start_date > end_date)."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "DeFi protocol TVL history",
        "tags": [
          "defi-tvl"
        ]
      }
    },
    "/v1/defi/protocols": {
      "get": {
        "description": "Returns the latest TVL snapshot for each of the top 20 seeded DeFi protocols (Lido, Aave, MakerDAO, Uniswap V3, Curve, Compound, EigenLayer, ether.fi, Pendle, Jito, Marinade, Ondo Finance, Rocket Pool, Sky, Spark, Morpho, GMX, Jupiter, dYdX, Balancer). Sorted by protocol slug alphabetically. Source: DeFiLlama (api.llama.fi). Seeded by scripts/seed-defillama-top20.py.",
        "operationId": "list_protocols_v1_defi_protocols_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtocolsListResponse"
                }
              }
            },
            "description": "Protocol list returned successfully."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "List DeFi protocols with latest TVL",
        "tags": [
          "defi-tvl"
        ]
      }
    },
    "/v1/demo/assets": {
      "get": {
        "description": "Returns the set of assets available in the public demo. No auth required. Rate-limited to 50 requests per IP per day.",
        "operationId": "list_demo_assets_v1_demo_assets_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "List demo assets",
        "tags": [
          "demo"
        ]
      }
    },
    "/v1/demo/assets/{asset_id}": {
      "get": {
        "description": "Returns the latest price snapshot and AI-generated context for a demo asset. 404 if the asset is not in the demo list. 429 if the IP rate limit is reached.",
        "operationId": "get_demo_asset_v1_demo_assets__asset_id__get",
        "parameters": [
          {
            "in": "path",
            "name": "asset_id",
            "required": true,
            "schema": {
              "title": "Asset Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Demo asset snapshot",
        "tags": [
          "demo"
        ]
      }
    },
    "/v1/demo/assets/{asset_id}/ai-history": {
      "get": {
        "description": "Returns 30 days of synthetic AI analysis snapshots for a demo asset, most recent first. No DB hit \u2014 deterministic mock data.",
        "operationId": "get_demo_asset_ai_history_v1_demo_assets__asset_id__ai_history_get",
        "parameters": [
          {
            "in": "path",
            "name": "asset_id",
            "required": true,
            "schema": {
              "title": "Asset Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Demo asset \u2014 30-day AI history",
        "tags": [
          "demo"
        ]
      }
    },
    "/v1/demo/assets/{asset_id}/ai-latest": {
      "get": {
        "description": "Returns the most recent AI-generated analysis snapshot for a demo asset. Equivalent to the first entry of /ai-history. Synthetic data, 5-min conceptual cache (identical payload across calls within the day).",
        "operationId": "get_demo_asset_ai_latest_v1_demo_assets__asset_id__ai_latest_get",
        "parameters": [
          {
            "in": "path",
            "name": "asset_id",
            "required": true,
            "schema": {
              "title": "Asset Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Demo asset \u2014 latest AI snapshot",
        "tags": [
          "demo"
        ]
      }
    },
    "/v1/discover/{ticker}": {
      "post": {
        "description": "Check whether a ticker is in the PIQ database. If found: 200 OK with minimal asset card. If not found: queue an automated ingestion and return 202 Accepted. The actual ingestion is performed asynchronously by the PIQ CRON worker. Idempotent: repeated calls for the same pending ticker return the same request_id. Scope: discover:request (Free tier, 50 requests/day). Not financial advice. Methodology disclosed.",
        "operationId": "post_discover_ticker_v1_discover__ticker__post",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Ticker found in DB \u2014 returns asset metadata."
          },
          "202": {
            "description": "Ticker not found \u2014 ingestion queued (or already pending)."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Invalid ticker format."
          },
          "429": {
            "description": "Daily discover limit reached (Free tier: 50/day)."
          }
        },
        "summary": "Discover / request ingestion of an unknown ticker",
        "tags": [
          "discover"
        ],
        "x-required-scope": "discover:request"
      }
    },
    "/v1/education/glossary": {
      "get": {
        "description": "Return all glossary terms for the requested language.\n\nSupported languages: en (57 terms), fr (15 terms MVP), ar (12 terms MVP).\nFR and AR coverage will be expanded to 57 terms in Sprint 68.",
        "operationId": "list_glossary_v1_education_glossary_get",
        "parameters": [
          {
            "description": "Language code (en, fr, ar)",
            "in": "query",
            "name": "lang",
            "required": false,
            "schema": {
              "default": "en",
              "description": "Language code (en, fr, ar)",
              "pattern": "^(en|fr|ar)$",
              "title": "Lang",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response List Glossary V1 Education Glossary Get",
                  "type": "object"
                }
              }
            },
            "description": "Full glossary term list with definitions"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List all glossary terms for a language",
        "tags": [
          "education"
        ]
      }
    },
    "/v1/education/glossary/{term}": {
      "get": {
        "description": "Return a single glossary term.\n\nLookup by `slug` field first; falls back to case-insensitive `term` field match.\nReturns 404 if the term is not found in the requested language.",
        "operationId": "get_term_v1_education_glossary__term__get",
        "parameters": [
          {
            "in": "path",
            "name": "term",
            "required": true,
            "schema": {
              "title": "Term",
              "type": "string"
            }
          },
          {
            "description": "Language code (en, fr, ar)",
            "in": "query",
            "name": "lang",
            "required": false,
            "schema": {
              "default": "en",
              "description": "Language code (en, fr, ar)",
              "pattern": "^(en|fr|ar)$",
              "title": "Lang",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response Get Term V1 Education Glossary  Term  Get",
                  "type": "object"
                }
              }
            },
            "description": "Single glossary term with definition"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get a single glossary term by slug or name",
        "tags": [
          "education"
        ]
      }
    },
    "/v1/education/methodology": {
      "get": {
        "description": "Return metadata for all available methodology documents.\n\nBoth complete and stub documents are listed. Consumers can detect stubs\nby checking `version` for the `-stub-` marker.",
        "operationId": "list_methodology_v1_education_methodology_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response List Methodology V1 Education Methodology Get",
                  "type": "object"
                }
              }
            },
            "description": "List of methodology topics with metadata"
          }
        },
        "summary": "List all methodology topics",
        "tags": [
          "education"
        ]
      }
    },
    "/v1/education/methodology/{topic}": {
      "get": {
        "description": "Return the full methodology document for a given topic.\n\nThe `content_markdown` field contains the document body without frontmatter.\nConsumers can render it as Markdown or parse it further.\n\nNote: methodology content is currently English-only. FR/AR translations\nare planned for Sprint 68. The `lang` parameter is accepted for forward\ncompatibility and recorded in the response meta.",
        "operationId": "get_methodology_v1_education_methodology__topic__get",
        "parameters": [
          {
            "in": "path",
            "name": "topic",
            "required": true,
            "schema": {
              "title": "Topic",
              "type": "string"
            }
          },
          {
            "description": "Language code (en, fr, ar). Content is currently EN-only; lang is recorded in meta.",
            "in": "query",
            "name": "lang",
            "required": false,
            "schema": {
              "default": "en",
              "description": "Language code (en, fr, ar). Content is currently EN-only; lang is recorded in meta.",
              "pattern": "^(en|fr|ar)$",
              "title": "Lang",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response Get Methodology V1 Education Methodology  Topic  Get",
                  "type": "object"
                }
              }
            },
            "description": "Methodology metadata and markdown content"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get full methodology content by topic slug",
        "tags": [
          "education"
        ]
      }
    },
    "/v1/etf/search": {
      "get": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use GET /v1/instruments/etf instead. Returns the same payload with a Link header pointing to the canonical URL. Not financial advice. Methodology disclosed.",
        "operationId": "search_etf_alias_v1_etf_search_get",
        "parameters": [
          {
            "description": "Search query",
            "in": "query",
            "name": "q",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Search query",
              "title": "Q"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Search Etf Alias V1 Etf Search Get"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Search ETFs (alias \u2014 deprecated)",
        "tags": [
          "etf-alias"
        ]
      }
    },
    "/v1/etf/{ticker}": {
      "get": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use GET /v1/instruments/etf/{ticker} instead. Returns the same payload with an additional Link header pointing to the canonical URL. Pattern: Stripe /charges \u2194 /payment_intents. Not financial advice. Methodology disclosed.",
        "operationId": "get_etf_alias_v1_etf__ticker__get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Etf Alias V1 Etf  Ticker  Get"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get ETF by ticker (alias \u2014 deprecated)",
        "tags": [
          "etf-alias"
        ]
      }
    },
    "/v1/etf/{ticker}/ai": {
      "get": {
        "description": "AI-generated analysis for an ETF ticker. Legacy types: composition (default), holdings_screening_halal, tracking_error. Extended types (D-102, pre-seeded from KB): growth_analysis, valuation_analysis, risk_assessment, catalysts_outlook, peer_comparison. Extended types are read directly from dv.sat_asset_ai_analysis (no LLM call). Returns 404 if extended type content not yet seeded. Synthetic swap fast-path: if replication_method=synthetic_swap, 0 LLM call made \u2014 response set to non-shariah-compliant per AAOIFI (OIC Fiqh Academy N\u00b040). Scope: pro. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_etf_ai_v1_etf__ticker__ai_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Analysis type. Legacy: composition, holdings_screening_halal, tracking_error. Extended (D-102, pre-seeded): growth_analysis, valuation_analysis, risk_assessment, catalysts_outlook, peer_comparison.",
            "in": "query",
            "name": "analysis_type",
            "required": false,
            "schema": {
              "default": "composition",
              "description": "Analysis type. Legacy: composition, holdings_screening_halal, tracking_error. Extended (D-102, pre-seeded): growth_analysis, valuation_analysis, risk_assessment, catalysts_outlook, peer_comparison.",
              "enum": [
                "composition",
                "holdings_screening_halal",
                "tracking_error",
                "growth_analysis",
                "valuation_analysis",
                "risk_assessment",
                "catalysts_outlook",
                "peer_comparison"
              ],
              "title": "Analysis Type",
              "type": "string"
            }
          },
          {
            "description": "Requested locale for AI analysis: 'en' (default), 'fr' (Pro tier), 'ar' (Enterprise tier). Falls back to Accept-Language header, then 'en'. If requested locale has no data, EN is served and meta.fallback_used=true.",
            "in": "query",
            "name": "lang",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Requested locale for AI analysis: 'en' (default), 'fr' (Pro tier), 'ar' (Enterprise tier). Falls back to Accept-Language header, then 'en'. If requested locale has no data, EN is served and meta.fallback_used=true.",
              "title": "Lang"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_ETFAIAnalysis_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "ETF AI analysis \u2014 composition + halal + extended types (D-102)",
        "tags": [
          "etf-alias"
        ],
        "x-required-scope": "pro"
      }
    },
    "/v1/etf/{ticker}/holdings": {
      "get": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use GET /v1/instruments/etf/{ticker}/holdings instead. Returns paginated ETF constituents with weights. Scope: standard. Link header points to canonical URL. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_etf_holdings_alias_v1_etf__ticker__holdings_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Holdings per page [1-500]",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Holdings per page [1-500]",
              "maximum": 500,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Etf Holdings Alias V1 Etf  Ticker  Holdings Get"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "ETF holdings \u2014 constituent list with weights (alias \u2014 deprecated, T-485)",
        "tags": [
          "etf-alias"
        ]
      }
    },
    "/v1/etf/{ticker}/prices": {
      "get": {
        "description": "EOD price history for US ETF tickers from dv.sat_stock_price_consensus. Same methodology as stocks (stock_consensus_v1), asset_kind='etf'. No scope gate \u2014 ETF free wave 1 (F4-C1-001). Range: 1d|7d|30d|90d|1y|2y (default 30d). EU ETFs planned Sprint 32. Cache: Redis TTL 7d historical / 1h today. Not financial advice.",
        "operationId": "get_etf_prices_v1_etf__ticker__prices_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "1d|7d|30d|90d|1y|2y",
            "in": "query",
            "name": "range",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "default": "30d",
              "description": "1d|7d|30d|90d|1y|2y",
              "title": "Range"
            }
          },
          {
            "description": "Only 'daily' in Sprint 31",
            "in": "query",
            "name": "granularity",
            "required": false,
            "schema": {
              "default": "daily",
              "description": "Only 'daily' in Sprint 31",
              "title": "Granularity",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "From Date"
            }
          },
          {
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "To Date"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StockPriceResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "ETF EOD price history \u2014 consensus (T-527)",
        "tags": [
          "prices-etf"
        ]
      }
    },
    "/v1/events": {
      "get": {
        "description": "Returns global factual editorial events detected on financial assets. Pull-only endpoint \u2014 no user personalization, no push notifications. Events are asset-level statistical anomalies enriched with pedagogical context. **Filters**: `asset` (ticker or CSV), `since` (ISO 8601 UTC), `type`, `lang`. Each event includes a mandatory disclaimer. LEGAL: Information factuelle uniquement. Not financial advice.",
        "operationId": "get_events_v1_events_get",
        "parameters": [
          {
            "description": "Ticker or comma-separated list (e.g. BTC or BTC,ETH,AAPL).",
            "in": "query",
            "name": "asset",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Ticker or comma-separated list (e.g. BTC or BTC,ETH,AAPL).",
              "title": "Asset"
            }
          },
          {
            "description": "Return events after this UTC datetime (ISO 8601, e.g. 2026-05-01T00:00:00Z).",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date-time",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Return events after this UTC datetime (ISO 8601, e.g. 2026-05-01T00:00:00Z).",
              "title": "Since"
            }
          },
          {
            "description": "Event type filter: price_anomaly | volume_anomaly | volatility_spike | trend_reversal",
            "in": "query",
            "name": "type",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Event type filter: price_anomaly | volume_anomaly | volatility_spike | trend_reversal",
              "title": "Type"
            }
          },
          {
            "description": "Response language: fr | en.",
            "in": "query",
            "name": "lang",
            "required": false,
            "schema": {
              "default": "fr",
              "description": "Response language: fr | en.",
              "title": "Lang",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "List of editorial events (may be empty)."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database unavailable."
          }
        },
        "summary": "Editorial events \u2014 pull API (D-142)",
        "tags": [
          "events"
        ]
      }
    },
    "/v1/forex/search": {
      "get": {
        "description": "Returns the list of available EUR-based currency pairs with latest reference rates. Filter by currency code with ?q=EUR. Returns meta.total = count of distinct pairs matching the query. Requires scope `fx:read`. LEGAL: ECB SDW open data \u2014 100% redistribuable (COMITE-014 D-069 GO ABSOLU). Market data only. Not financial advice. MAR Art. 20.",
        "operationId": "search_forex_pairs_v1_forex_search_get",
        "parameters": [
          {
            "description": "Filter by 3-letter ISO 4217 currency code (e.g. 'EUR', 'USD'). Case-insensitive.",
            "in": "query",
            "name": "q",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 3,
                  "minLength": 2,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by 3-letter ISO 4217 currency code (e.g. 'EUR', 'USD'). Case-insensitive.",
              "title": "Q"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ForexSearchResponse"
                }
              }
            },
            "description": "Pairs list successfully resolved"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          },
          "503": {
            "description": "ECB data unavailable \u2014 scraper not run"
          }
        },
        "summary": "Search available ECB forex pairs",
        "tags": [
          "forex"
        ]
      }
    },
    "/v1/forex/{pair}": {
      "get": {
        "description": "Returns the latest ECB SDW reference rate and the 30-day series for a currency pair (e.g. EUR-USD). The pair format is BASE-QUOTE with 3-letter ISO 4217 codes.\n\n**Supported codes**: EUR, USD, GBP, JPY, CHF, CAD, AUD, NZD, SEK, NOK, DKK, CZK, HUF, PLN, RON, BGN, HKD, SGD, CNY, INR, BRL, MXN, ZAR, TRY, KRW, THB, IDR, PHP, MYR, ILS, ISK.\n\n**Note**: ECB publishes reference rates on business days only (~16:00 CET). Weekends and bank holidays return the last known close. If `data_quality = 'partial'`, the latest observation is older than 5 days.\n\nRequires scope `fx:read`.\n\n**Legal**: Market data only. Not financial advice. MAR Art. 20.",
        "operationId": "get_forex_pair_v1_forex__pair__get",
        "parameters": [
          {
            "description": "Currency pair in BASE-QUOTE format (e.g. 'EUR-USD' or 'EUR/USD').",
            "in": "path",
            "name": "pair",
            "required": true,
            "schema": {
              "description": "Currency pair in BASE-QUOTE format (e.g. 'EUR-USD' or 'EUR/USD').",
              "examples": [
                "EUR-USD",
                "EUR-GBP",
                "USD-JPY"
              ],
              "maxLength": 8,
              "minLength": 6,
              "title": "Pair",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ForexResponse"
                }
              }
            },
            "description": "Forex rate successfully resolved"
          },
          "422": {
            "description": "Invalid pair format or unsupported currency code"
          },
          "503": {
            "description": "ECB data unavailable \u2014 scraper not run or pair missing"
          }
        },
        "summary": "Latest ECB reference rate + 30-day series for a currency pair",
        "tags": [
          "forex"
        ]
      }
    },
    "/v1/fundamentals/equity/{isin}": {
      "get": {
        "description": "Returns the latest available fundamentals snapshot for a EU-listed stock identified by ISIN (ISO 6166).\n\n**Data**: official statutory filings (AMF, BaFin, CNMV, Companies House, etc.) ingested via the DV2.0 pipeline and exposed through the dbt mart view `marts.fact_equity_fundamentals`.\n\n**AAOIFI signal**: `is_halal_aaoifi` is a methodological screening signal computed by portfolIQ against AAOIFI Shari'a Standard ratio thresholds. It is **NOT a fatwa**. HS cross-validates independently.\n\n**Scope**: `fundamentals:read` (Growth tier+).\n\n**Coverage v1**: 53 EU stocks (seed \u2014 CAC40/DAX/AEX/IBEX35/FTSE100/BEL20/OMX/AthEx). Full pipeline (incremental scrapers) in Sprint 36+.\n\n**Legal**: Not financial advice. Not a fatwa. Methodology disclosed. MAR (EU 596/2014) Art. 20 compliant.",
        "operationId": "get_equity_fundamentals_v1_fundamentals_equity__isin__get",
        "parameters": [
          {
            "description": "ISIN code (ISO 6166) \u2014 2 uppercase alpha country code + 9 alphanumeric + 1 numeric check digit. Example: FR0000121014 (LVMH), BE0003604155 (Lotus Bakeries).",
            "in": "path",
            "name": "isin",
            "required": true,
            "schema": {
              "description": "ISIN code (ISO 6166) \u2014 2 uppercase alpha country code + 9 alphanumeric + 1 numeric check digit. Example: FR0000121014 (LVMH), BE0003604155 (Lotus Bakeries).",
              "examples": [
                "FR0000121014",
                "BE0003604155",
                "BE0974293251"
              ],
              "maxLength": 12,
              "minLength": 12,
              "title": "Isin",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EquityFundamentalsResponse"
                }
              }
            },
            "description": "Fundamentals snapshot found."
          },
          "404": {
            "content": {
              "application/json": {
                "example": {
                  "error": "isin_not_found",
                  "isin": "FR0000000000"
                }
              }
            },
            "description": "ISIN not found in marts.fact_equity_fundamentals."
          },
          "422": {
            "description": "Invalid ISIN format (must match [A-Z]{2}[A-Z0-9]{9}\\d)."
          },
          "503": {
            "description": "Database pool not initialised."
          }
        },
        "summary": "EU stock fundamentals + AAOIFI halal screening signal",
        "tags": [
          "fundamentals"
        ]
      }
    },
    "/v1/fx/{base}/{quote}": {
      "get": {
        "description": "Returns the latest available FX exchange rate for a currency pair. Direct pairs are sourced from FRED (Federal Reserve Bank of St. Louis). Cross-rates are computed via USD pivot when no direct FRED series exists. \n\n**Supported codes**: USD, EUR, GBP, JPY, CHF, CNY, CAD, MXN, BRL, AUD, HKD, KRW, SGD, TWD, INR, DKK, NOK, SEK, ZAR, THB, MYR.\n\n**Note**: data has a 1\u20132 day publication lag from FRED. If `data_quality = 'partial'`, the observation is older than 7 days. \n\nRequires scope `fx:read` or `instruments:read`.\n\n**Legal**: Market data only. Not financial advice. MAR Art. 20.",
        "operationId": "get_fx_rate_v1_fx__base___quote__get",
        "parameters": [
          {
            "description": "Base currency ISO 4217 code (e.g. EUR, USD, GBP).",
            "in": "path",
            "name": "base",
            "required": true,
            "schema": {
              "description": "Base currency ISO 4217 code (e.g. EUR, USD, GBP).",
              "examples": [
                "EUR",
                "GBP",
                "USD"
              ],
              "maxLength": 3,
              "minLength": 3,
              "title": "Base",
              "type": "string"
            }
          },
          {
            "description": "Quote currency ISO 4217 code (e.g. USD, GBP, JPY).",
            "in": "path",
            "name": "quote",
            "required": true,
            "schema": {
              "description": "Quote currency ISO 4217 code (e.g. USD, GBP, JPY).",
              "examples": [
                "USD",
                "EUR",
                "JPY"
              ],
              "maxLength": 3,
              "minLength": 3,
              "title": "Quote",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FxResponse"
                }
              }
            },
            "description": "FX rate successfully resolved"
          },
          "422": {
            "description": "Invalid currency codes or same base/quote"
          },
          "503": {
            "description": "FRED data unavailable \u2014 scraper not run or data missing"
          }
        },
        "summary": "Latest FX rate \u2014 base/quote",
        "tags": [
          "fx"
        ]
      }
    },
    "/v1/geopolitical/countries": {
      "get": {
        "description": "Returns the 20 top-GDP countries supported for GDELT geopolitical data (ISO3 codes).",
        "operationId": "get_geopolitical_countries_v1_geopolitical_countries_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeopoliticalCountriesResponse"
                }
              }
            },
            "description": "Countries catalogue returned successfully."
          }
        },
        "summary": "Geopolitical supported countries",
        "tags": [
          "geopolitical"
        ]
      }
    },
    "/v1/geopolitical/event-types": {
      "get": {
        "description": "Returns the supported event type categories for GDELT geopolitical data.",
        "operationId": "get_geopolitical_event_types_v1_geopolitical_event_types_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeopoliticalEventTypesResponse"
                }
              }
            },
            "description": "Event types catalogue returned successfully."
          }
        },
        "summary": "Geopolitical event types",
        "tags": [
          "geopolitical"
        ]
      }
    },
    "/v1/geopolitical/{country_iso3}": {
      "get": {
        "description": "Returns recent GDELT geopolitical event aggregations for one country. Data covers current week (7-day rolling window seeded by default). Supports optional filtering by date range and event type. Supported countries: USA, CHN, JPN, DEU, GBR, FRA, IND, RUS, ITA, BRA, CAN, KOR, ESP, AUS, MEX, IDN, NLD, SAU, TUR, CHE. avg_tone scale: [-10, +10] (normalised from GDELT raw tone). Source: The GDELT Project. License: GDELT open data.",
        "operationId": "get_geopolitical_by_country_v1_geopolitical__country_iso3__get",
        "parameters": [
          {
            "description": "ISO 3166-1 alpha-3 country code (case-insensitive). E.g. 'USA', 'DEU', 'FRA'.",
            "in": "path",
            "name": "country_iso3",
            "required": true,
            "schema": {
              "description": "ISO 3166-1 alpha-3 country code (case-insensitive). E.g. 'USA', 'DEU', 'FRA'.",
              "examples": {
                "default": {
                  "value": "USA"
                }
              },
              "title": "Country Iso3",
              "type": "string"
            }
          },
          {
            "description": "Start date filter (inclusive). ISO format YYYY-MM-DD. Default: no lower bound.",
            "in": "query",
            "name": "start_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date filter (inclusive). ISO format YYYY-MM-DD. Default: no lower bound.",
              "examples": {
                "default": {
                  "value": "2026-05-19"
                }
              },
              "title": "Start Date"
            }
          },
          {
            "description": "End date filter (inclusive). ISO format YYYY-MM-DD. Default: no upper bound.",
            "in": "query",
            "name": "end_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date filter (inclusive). ISO format YYYY-MM-DD. Default: no upper bound.",
              "examples": {
                "default": {
                  "value": "2026-05-26"
                }
              },
              "title": "End Date"
            }
          },
          {
            "description": "Filter by event type. One of: economic, political, conflict, diplomatic, social, general. Default: all types returned.",
            "in": "query",
            "name": "event_type",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by event type. One of: economic, political, conflict, diplomatic, social, general. Default: all types returned.",
              "examples": {
                "default": {
                  "value": "economic"
                }
              },
              "title": "Event Type"
            }
          },
          {
            "description": "Maximum rows to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum rows to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeopoliticalResponse"
                }
              }
            },
            "description": "Events returned successfully."
          },
          "404": {
            "description": "Unknown country_iso3."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "Geopolitical events by country",
        "tags": [
          "geopolitical"
        ]
      }
    },
    "/v1/health/version": {
      "get": {
        "description": "Returns the current API version and a coverage map indicating which data capabilities are active (enabled=true) with their last refresh timestamp and asset count. Used by HalalStack to auto-discover available PIQ data and trigger fallbacks. No auth required. Sprint 28 T-410.",
        "operationId": "get_version_v1_health_version_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersionResponse"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "API version + per-capability coverage map",
        "tags": [
          "health"
        ]
      }
    },
    "/v1/instruments/commodity/{symbol}": {
      "get": {
        "description": "Returns spot price + contract metadata for a commodity symbol. Sources: metals.dev (XAU, XAG \u2014 paid spot 1.79\u20ac/mois) + FRED (CL, BZ, HG \u2014 Federal Reserve Bank of St. Louis, public domain US). HS-blocking fields exposed (raw factual data, no fiqh verdict): instrument_type, is_physically_backed, metal_storage_type. Available symbols: XAU, XAG, CL, BZ, NG, HG, ZW, ZC, KC, SB, CC. Scope: instruments:read (Free tier included \u2014 D-074). Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_commodity_endpoint_v1_instruments_commodity__symbol__get",
        "parameters": [
          {
            "in": "path",
            "name": "symbol",
            "required": true,
            "schema": {
              "title": "Symbol",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_CommodityInstrument_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Commodity spot price + metadata",
        "tags": [
          "instruments-stocks"
        ],
        "x-required-scope": "instruments:read"
      }
    },
    "/v1/instruments/etf": {
      "get": {
        "description": "Full search across ETFs. Searches: ticker prefix, ISIN exact match. Optional filters: issuer, domicile, replication_method. Min 2 chars for search param \u2014 400 if shorter. Returns 0 results (not 500) if sat_etf_metadata is empty. Pagination: meta.total + meta.has_next. licensed_for_commercial_use=true. Scope: instruments:read (Free tier included \u2014 D-074). Factual data only. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "search_instruments_etf_v1_instruments_etf_get",
        "parameters": [
          {
            "description": "Ticker prefix, ISIN, or ETF name. Min 2 chars. Alias: q.",
            "in": "query",
            "name": "search",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Ticker prefix, ISIN, or ETF name. Min 2 chars. Alias: q.",
              "title": "Search"
            }
          },
          {
            "description": "Alias for search.",
            "in": "query",
            "name": "q",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Alias for search.",
              "title": "Q"
            }
          },
          {
            "description": "Filter by issuer (exact): BlackRock, Vanguard, iShares, Amundi, SPDR, Invesco, Xtrackers.",
            "in": "query",
            "name": "issuer",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by issuer (exact): BlackRock, Vanguard, iShares, Amundi, SPDR, Invesco, Xtrackers.",
              "title": "Issuer"
            }
          },
          {
            "description": "Filter by domicile ISO 3166-1 alpha-2: IE, LU, US, FR, DE.",
            "in": "query",
            "name": "domicile",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by domicile ISO 3166-1 alpha-2: IE, LU, US, FR, DE.",
              "title": "Domicile"
            }
          },
          {
            "description": "Filter by replication method: physical_full | physical_sampling | synthetic_swap.",
            "in": "query",
            "name": "replication_method",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by replication method: physical_full | physical_sampling | synthetic_swap.",
              "title": "Replication Method"
            }
          },
          {
            "description": "Results per page [1-100].",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Results per page [1-100].",
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset.",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset.",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_InstrumentEtfList__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Search ETFs by ticker, ISIN, issuer, domicile, or replication method",
        "tags": [
          "instruments-stocks"
        ],
        "x-required-scope": "instruments:read"
      }
    },
    "/v1/instruments/etf/{ticker}": {
      "get": {
        "description": "Returns structural metadata for an ETF ticker or ISIN. Source: dv.sat_etf_metadata (mig 065, populated by T-452 issuer scraper). If sat_etf_metadata empty: returns 404. HS-blocking fields exposed raw \u2014 no fiqh verdict from PIQ. replication_method='synthetic_swap' \u2192 HalalStack classifies haram automatically. licensed_for_commercial_use=true. Scope: instruments:read (Free tier included \u2014 D-074). Factual data only. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_instrument_etf_v1_instruments_etf__ticker__get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_InstrumentEtf_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "ETF metadata \u2014 sat_etf_metadata (mig 065) + EDGAR N-PORT",
        "tags": [
          "instruments-stocks"
        ],
        "x-required-scope": "instruments:read"
      }
    },
    "/v1/instruments/etf/{ticker}/holdings": {
      "get": {
        "description": "Returns paginated ETF constituents with weights for the most recent N-PORT snapshot. Source: dv.sat_etf_holdings (mig 049+068), populated by T-487 N-PORT/KIDs scraper. weight is a fraction (0.0714 = 7.14%). Ordered by weight DESC. Empty data + data_quality='partial' if holdings not yet ingested. synthetic_swap_warning in meta if replication_method='synthetic_swap'. ETF lookthrough halal NOT computed by PIQ \u2014 HalalStack consumes raw holdings. Scope: standard. Licensed sources: EDGAR N-PORT (17 CFR \u00a7200.80) + KIDs PRIIPs EU (Etalab 2.0). Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_etf_holdings_endpoint_v1_instruments_etf__ticker__holdings_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Holdings per page [1-500]",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Holdings per page [1-500]",
              "maximum": 500,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ETFHoldingsResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "ETF holdings \u2014 constituent list with weights (T-485)",
        "tags": [
          "instruments-stocks"
        ],
        "x-required-scope": "instruments:read"
      }
    },
    "/v1/instruments/stock": {
      "get": {
        "description": "Full-text search across stocks. Searches: ticker prefix, ISIN exact match, company name full-text (PostgreSQL tsvector). Two-level: DB first, edgartools fallback if < 3 results. Params: search (alias q), limit [1-100], offset. Min 2 chars \u2014 400 if shorter. Source: dv.sat_stock_enriched (mig 064) + edgar.find_company() fallback. Asia params (Sprint 32 T-587): ?venue=XTKS filters results to a specific MIC exchange. ?include_holidays=true includes holiday sessions. ?display_currency: Sprint 33 only \u2014 returns HTTP 422 if provided. Factual data only. Not financial advice. Methodology disclosed.",
        "operationId": "search_instruments_stock_v1_instruments_stock_get",
        "parameters": [
          {
            "description": "Search query: ticker prefix, ISIN, or company name. Min 2 chars.",
            "in": "query",
            "name": "search",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Search query: ticker prefix, ISIN, or company name. Min 2 chars.",
              "title": "Search"
            }
          },
          {
            "description": "Alias for search. If both provided, search takes precedence.",
            "in": "query",
            "name": "q",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Alias for search. If both provided, search takes precedence.",
              "title": "Q"
            }
          },
          {
            "description": "Results per page [1-100]",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Results per page [1-100]",
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          },
          {
            "description": "Filter by MIC exchange code (ISO-10383). Examples: XTKS (Tokyo), XHKG (Hong Kong), XSES (Singapore), XNSE (India NSE), XKRX (Korea), XASX (Australia), XTAI (Taiwan), XKLS (Bursa Malaysia), XIDX (Indonesia IDX). Must match ^X[A-Z]{3}$ (4-letter MIC code). If omitted: results include all venues.",
            "in": "query",
            "name": "venue",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 4,
                  "minLength": 4,
                  "pattern": "^X[A-Z]{3}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by MIC exchange code (ISO-10383). Examples: XTKS (Tokyo), XHKG (Hong Kong), XSES (Singapore), XNSE (India NSE), XKRX (Korea), XASX (Australia), XTAI (Taiwan), XKLS (Bursa Malaysia), XIDX (Indonesia IDX). Must match ^X[A-Z]{3}$ (4-letter MIC code). If omitted: results include all venues.",
              "examples": {
                "Australia": {
                  "summary": "Australian Securities Exchange",
                  "value": "XASX"
                },
                "HongKong": {
                  "summary": "Hong Kong Exchange",
                  "value": "XHKG"
                },
                "India": {
                  "summary": "NSE India",
                  "value": "XNSE"
                },
                "Korea": {
                  "summary": "Korea Exchange",
                  "value": "XKRX"
                },
                "Singapore": {
                  "summary": "Singapore Exchange",
                  "value": "XSES"
                },
                "Taiwan": {
                  "summary": "Taiwan Stock Exchange",
                  "value": "XTAI"
                },
                "Tokyo": {
                  "summary": "Tokyo Stock Exchange",
                  "value": "XTKS"
                }
              },
              "title": "Venue"
            }
          },
          {
            "description": "If false (default): trading sessions on exchange holidays are excluded from price and OHLCV results. Holiday calendar source: pandas_market_calendars (OSS MIT) + manual curation. If true: all sessions are included regardless of holiday status. Use true for data auditing or completeness checks only.",
            "in": "query",
            "name": "include_holidays",
            "required": false,
            "schema": {
              "default": false,
              "description": "If false (default): trading sessions on exchange holidays are excluded from price and OHLCV results. Holiday calendar source: pandas_market_calendars (OSS MIT) + manual curation. If true: all sessions are included regardless of holiday status. Use true for data auditing or completeness checks only.",
              "title": "Include Holidays",
              "type": "boolean"
            }
          },
          {
            "description": "[Sprint 33 \u2014 Not yet active] Convert displayed prices to the specified currency. Default: prices are returned in the native quote currency of the exchange (JPY for Tokyo, HKD for Hong Kong, SGD for Singapore, etc.). When available (Sprint 33): accepts ISO-4217 codes (USD, EUR, JPY, GBP, etc.). If provided in Sprint 32: returns HTTP 422 with guidance message.",
            "in": "query",
            "name": "display_currency",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 3,
                  "minLength": 3,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "[Sprint 33 \u2014 Not yet active] Convert displayed prices to the specified currency. Default: prices are returned in the native quote currency of the exchange (JPY for Tokyo, HKD for Hong Kong, SGD for Singapore, etc.). When available (Sprint 33): accepts ISO-4217 codes (USD, EUR, JPY, GBP, etc.). If provided in Sprint 32: returns HTTP 422 with guidance message.",
              "title": "Display Currency"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_InstrumentStock__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Search stocks by ticker, ISIN, or company name",
        "tags": [
          "instruments-stocks"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/instruments/stock/batch": {
      "post": {
        "description": "Bulk metadata fetch for up to 100 stock tickers. Premium feature (standard tier+). Results may be partial: unknown tickers return error items, not a 404. Source: DB bulk lookup (1 query) + EDGAR fallback for missing tickers. Request body: {tickers: [...], fields: [...]} (fields is optional projection). Max 100 tickers \u2192 422 if exceeded. Empty list \u2192 422. Factual data only. Not financial advice. Methodology disclosed.",
        "operationId": "batch_instruments_stock_v1_instruments_stock_batch_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StockBatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StockBatchResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Bulk stock metadata \u2014 up to 100 tickers",
        "tags": [
          "instruments-stocks"
        ],
        "x-required-scope": "instruments:batch"
      }
    },
    "/v1/instruments/stock/{ticker}": {
      "get": {
        "description": "Returns structural metadata for a stock ticker. Source: SEC EDGAR (CIK lookup + company facts) via edgartools MIT lib. DB: dv.hub_asset + dv.sat_stock_enriched (mig 064). If ticker not in DB: live EDGAR fetch + automatic seeding. Wave 1: price_usd, market_cap_usd, pe_rolling_12m are nullable (not yet live). Header X-Asset-Kind: stock always present. licensed_for_commercial_use = true (EDGAR = US public domain). Asia params (Sprint 32 T-587): ?venue=XTKS filters multi-listed stocks by exchange MIC. ?include_holidays=true includes holiday sessions (default: excluded). ?display_currency=USD: Sprint 33 only \u2014 returns HTTP 422 if provided now. Factual data only. Not financial advice. Methodology disclosed.",
        "operationId": "get_instrument_stock_v1_instruments_stock__ticker__get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Filter by MIC exchange code (ISO-10383). Examples: XTKS (Tokyo), XHKG (Hong Kong), XSES (Singapore), XNSE (India NSE), XKRX (Korea), XASX (Australia), XTAI (Taiwan), XKLS (Bursa Malaysia), XIDX (Indonesia IDX). Must match ^X[A-Z]{3}$ (4-letter MIC code). If omitted: results include all venues.",
            "in": "query",
            "name": "venue",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 4,
                  "minLength": 4,
                  "pattern": "^X[A-Z]{3}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by MIC exchange code (ISO-10383). Examples: XTKS (Tokyo), XHKG (Hong Kong), XSES (Singapore), XNSE (India NSE), XKRX (Korea), XASX (Australia), XTAI (Taiwan), XKLS (Bursa Malaysia), XIDX (Indonesia IDX). Must match ^X[A-Z]{3}$ (4-letter MIC code). If omitted: results include all venues.",
              "examples": {
                "Australia": {
                  "summary": "Australian Securities Exchange",
                  "value": "XASX"
                },
                "HongKong": {
                  "summary": "Hong Kong Exchange",
                  "value": "XHKG"
                },
                "India": {
                  "summary": "NSE India",
                  "value": "XNSE"
                },
                "Korea": {
                  "summary": "Korea Exchange",
                  "value": "XKRX"
                },
                "Singapore": {
                  "summary": "Singapore Exchange",
                  "value": "XSES"
                },
                "Taiwan": {
                  "summary": "Taiwan Stock Exchange",
                  "value": "XTAI"
                },
                "Tokyo": {
                  "summary": "Tokyo Stock Exchange",
                  "value": "XTKS"
                }
              },
              "title": "Venue"
            }
          },
          {
            "description": "If false (default): trading sessions on exchange holidays are excluded from price and OHLCV results. Holiday calendar source: pandas_market_calendars (OSS MIT) + manual curation. If true: all sessions are included regardless of holiday status. Use true for data auditing or completeness checks only.",
            "in": "query",
            "name": "include_holidays",
            "required": false,
            "schema": {
              "default": false,
              "description": "If false (default): trading sessions on exchange holidays are excluded from price and OHLCV results. Holiday calendar source: pandas_market_calendars (OSS MIT) + manual curation. If true: all sessions are included regardless of holiday status. Use true for data auditing or completeness checks only.",
              "title": "Include Holidays",
              "type": "boolean"
            }
          },
          {
            "description": "[Sprint 33 \u2014 Not yet active] Convert displayed prices to the specified currency. Default: prices are returned in the native quote currency of the exchange (JPY for Tokyo, HKD for Hong Kong, SGD for Singapore, etc.). When available (Sprint 33): accepts ISO-4217 codes (USD, EUR, JPY, GBP, etc.). If provided in Sprint 32: returns HTTP 422 with guidance message.",
            "in": "query",
            "name": "display_currency",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 3,
                  "minLength": 3,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "[Sprint 33 \u2014 Not yet active] Convert displayed prices to the specified currency. Default: prices are returned in the native quote currency of the exchange (JPY for Tokyo, HKD for Hong Kong, SGD for Singapore, etc.). When available (Sprint 33): accepts ISO-4217 codes (USD, EUR, JPY, GBP, etc.). If provided in Sprint 32: returns HTTP 422 with guidance message.",
              "title": "Display Currency"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_InstrumentStock_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Stock metadata \u2014 CIK + company facts + enriched metadata",
        "tags": [
          "instruments-stocks"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/instruments/stock/{ticker}/corporate-actions": {
      "get": {
        "description": "Returns paginated corporate action history for a stock ticker. Event types: split | reverse_split | merger | acquisition | rename | delisting | spinoff. Sources: SEC EDGAR 8-K, Companies House UK, AMF info-financiere FR. All Tier 0 \u2014 licensed_for_commercial_use=true. HTTP 200 with data=[] if no corporate actions ingested. HTTP 404 if ticker unknown. Factual data only. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_stock_corporate_actions_v1_instruments_stock__ticker__corporate_actions_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Page size [1-100]",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Page size [1-100]",
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_CorporateAction__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Stock corporate action history",
        "tags": [
          "instruments-stocks"
        ],
        "x-required-scope": "instruments:read"
      }
    },
    "/v1/instruments/stock/{ticker}/dividends": {
      "get": {
        "description": "Returns paginated dividend history for a stock ticker. Sources: SEC EDGAR 8-K (US stocks), Companies House UK (UK stocks), AMF info-financiere API (FR stocks). All Tier 0 \u2014 licensed_for_commercial_use=true. HTTP 200 with data=[] if ticker has no dividends ingested (e.g. AMZN pre-2024). HTTP 404 if ticker unknown. meta.frequency inferred from >=4 dividends (annual/semi_annual/quarterly/monthly). Factual data only. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_stock_dividends_v1_instruments_stock__ticker__dividends_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Page size [1-100]",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Page size [1-100]",
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_Dividend__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Stock dividend history",
        "tags": [
          "instruments-stocks"
        ],
        "x-required-scope": "instruments:read"
      }
    },
    "/v1/instruments/stock/{ticker}/fundamentals": {
      "get": {
        "description": "Returns raw DJIM inputs for a stock ticker. Supports US tickers (EDGAR XBRL 10-K/10-Q) AND EU Euronext tickers (Yahoo-style MC.PA/TTE.PA/ASML.AS) AND ISIN lookup (FR0000121014). \n\n**US path**: Source: dv.sat_stock_fundamentals (mig 048, EDGAR XBRL). marketCapAvg24m: sat_stock_market_cap_history (mig 067). Values in USD. \n\n**EU path (T-891)**: Source: api_views.stocks_fundamentals_eu (mig 294). Values in native currency (EUR/DKK/SEK\u2026). filing_standard='IFRS'. record_source exposed for traceability. Attribution: info-financiere.gouv.fr (OAM AMF/DILA, licence Etalab 2.0). marketCapCurrent=null, marketCapAvg24m=null (D-170 \u2014 no licensed FR price source). \n\nPIQ exposes raw inputs only \u2014 no DJIM ratio computation (D-070 arbitrage 2). Ratios computed by HalalStack (or any consumer) from these inputs. nonPermissibleRevenue: always null v1. meta.data_quality: 'full' if marketCapAvg24m non-null (US only), 'partial' otherwise. meta.licensed_for_commercial_use: true (EDGAR = US public domain 17 CFR \u00a7200.80 / Etalab 2.0 = commercial use permitted). Factual data only. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_stock_fundamentals_endpoint_v1_instruments_stock__ticker__fundamentals_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_StockFundamentals_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Stock fundamentals \u2014 DJIM inputs bruts (brief HS \u00a74.1) \u2014 US + EU Euronext",
        "tags": [
          "instruments-stocks"
        ],
        "x-required-scope": "instruments:read"
      }
    },
    "/v1/internal/monitoring/hs-anomalies": {
      "get": {
        "description": "Detect anomaly patterns for live alerting.\n\nAnomalies detected:\n  - Any 5xx error\n  - Endpoint with > 50% error rate (and > 5 calls)\n  - Endpoint with p95 latency > 5s\n  - Path requested but returning consistent 404 (suggests missing data PROD)\n  - 429 rate limit hits",
        "operationId": "hs_anomalies_v1_internal_monitoring_hs_anomalies_get",
        "parameters": [
          {
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "default": "1h",
              "pattern": "^\\d+[mhd]$",
              "title": "Since",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Hs Anomalies",
        "tags": [
          "internal-monitoring"
        ]
      }
    },
    "/v1/internal/monitoring/hs-recent-errors": {
      "get": {
        "description": "Recent error responses (4xx, 5xx) from HS test keys.",
        "operationId": "hs_recent_errors_v1_internal_monitoring_hs_recent_errors_get",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "maximum": 500,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "min_status",
            "required": false,
            "schema": {
              "default": 400,
              "maximum": 599,
              "minimum": 100,
              "title": "Min Status",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Hs Recent Errors",
        "tags": [
          "internal-monitoring"
        ]
      }
    },
    "/v1/internal/monitoring/hs-stats": {
      "get": {
        "description": "Detailed stats grouped by path / tier / status.",
        "operationId": "hs_stats_v1_internal_monitoring_hs_stats_get",
        "parameters": [
          {
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "default": "24h",
              "pattern": "^\\d+[mhd]$",
              "title": "Since",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "group_by",
            "required": false,
            "schema": {
              "default": "path",
              "enum": [
                "path",
                "tier",
                "status_code",
                "path_tier"
              ],
              "title": "Group By",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "maximum": 500,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Hs Stats",
        "tags": [
          "internal-monitoring"
        ]
      }
    },
    "/v1/internal/monitoring/hs-summary": {
      "get": {
        "description": "High-level summary : total requests, error rate, avg latency per tier.",
        "operationId": "hs_summary_v1_internal_monitoring_hs_summary_get",
        "parameters": [
          {
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "default": "24h",
              "pattern": "^\\d+[mhd]$",
              "title": "Since",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Hs Summary",
        "tags": [
          "internal-monitoring"
        ]
      }
    },
    "/v1/legal-entity/search": {
      "get": {
        "description": "Full-text name search against the GLEIF LEI database. Queries local DB cache first; falls back to live GLEIF API if no results. Returns up to `limit` results (max 20). Source: GLEIF CC0.",
        "operationId": "search_legal_entity_v1_legal_entity_search_get",
        "parameters": [
          {
            "description": "Legal name search query (e.g. 'Apple', 'LVMH', 'Nestl\u00e9')",
            "in": "query",
            "name": "q",
            "required": true,
            "schema": {
              "description": "Legal name search query (e.g. 'Apple', 'LVMH', 'Nestl\u00e9')",
              "maxLength": 200,
              "minLength": 2,
              "title": "Q",
              "type": "string"
            }
          },
          {
            "description": "Max results (1-20)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Max results (1-20)",
              "maximum": 20,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegalEntitySearchResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Search legal entities by name",
        "tags": [
          "legal-entity"
        ]
      }
    },
    "/v1/legal-entity/{lei}": {
      "get": {
        "description": "Fetch a legal entity record by ISO 17442 LEI code (20 chars). Queries local DB cache first; falls back to live GLEIF API if not cached. Source: GLEIF CC0.",
        "operationId": "get_legal_entity_by_lei_v1_legal_entity__lei__get",
        "parameters": [
          {
            "in": "path",
            "name": "lei",
            "required": true,
            "schema": {
              "title": "Lei",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegalEntityResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get legal entity by LEI",
        "tags": [
          "legal-entity"
        ]
      }
    },
    "/v1/legal-entity/{lei}/sanctions": {
      "get": {
        "description": "Return the cached sanctions screening result for an entity identified by its ISO 17442 LEI code. Sourced from OpenSanctions (CC-BY 4.0). Served from DB cache only \u2014 refresh via seed-opensanctions-known-leis.py. **DISCLAIMER**: informational only, not a substitute for licensed compliance services.",
        "operationId": "get_lei_sanctions_v1_legal_entity__lei__sanctions_get",
        "parameters": [
          {
            "in": "path",
            "name": "lei",
            "required": true,
            "schema": {
              "title": "Lei",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SanctionsResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get sanctions status for a legal entity",
        "tags": [
          "sanctions"
        ]
      }
    },
    "/v1/macro/bis/countries": {
      "get": {
        "description": "Returns the 10 country codes supported for BIS macro data, with pre-computed series keys per dataset.",
        "operationId": "get_bis_countries_v1_macro_bis_countries_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BISCountriesResponse"
                }
              }
            },
            "description": "Countries catalogue returned successfully."
          }
        },
        "summary": "BIS supported country codes",
        "tags": [
          "macro-bis"
        ]
      }
    },
    "/v1/macro/bis/datasets": {
      "get": {
        "description": "Returns the 5 priority BIS macro datasets supported by this API.",
        "operationId": "get_bis_datasets_v1_macro_bis_datasets_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BISDatasetsResponse"
                }
              }
            },
            "description": "Datasets catalogue returned successfully."
          }
        },
        "summary": "BIS supported datasets",
        "tags": [
          "macro-bis"
        ]
      }
    },
    "/v1/macro/bis/{dataset_code}/{series_key}": {
      "get": {
        "description": "Returns observations from BIS Statistics for one dataset and series key. Supported datasets: BIS_CBS, BIS_LBS, BIS_CREDIT, BIS_DEBT, BIS_EER. series_key: BIS SDMX dimension key (e.g. 'Q.US.USD.A.A.TO1.A.A.TO1.A' for CBS/US). Use GET /v1/macro/bis/countries to retrieve pre-computed series keys per country. Observation period format: '2025-Q1' (quarterly), '2024' (annual). Source: Bank for International Settlements (BIS). stats.bis.org.",
        "operationId": "get_bis_series_v1_macro_bis__dataset_code___series_key__get",
        "parameters": [
          {
            "description": "BIS dataset code (case-insensitive). E.g. 'BIS_CBS', 'BIS_CREDIT', 'BIS_EER'.",
            "in": "path",
            "name": "dataset_code",
            "required": true,
            "schema": {
              "description": "BIS dataset code (case-insensitive). E.g. 'BIS_CBS', 'BIS_CREDIT', 'BIS_EER'.",
              "examples": {
                "default": {
                  "value": "BIS_CREDIT"
                }
              },
              "title": "Dataset Code",
              "type": "string"
            }
          },
          {
            "description": "BIS SDMX series key identifying a specific time-series. E.g. 'Q.US.P.770.A.M.XDC.GDP.D.M.IF.B' for BIS_CREDIT/US. Use GET /v1/macro/bis/countries for pre-computed keys per country.",
            "in": "path",
            "name": "series_key",
            "required": true,
            "schema": {
              "description": "BIS SDMX series key identifying a specific time-series. E.g. 'Q.US.P.770.A.M.XDC.GDP.D.M.IF.B' for BIS_CREDIT/US. Use GET /v1/macro/bis/countries for pre-computed keys per country.",
              "examples": {
                "default": {
                  "value": "Q.US.P.770.A.M.XDC.GDP.D.M.IF.B"
                }
              },
              "title": "Series Key",
              "type": "string"
            }
          },
          {
            "description": "Start period filter (inclusive). Format depends on dataset frequency: '2024-Q1' (quarterly), '2023' (annual). Default: no lower bound.",
            "in": "query",
            "name": "start_period",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start period filter (inclusive). Format depends on dataset frequency: '2024-Q1' (quarterly), '2023' (annual). Default: no lower bound.",
              "examples": {
                "annual": {
                  "value": "2023"
                },
                "quarterly": {
                  "value": "2024-Q1"
                }
              },
              "title": "Start Period"
            }
          },
          {
            "description": "End period filter (inclusive). Same format as start_period. Default: no upper bound.",
            "in": "query",
            "name": "end_period",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End period filter (inclusive). Same format as start_period. Default: no upper bound.",
              "examples": {
                "annual": {
                  "value": "2025"
                },
                "quarterly": {
                  "value": "2025-Q2"
                }
              },
              "title": "End Period"
            }
          },
          {
            "description": "Maximum observations to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum observations to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BISSeriesResponse"
                }
              }
            },
            "description": "Observations returned successfully."
          },
          "404": {
            "description": "Unknown dataset_code."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "BIS macro observations by dataset and series key",
        "tags": [
          "macro-bis"
        ]
      }
    },
    "/v1/macro/calendar": {
      "get": {
        "description": "Returns macro-economic events from official sources: FOMC rate decisions, ECB Governing Council meetings, US NFP, CPI, PPI, JOLTS, GDP, PCE. All data is from public domain or attribution-required government sources. Populated by a daily cron at 04:00 UTC.",
        "operationId": "get_macro_calendar_v1_macro_calendar_get",
        "parameters": [
          {
            "description": "Start date (inclusive), format: YYYY-MM-DD.",
            "in": "query",
            "name": "from",
            "required": true,
            "schema": {
              "description": "Start date (inclusive), format: YYYY-MM-DD.",
              "examples": {
                "default": {
                  "value": "2026-05-24"
                }
              },
              "format": "date",
              "title": "From",
              "type": "string"
            }
          },
          {
            "description": "End date (inclusive), format: YYYY-MM-DD.",
            "in": "query",
            "name": "to",
            "required": true,
            "schema": {
              "description": "End date (inclusive), format: YYYY-MM-DD.",
              "examples": {
                "default": {
                  "value": "2026-06-30"
                }
              },
              "format": "date",
              "title": "To",
              "type": "string"
            }
          },
          {
            "description": "Comma-separated ISO-2 country codes, e.g. 'US,EU'. Default: all countries.",
            "in": "query",
            "name": "country",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Comma-separated ISO-2 country codes, e.g. 'US,EU'. Default: all countries.",
              "examples": {
                "default": {
                  "value": "US,EU"
                }
              },
              "title": "Country"
            }
          },
          {
            "description": "Filter by importance level: high | medium | low. Default: all.",
            "in": "query",
            "name": "importance",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by importance level: high | medium | low. Default: all.",
              "examples": {
                "default": {
                  "value": "high"
                }
              },
              "title": "Importance"
            }
          },
          {
            "description": "Maximum events to return. Default: 100, max: 500.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum events to return. Default: 100, max: 500.",
              "maximum": 500,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MacroCalendarResponse"
                }
              }
            },
            "description": "Calendar events returned successfully."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "Macro economic calendar",
        "tags": [
          "macro-calendar"
        ]
      }
    },
    "/v1/macro/eu/series": {
      "get": {
        "description": "Returns the full catalogue of 15 available ECB Statistical Data Warehouse macro series. Covers ECB policy rates, HICP inflation, monetary aggregates (M1/M2/M3), sovereign bond yields, EUR STR/EONIA, GDP, and unemployment. No database query \u2014 served from in-memory catalogue.",
        "operationId": "get_ecb_catalogue_v1_macro_eu_series_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EcbCatalogueResponse"
                }
              }
            },
            "description": "Catalogue returned successfully."
          }
        },
        "summary": "ECB macro series catalogue",
        "tags": [
          "macro-ecb"
        ]
      }
    },
    "/v1/macro/eu/{series_id}": {
      "get": {
        "description": "Returns time-series observations from the ECB Statistical Data Warehouse for the specified macro series. Available series: ECB_DFR, ECB_MRR, ECB_MLR, ECB_HICP_OVERALL, ECB_HICP_CORE, ECB_M1, ECB_M2, ECB_M3, ECB_GOV_10Y_BUND, ECB_GOV_10Y_FRANCE, ECB_GOV_10Y_ITALY, ECB_GOV_10Y_SPAIN, ECB_EONIA, ECB_EUROAREA_GDP, ECB_UNEMPLOYMENT_EA. Data source: ECB SDW. ECB Open Access license. Seeded via scripts/seed-ecb-sdw-macro.py.",
        "operationId": "get_ecb_series_v1_macro_eu__series_id__get",
        "parameters": [
          {
            "description": "ECB series identifier. One of: ECB_DFR, ECB_MRR, ECB_MLR, ECB_HICP_OVERALL, ECB_HICP_CORE, ECB_M1, ECB_M2, ECB_M3, ECB_GOV_10Y_BUND, ECB_GOV_10Y_FRANCE, ECB_GOV_10Y_ITALY, ECB_GOV_10Y_SPAIN, ECB_EONIA, ECB_EUROAREA_GDP, ECB_UNEMPLOYMENT_EA. Case-insensitive.",
            "in": "path",
            "name": "series_id",
            "required": true,
            "schema": {
              "description": "ECB series identifier. One of: ECB_DFR, ECB_MRR, ECB_MLR, ECB_HICP_OVERALL, ECB_HICP_CORE, ECB_M1, ECB_M2, ECB_M3, ECB_GOV_10Y_BUND, ECB_GOV_10Y_FRANCE, ECB_GOV_10Y_ITALY, ECB_GOV_10Y_SPAIN, ECB_EONIA, ECB_EUROAREA_GDP, ECB_UNEMPLOYMENT_EA. Case-insensitive.",
              "examples": {
                "default": {
                  "value": "ECB_DFR"
                }
              },
              "title": "Series Id",
              "type": "string"
            }
          },
          {
            "description": "Start date (inclusive), format: YYYY-MM-DD. Default: no lower bound.",
            "in": "query",
            "name": "start_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date (inclusive), format: YYYY-MM-DD. Default: no lower bound.",
              "examples": {
                "default": {
                  "value": "2026-01-01"
                }
              },
              "title": "Start Date"
            }
          },
          {
            "description": "End date (inclusive), format: YYYY-MM-DD. Default: no upper bound.",
            "in": "query",
            "name": "end_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date (inclusive), format: YYYY-MM-DD. Default: no upper bound.",
              "examples": {
                "default": {
                  "value": "2026-05-31"
                }
              },
              "title": "End Date"
            }
          },
          {
            "description": "Maximum observations to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum observations to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EcbSeriesResponse"
                }
              }
            },
            "description": "Observations returned successfully."
          },
          "404": {
            "description": "Unknown series_id \u2014 use GET /v1/macro/eu/series for catalogue."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "ECB macro time-series",
        "tags": [
          "macro-ecb"
        ]
      }
    },
    "/v1/macro/eurostat/datasets": {
      "get": {
        "description": "Returns the 10 priority Eurostat macro datasets supported by this API.",
        "operationId": "get_eurostat_datasets_v1_macro_eurostat_datasets_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EurostatDatasetsResponse"
                }
              }
            },
            "description": "Datasets catalogue returned successfully."
          }
        },
        "summary": "Eurostat supported datasets",
        "tags": [
          "macro-eurostat"
        ]
      }
    },
    "/v1/macro/eurostat/geo": {
      "get": {
        "description": "Returns the 15 geo codes supported for Eurostat macro data: EA20, EU27_2020, and 13 EU member states.",
        "operationId": "get_eurostat_geo_v1_macro_eurostat_geo_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EurostatGeoResponse"
                }
              }
            },
            "description": "Geo catalogue returned successfully."
          }
        },
        "summary": "Eurostat supported geo codes",
        "tags": [
          "macro-eurostat"
        ]
      }
    },
    "/v1/macro/eurostat/{dataset_code}/{geo_code}": {
      "get": {
        "description": "Returns observations from Eurostat for one dataset and geo code. Supported datasets: prc_hicp_manr, une_rt_m, nama_10_gdp, gov_10dd_edpt1, bop_c6_q, ext_lt_intratrd, prc_ppp_ind, ei_lmiq_q, ei_isen_m, naid_10_gdp. Supported geo codes: EA20, EU27_2020, DE, FR, IT, ES, NL, BE, PT, GR, IE, AT, FI, DK, SE. Observation period format: '2026-03' (monthly), '2026-Q1' (quarterly), '2025' (annual). Source: Eurostat (ec.europa.eu/eurostat).",
        "operationId": "get_eurostat_series_v1_macro_eurostat__dataset_code___geo_code__get",
        "parameters": [
          {
            "description": "Eurostat dataset code (case-insensitive). E.g. 'prc_hicp_manr', 'une_rt_m', 'nama_10_gdp'.",
            "in": "path",
            "name": "dataset_code",
            "required": true,
            "schema": {
              "description": "Eurostat dataset code (case-insensitive). E.g. 'prc_hicp_manr', 'une_rt_m', 'nama_10_gdp'.",
              "examples": {
                "default": {
                  "value": "prc_hicp_manr"
                }
              },
              "title": "Dataset Code",
              "type": "string"
            }
          },
          {
            "description": "Eurostat geo code (case-insensitive). E.g. 'EA20', 'DE', 'FR'. Use EU aggregates: 'EA20', 'EU27_2020'.",
            "in": "path",
            "name": "geo_code",
            "required": true,
            "schema": {
              "description": "Eurostat geo code (case-insensitive). E.g. 'EA20', 'DE', 'FR'. Use EU aggregates: 'EA20', 'EU27_2020'.",
              "examples": {
                "default": {
                  "value": "EA20"
                }
              },
              "title": "Geo Code",
              "type": "string"
            }
          },
          {
            "description": "Start period filter (inclusive). Format depends on dataset frequency: '2025-01' (monthly), '2025-Q1' (quarterly), '2023' (annual). Default: no lower bound.",
            "in": "query",
            "name": "start_period",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start period filter (inclusive). Format depends on dataset frequency: '2025-01' (monthly), '2025-Q1' (quarterly), '2023' (annual). Default: no lower bound.",
              "examples": {
                "monthly": {
                  "value": "2025-01"
                },
                "quarterly": {
                  "value": "2025-Q1"
                }
              },
              "title": "Start Period"
            }
          },
          {
            "description": "End period filter (inclusive). Same format as start_period. Default: no upper bound.",
            "in": "query",
            "name": "end_period",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End period filter (inclusive). Same format as start_period. Default: no upper bound.",
              "examples": {
                "monthly": {
                  "value": "2026-03"
                },
                "quarterly": {
                  "value": "2026-Q1"
                }
              },
              "title": "End Period"
            }
          },
          {
            "description": "Maximum observations to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum observations to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EurostatSeriesResponse"
                }
              }
            },
            "description": "Observations returned successfully."
          },
          "404": {
            "description": "Unknown dataset_code or geo_code."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "Eurostat macro observations by dataset and geo",
        "tags": [
          "macro-eurostat"
        ]
      }
    },
    "/v1/macro/hk/series": {
      "get": {
        "description": "Returns the full catalogue of available Hong Kong Monetary Authority macro series.",
        "operationId": "get_hkma_catalogue_v1_macro_hk_series_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HKMACatalogueResponse"
                }
              }
            },
            "description": "Catalogue returned successfully."
          }
        },
        "summary": "HKMA macro series catalogue",
        "tags": [
          "macro-hkma"
        ]
      }
    },
    "/v1/macro/hk/{series_id}": {
      "get": {
        "description": "Returns time-series observations from the Hong Kong Monetary Authority for the specified macro series. Available series: HKMA_BASE_RATE, HKMA_HKD_USD, HKMA_M1, HKMA_M2, HKMA_M3, HKMA_HIBOR_OVERNIGHT, HKMA_HIBOR_3M, HKMA_FX_RESERVES, HKMA_BANK_RESIDENT_DEPOSITS, HKMA_PROPERTY_PRICE_INDEX. Data source: Hong Kong Monetary Authority (hkma.gov.hk). Hong Kong Government Open Data License. Seeded via scripts/seed-hkma-macro.py.",
        "operationId": "get_hkma_series_v1_macro_hk__series_id__get",
        "parameters": [
          {
            "description": "HKMA series identifier. One of: HKMA_BASE_RATE, HKMA_HKD_USD, HKMA_M1, HKMA_M2, HKMA_M3, HKMA_HIBOR_OVERNIGHT, HKMA_HIBOR_3M, HKMA_FX_RESERVES, HKMA_BANK_RESIDENT_DEPOSITS, HKMA_PROPERTY_PRICE_INDEX.",
            "in": "path",
            "name": "series_id",
            "required": true,
            "schema": {
              "description": "HKMA series identifier. One of: HKMA_BASE_RATE, HKMA_HKD_USD, HKMA_M1, HKMA_M2, HKMA_M3, HKMA_HIBOR_OVERNIGHT, HKMA_HIBOR_3M, HKMA_FX_RESERVES, HKMA_BANK_RESIDENT_DEPOSITS, HKMA_PROPERTY_PRICE_INDEX.",
              "examples": {
                "default": {
                  "value": "HKMA_HKD_USD"
                }
              },
              "title": "Series Id",
              "type": "string"
            }
          },
          {
            "description": "Start date (inclusive), format: YYYY-MM-DD. Default: no lower bound.",
            "in": "query",
            "name": "start_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date (inclusive), format: YYYY-MM-DD. Default: no lower bound.",
              "examples": {
                "default": {
                  "value": "2026-01-01"
                }
              },
              "title": "Start Date"
            }
          },
          {
            "description": "End date (inclusive), format: YYYY-MM-DD. Default: no upper bound.",
            "in": "query",
            "name": "end_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date (inclusive), format: YYYY-MM-DD. Default: no upper bound.",
              "examples": {
                "default": {
                  "value": "2026-05-31"
                }
              },
              "title": "End Date"
            }
          },
          {
            "description": "Maximum observations to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum observations to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HKMASeriesResponse"
                }
              }
            },
            "description": "Observations returned successfully."
          },
          "404": {
            "description": "Unknown series_id \u2014 use GET /v1/macro/hk/series for catalogue."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "HKMA Hong Kong macro time-series",
        "tags": [
          "macro-hkma"
        ]
      }
    },
    "/v1/macro/imf/countries": {
      "get": {
        "description": "Returns the 25 top-GDP countries (ISO3) supported for IMF WEO macro data.",
        "operationId": "get_imf_countries_v1_macro_imf_countries_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImfCountriesResponse"
                }
              }
            },
            "description": "Countries catalogue returned successfully."
          }
        },
        "summary": "IMF WEO supported countries",
        "tags": [
          "macro-imf"
        ]
      }
    },
    "/v1/macro/imf/indicators": {
      "get": {
        "description": "Returns the 10 WEO macro indicators supported for IMF data.",
        "operationId": "get_imf_indicators_v1_macro_imf_indicators_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImfIndicatorsResponse"
                }
              }
            },
            "description": "Indicators catalogue returned successfully."
          }
        },
        "summary": "IMF WEO supported indicators",
        "tags": [
          "macro-imf"
        ]
      }
    },
    "/v1/macro/imf/{country_iso3}/{indicator_code}": {
      "get": {
        "description": "Returns annual observations from the IMF World Economic Outlook (WEO) for one country and indicator. Supported countries: USA, CHN, JPN, DEU, IND, GBR, FRA, ITA, BRA, CAN, RUS, KOR, ESP, AUS, MEX, IDN, NLD, SAU, TUR, CHE, POL, SWE, BEL, ARG, NOR. Supported indicators: NGDP_RPCH, NGDPD, PCPIPCH, LUR, GGXWDG_NGDP, BCA_NGDPD, GGXCNL_NGDP, PCPI, NID_NGDP, NGSD_NGDP. Source: IMF DataMapper. License: IMF Data \u2014 redistribution with attribution.",
        "operationId": "get_imf_series_v1_macro_imf__country_iso3___indicator_code__get",
        "parameters": [
          {
            "description": "ISO 3166-1 alpha-3 country code (case-insensitive). E.g. 'USA', 'DEU', 'FRA'.",
            "in": "path",
            "name": "country_iso3",
            "required": true,
            "schema": {
              "description": "ISO 3166-1 alpha-3 country code (case-insensitive). E.g. 'USA', 'DEU', 'FRA'.",
              "examples": {
                "default": {
                  "value": "USA"
                }
              },
              "title": "Country Iso3",
              "type": "string"
            }
          },
          {
            "description": "IMF WEO indicator code (case-insensitive). E.g. 'NGDP_RPCH', 'PCPIPCH'.",
            "in": "path",
            "name": "indicator_code",
            "required": true,
            "schema": {
              "description": "IMF WEO indicator code (case-insensitive). E.g. 'NGDP_RPCH', 'PCPIPCH'.",
              "examples": {
                "default": {
                  "value": "NGDP_RPCH"
                }
              },
              "title": "Indicator Code",
              "type": "string"
            }
          },
          {
            "description": "Start period filter (inclusive). Format: '2020' or '2020Q1'. Default: no lower bound.",
            "in": "query",
            "name": "start_period",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 7,
                  "minLength": 4,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start period filter (inclusive). Format: '2020' or '2020Q1'. Default: no lower bound.",
              "examples": {
                "default": {
                  "value": "2020"
                }
              },
              "title": "Start Period"
            }
          },
          {
            "description": "End period filter (inclusive). Format: '2024' or '2024Q4'. Default: no upper bound.",
            "in": "query",
            "name": "end_period",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 7,
                  "minLength": 4,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End period filter (inclusive). Format: '2024' or '2024Q4'. Default: no upper bound.",
              "examples": {
                "default": {
                  "value": "2024"
                }
              },
              "title": "End Period"
            }
          },
          {
            "description": "Maximum observations to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum observations to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImfSeriesResponse"
                }
              }
            },
            "description": "Observations returned successfully."
          },
          "404": {
            "description": "Unknown country_iso3 or indicator_code."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "IMF WEO macro indicator by country",
        "tags": [
          "macro-imf"
        ]
      }
    },
    "/v1/macro/japan/series": {
      "get": {
        "description": "Returns the full catalogue of available Bank of Japan macro series.",
        "operationId": "get_boj_catalogue_v1_macro_japan_series_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BojCatalogueResponse"
                }
              }
            },
            "description": "Catalogue returned successfully."
          }
        },
        "summary": "BoJ macro series catalogue",
        "tags": [
          "macro-boj"
        ]
      }
    },
    "/v1/macro/japan/{series_id}": {
      "get": {
        "description": "Returns time-series observations from the Bank of Japan for the specified macro series. Available series: BOJ_POLICY_RATE, BOJ_CPI_CORE, BOJ_M2, BOJ_M3, BOJ_GDP_NOMINAL, BOJ_GDP_REAL, BOJ_USDJPY, BOJ_UNEMPLOYMENT, BOJ_TANKAN_LARGE, BOJ_MONETARY_BASE. Data source: Bank of Japan (boj.or.jp). Open Data Japan Policy license. Seeded via scripts/seed-boj-timeseries.py.",
        "operationId": "get_boj_series_v1_macro_japan__series_id__get",
        "parameters": [
          {
            "description": "BoJ series identifier. One of: BOJ_POLICY_RATE, BOJ_CPI_CORE, BOJ_M2, BOJ_M3, BOJ_GDP_NOMINAL, BOJ_GDP_REAL, BOJ_USDJPY, BOJ_UNEMPLOYMENT, BOJ_TANKAN_LARGE, BOJ_MONETARY_BASE.",
            "in": "path",
            "name": "series_id",
            "required": true,
            "schema": {
              "description": "BoJ series identifier. One of: BOJ_POLICY_RATE, BOJ_CPI_CORE, BOJ_M2, BOJ_M3, BOJ_GDP_NOMINAL, BOJ_GDP_REAL, BOJ_USDJPY, BOJ_UNEMPLOYMENT, BOJ_TANKAN_LARGE, BOJ_MONETARY_BASE.",
              "examples": {
                "default": {
                  "value": "BOJ_USDJPY"
                }
              },
              "title": "Series Id",
              "type": "string"
            }
          },
          {
            "description": "Start date (inclusive), format: YYYY-MM-DD. Default: no lower bound.",
            "in": "query",
            "name": "start_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date (inclusive), format: YYYY-MM-DD. Default: no lower bound.",
              "examples": {
                "default": {
                  "value": "2026-01-01"
                }
              },
              "title": "Start Date"
            }
          },
          {
            "description": "End date (inclusive), format: YYYY-MM-DD. Default: no upper bound.",
            "in": "query",
            "name": "end_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date (inclusive), format: YYYY-MM-DD. Default: no upper bound.",
              "examples": {
                "default": {
                  "value": "2026-05-31"
                }
              },
              "title": "End Date"
            }
          },
          {
            "description": "Maximum observations to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum observations to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BojSeriesResponse"
                }
              }
            },
            "description": "Observations returned successfully."
          },
          "404": {
            "description": "Unknown series_id \u2014 use GET /v1/macro/japan/series for catalogue."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "Bank of Japan macro time-series",
        "tags": [
          "macro-boj"
        ]
      }
    },
    "/v1/macro/kr/series": {
      "get": {
        "description": "Returns the full catalogue of 12 available Bank of Korea ECOS macro series. Covers BoK policy rate, CPI, core CPI, monetary aggregates (M1/M2/M3), KRW/USD exchange rate, GDP (nominal + real), unemployment, PPI, and current account balance. No database query \u2014 served from in-memory catalogue.",
        "operationId": "get_bok_catalogue_v1_macro_kr_series_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BokCatalogueResponse"
                }
              }
            },
            "description": "Catalogue returned successfully."
          }
        },
        "summary": "Bank of Korea macro series catalogue",
        "tags": [
          "macro-bok"
        ]
      }
    },
    "/v1/macro/kr/{series_id}": {
      "get": {
        "description": "Returns time-series observations from the Bank of Korea ECOS for the specified macro series. Available series: BOK_POLICY_RATE, BOK_CPI, BOK_CORE_CPI, BOK_M1, BOK_M2, BOK_M3, BOK_KRW_USD, BOK_GDP_NOMINAL, BOK_GDP_REAL, BOK_UNEMPLOYMENT, BOK_PPI, BOK_CURRENT_ACCOUNT. Source: Bank of Korea ECOS. Korea public sector open data license. Seeded via scripts/seed-bok-ecos.py.",
        "operationId": "get_bok_series_v1_macro_kr__series_id__get",
        "parameters": [
          {
            "description": "BoK ECOS series identifier. One of: BOK_POLICY_RATE, BOK_CPI, BOK_CORE_CPI, BOK_M1, BOK_M2, BOK_M3, BOK_KRW_USD, BOK_GDP_NOMINAL, BOK_GDP_REAL, BOK_UNEMPLOYMENT, BOK_PPI, BOK_CURRENT_ACCOUNT. Case-insensitive.",
            "in": "path",
            "name": "series_id",
            "required": true,
            "schema": {
              "description": "BoK ECOS series identifier. One of: BOK_POLICY_RATE, BOK_CPI, BOK_CORE_CPI, BOK_M1, BOK_M2, BOK_M3, BOK_KRW_USD, BOK_GDP_NOMINAL, BOK_GDP_REAL, BOK_UNEMPLOYMENT, BOK_PPI, BOK_CURRENT_ACCOUNT. Case-insensitive.",
              "examples": {
                "default": {
                  "value": "BOK_POLICY_RATE"
                }
              },
              "title": "Series Id",
              "type": "string"
            }
          },
          {
            "description": "Start date (inclusive), format: YYYY-MM-DD. Default: no lower bound.",
            "in": "query",
            "name": "start_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date (inclusive), format: YYYY-MM-DD. Default: no lower bound.",
              "examples": {
                "default": {
                  "value": "2026-01-01"
                }
              },
              "title": "Start Date"
            }
          },
          {
            "description": "End date (inclusive), format: YYYY-MM-DD. Default: no upper bound.",
            "in": "query",
            "name": "end_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date (inclusive), format: YYYY-MM-DD. Default: no upper bound.",
              "examples": {
                "default": {
                  "value": "2026-05-31"
                }
              },
              "title": "End Date"
            }
          },
          {
            "description": "Maximum observations to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum observations to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BokSeriesResponse"
                }
              }
            },
            "description": "Observations returned successfully."
          },
          "404": {
            "description": "Unknown series_id \u2014 use GET /v1/macro/kr/series for catalogue."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "Bank of Korea ECOS macro time-series",
        "tags": [
          "macro-bok"
        ]
      }
    },
    "/v1/macro/oecd/countries": {
      "get": {
        "description": "Returns the 20 top OECD countries supported for OECD macro data (ISO3 codes).",
        "operationId": "get_oecd_countries_v1_macro_oecd_countries_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OecdCountriesResponse"
                }
              }
            },
            "description": "Countries catalogue returned successfully."
          }
        },
        "summary": "OECD supported countries",
        "tags": [
          "macro-oecd"
        ]
      }
    },
    "/v1/macro/oecd/indicators": {
      "get": {
        "description": "Returns the 10 OECD macro indicators supported by this endpoint.",
        "operationId": "get_oecd_indicators_v1_macro_oecd_indicators_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OecdIndicatorsResponse"
                }
              }
            },
            "description": "Indicators catalogue returned successfully."
          }
        },
        "summary": "OECD supported indicators",
        "tags": [
          "macro-oecd"
        ]
      }
    },
    "/v1/macro/oecd/{country_iso3}/{indicator_code}": {
      "get": {
        "description": "Returns observations from the OECD Stats API for one country and indicator. Supported countries (ISO3): USA, JPN, DEU, GBR, FRA, ITA, CAN, KOR, AUS, ESP, NLD, BEL, CHE, SWE, NOR, FIN, DNK, AUT, IRL, POL. Supported indicators: OECD_GDP_GROWTH, OECD_INFLATION_HICP, OECD_UNEMPLOYMENT, OECD_BALANCE_PAYMENTS_CA, OECD_GOV_DEBT, OECD_LEAD_INDICATOR, OECD_TRADE_EXPORTS, OECD_TRADE_IMPORTS, OECD_PRODUCER_PRICE_INDEX, OECD_INTEREST_RATE_LONG. Source: OECD Stats API. \u00a9 OECD.",
        "operationId": "get_oecd_series_v1_macro_oecd__country_iso3___indicator_code__get",
        "parameters": [
          {
            "description": "ISO 3166-1 alpha-3 country code (case-insensitive). E.g. 'USA', 'DEU', 'FRA'.",
            "in": "path",
            "name": "country_iso3",
            "required": true,
            "schema": {
              "description": "ISO 3166-1 alpha-3 country code (case-insensitive). E.g. 'USA', 'DEU', 'FRA'.",
              "examples": {
                "default": {
                  "value": "USA"
                }
              },
              "title": "Country Iso3",
              "type": "string"
            }
          },
          {
            "description": "OECD indicator code (case-insensitive). E.g. 'OECD_GDP_GROWTH'.",
            "in": "path",
            "name": "indicator_code",
            "required": true,
            "schema": {
              "description": "OECD indicator code (case-insensitive). E.g. 'OECD_GDP_GROWTH'.",
              "examples": {
                "default": {
                  "value": "OECD_GDP_GROWTH"
                }
              },
              "title": "Indicator Code",
              "type": "string"
            }
          },
          {
            "description": "Maximum observations to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum observations to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OecdSeriesResponse"
                }
              }
            },
            "description": "Observations returned successfully."
          },
          "404": {
            "description": "Unknown country_iso3 or indicator_code."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "OECD macro indicator by country",
        "tags": [
          "macro-oecd"
        ]
      }
    },
    "/v1/macro/us-treasury/catalog": {
      "get": {
        "description": "Returns the full catalogue of supported US Treasury Fiscal Data datasets and their available series IDs with metadata. Served from in-memory catalogue \u2014 no DB query.",
        "operationId": "get_treasury_catalog_v1_macro_us_treasury_catalog_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TreasuryCatalogResponse"
                }
              }
            },
            "description": "Catalogue returned successfully."
          }
        },
        "summary": "US Treasury datasets and series catalogue",
        "tags": [
          "macro-us-treasury"
        ]
      }
    },
    "/v1/macro/us-treasury/{dataset_code}/{series_id}": {
      "get": {
        "description": "Returns observations from the US Treasury Fiscal Data API for one dataset and series combination. Supported datasets: daily_treasury_rates_2025, debt_to_penny, monthly_treasury_statement, treasury_general_account_balance, exchange_rates. Use GET /v1/macro/us-treasury/catalog for valid dataset/series codes. Source: US Treasury Fiscal Data API. License: US Public Domain.",
        "operationId": "get_treasury_series_v1_macro_us_treasury__dataset_code___series_id__get",
        "parameters": [
          {
            "description": "Treasury dataset code (case-insensitive). E.g. 'daily_treasury_rates_2025', 'debt_to_penny', 'exchange_rates'.",
            "in": "path",
            "name": "dataset_code",
            "required": true,
            "schema": {
              "description": "Treasury dataset code (case-insensitive). E.g. 'daily_treasury_rates_2025', 'debt_to_penny', 'exchange_rates'.",
              "examples": {
                "default": {
                  "value": "daily_treasury_rates_2025"
                }
              },
              "title": "Dataset Code",
              "type": "string"
            }
          },
          {
            "description": "Series ID within the dataset (case-insensitive). E.g. 'bc_10year', 'tot_pub_debt_out_amt', 'EUR'. Use GET /v1/macro/us-treasury/catalog for valid series IDs.",
            "in": "path",
            "name": "series_id",
            "required": true,
            "schema": {
              "description": "Series ID within the dataset (case-insensitive). E.g. 'bc_10year', 'tot_pub_debt_out_amt', 'EUR'. Use GET /v1/macro/us-treasury/catalog for valid series IDs.",
              "examples": {
                "default": {
                  "value": "bc_10year"
                }
              },
              "title": "Series Id",
              "type": "string"
            }
          },
          {
            "description": "Start date filter (inclusive). Format: YYYY-MM-DD. Default: no lower bound.",
            "in": "query",
            "name": "start_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 10,
                  "minLength": 10,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date filter (inclusive). Format: YYYY-MM-DD. Default: no lower bound.",
              "examples": {
                "default": {
                  "value": "2024-01-01"
                }
              },
              "title": "Start Date"
            }
          },
          {
            "description": "End date filter (inclusive). Format: YYYY-MM-DD. Default: no upper bound.",
            "in": "query",
            "name": "end_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 10,
                  "minLength": 10,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date filter (inclusive). Format: YYYY-MM-DD. Default: no upper bound.",
              "examples": {
                "default": {
                  "value": "2025-12-31"
                }
              },
              "title": "End Date"
            }
          },
          {
            "description": "Maximum observations to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum observations to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TreasurySeriesResponse"
                }
              }
            },
            "description": "Observations returned successfully."
          },
          "404": {
            "description": "Unknown dataset_code or series_id not in catalogue."
          },
          "422": {
            "description": "Invalid query parameters (e.g. start_date after end_date)."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "US Treasury fiscal data by dataset and series",
        "tags": [
          "macro-us-treasury"
        ]
      }
    },
    "/v1/macro/worldbank/countries": {
      "get": {
        "description": "Returns the 20 top-GDP countries supported for World Bank macro data.",
        "operationId": "get_worldbank_countries_v1_macro_worldbank_countries_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WbCountriesResponse"
                }
              }
            },
            "description": "Countries catalogue returned successfully."
          }
        },
        "summary": "World Bank supported countries",
        "tags": [
          "macro-worldbank"
        ]
      }
    },
    "/v1/macro/worldbank/indicators": {
      "get": {
        "description": "Returns the 10 macro indicators supported for World Bank data.",
        "operationId": "get_worldbank_indicators_v1_macro_worldbank_indicators_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WbIndicatorsResponse"
                }
              }
            },
            "description": "Indicators catalogue returned successfully."
          }
        },
        "summary": "World Bank supported indicators",
        "tags": [
          "macro-worldbank"
        ]
      }
    },
    "/v1/macro/worldbank/{country_iso2}/{indicator_code}": {
      "get": {
        "description": "Returns annual observations from the World Bank for one country and indicator. Supported countries: US, CN, JP, DE, IN, GB, FR, IT, CA, KR, RU, BR, AU, ES, MX, ID, NL, SA, TR, CH. Supported indicators: NY.GDP.MKTP.CD, NY.GDP.PCAP.CD, FP.CPI.TOTL.ZG, SL.UEM.TOTL.ZS, SP.POP.TOTL, GC.DOD.TOTL.GD.ZS, NE.EXP.GNFS.ZS, NE.IMP.GNFS.ZS, FR.INR.RINR, BX.KLT.DINV.WD.GD.ZS. Source: World Bank Open Data. License: CC BY 4.0.",
        "operationId": "get_worldbank_series_v1_macro_worldbank__country_iso2___indicator_code__get",
        "parameters": [
          {
            "description": "ISO 3166-1 alpha-2 country code (case-insensitive). E.g. 'US', 'DE', 'FR'.",
            "in": "path",
            "name": "country_iso2",
            "required": true,
            "schema": {
              "description": "ISO 3166-1 alpha-2 country code (case-insensitive). E.g. 'US', 'DE', 'FR'.",
              "examples": {
                "default": {
                  "value": "US"
                }
              },
              "title": "Country Iso2",
              "type": "string"
            }
          },
          {
            "description": "World Bank indicator code. E.g. 'NY.GDP.MKTP.CD'.",
            "in": "path",
            "name": "indicator_code",
            "required": true,
            "schema": {
              "description": "World Bank indicator code. E.g. 'NY.GDP.MKTP.CD'.",
              "examples": {
                "default": {
                  "value": "NY.GDP.MKTP.CD"
                }
              },
              "title": "Indicator Code",
              "type": "string"
            }
          },
          {
            "description": "Start year (inclusive). Default: no lower bound.",
            "in": "query",
            "name": "start_year",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maximum": 2100,
                  "minimum": 1960,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start year (inclusive). Default: no lower bound.",
              "examples": {
                "default": {
                  "value": 2020
                }
              },
              "title": "Start Year"
            }
          },
          {
            "description": "End year (inclusive). Default: no upper bound.",
            "in": "query",
            "name": "end_year",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maximum": 2100,
                  "minimum": 1960,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End year (inclusive). Default: no upper bound.",
              "examples": {
                "default": {
                  "value": 2024
                }
              },
              "title": "End Year"
            }
          },
          {
            "description": "Maximum observations to return. Default: 100, max: 1000.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Maximum observations to return. Default: 100, max: 1000.",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-indexed). Default: 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed). Default: 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WbSeriesResponse"
                }
              }
            },
            "description": "Observations returned successfully."
          },
          "404": {
            "description": "Unknown country_iso2 or indicator_code."
          },
          "422": {
            "description": "Invalid query parameters."
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "World Bank macro indicator by country",
        "tags": [
          "macro-worldbank"
        ]
      }
    },
    "/v1/market-regime/history": {
      "get": {
        "description": "Returns historical regime detections for a single scope.\n\n**Bi-temporal support** (COMITE-025 \u00a73 D4): optional `as_of` parameter filters rows by `load_ts <= as_of` to reconstruct what was known at a given point in time (RFC 3339 format).\n\n**Scope**: `market_regime:read` required (Free tier and above).\n\n**Disclaimer**: Not financial advice. Regime detection uses filtered probabilities only (Hamilton 1989). Historical regimes do not predict future market conditions.",
        "operationId": "get_market_regime_history_v1_market_regime_history_get",
        "parameters": [
          {
            "description": "Single market scope identifier (snake_case). Examples: crypto_large_cap, us_stocks, eu_stocks.",
            "in": "query",
            "name": "scope",
            "required": true,
            "schema": {
              "description": "Single market scope identifier (snake_case). Examples: crypto_large_cap, us_stocks, eu_stocks.",
              "title": "Scope",
              "type": "string"
            }
          },
          {
            "description": "Bi-temporal filter: return rows where load_ts <= as_of. RFC 3339 format (e.g. 2026-01-15T12:00:00Z). If omitted: returns all rows up to now.",
            "in": "query",
            "name": "as_of",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Bi-temporal filter: return rows where load_ts <= as_of. RFC 3339 format (e.g. 2026-01-15T12:00:00Z). If omitted: returns all rows up to now.",
              "title": "As Of"
            }
          },
          {
            "description": "Number of rows to return (1-100, default 20).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Number of rows to return (1-100, default 20).",
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Market regime history for a scope \u2014 bi-temporal (AI)",
        "tags": [
          "market-regime"
        ]
      }
    },
    "/v1/market-regime/latest": {
      "get": {
        "description": "Returns the most recently detected market regime classification for each requested `scope[]` parameter.\n\n**Entitlements**:\n- Free tier: max 5 scopes, weekly refresh cadence.\n- Starter+: max 10 scopes, daily refresh cadence.\n\n**Finance-academic guards** (COMITE-025 \u00a73 D7):\n- `filtered_probability` = P(regime | I_t), Hamilton (1989) \u2014 NEVER smoothed.\n- 2 regimes only: `risk-on` or `risk-off`.\n\n**Disclaimer**: Not financial advice. Regime detection uses filtered probabilities only (Hamilton 1989). Historical regimes do not predict future market conditions.",
        "operationId": "get_market_regime_latest_v1_market_regime_latest_get",
        "parameters": [
          {
            "description": "Market scope identifiers to query. snake_case. Examples: crypto_large_cap, us_stocks, eu_stocks. Free: max 5. Starter+: max 10.",
            "in": "query",
            "name": "scope[]",
            "required": false,
            "schema": {
              "default": [],
              "description": "Market scope identifiers to query. snake_case. Examples: crypto_large_cap, us_stocks, eu_stocks. Free: max 5. Starter+: max 10.",
              "items": {
                "type": "string"
              },
              "maxItems": 10,
              "title": "Scope[]",
              "type": "array"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Latest market regime per scope (AI)",
        "tags": [
          "market-regime"
        ]
      }
    },
    "/v1/news/hn": {
      "get": {
        "description": "Returns Hacker News stories matching the given keyword, paginated. keyword must be one of: bitcoin, ethereum, defi, fintech, stocks, crypto, banking, sec, etf, sukuk. Data refreshed daily by seed-hackernews.py. Scope: news_hn:read. Not financial advice.",
        "operationId": "get_hn_stories_v1_news_hn_get",
        "parameters": [
          {
            "description": "Keyword to filter stories. Must be one of the 10 supported keywords. Use GET /v1/news/hn/catalog for the full list.",
            "in": "query",
            "name": "keyword",
            "required": true,
            "schema": {
              "description": "Keyword to filter stories. Must be one of the 10 supported keywords. Use GET /v1/news/hn/catalog for the full list.",
              "title": "Keyword",
              "type": "string"
            }
          },
          {
            "description": "Number of results per page [1\u2013100]. Default 20.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Number of results per page [1\u2013100]. Default 20.",
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Page number (1-based). Default 1.",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-based). Default 1.",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          },
          {
            "description": "Filter: only stories fetched on or after this snapshot_date (ISO 8601).",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter: only stories fetched on or after this snapshot_date (ISO 8601).",
              "title": "Since"
            }
          },
          {
            "description": "Filter: only stories fetched on or before this snapshot_date (ISO 8601).",
            "in": "query",
            "name": "until",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter: only stories fetched on or before this snapshot_date (ISO 8601).",
              "title": "Until"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HNResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "HN community stories by keyword",
        "tags": [
          "news_hn"
        ],
        "x-required-scope": "news_hn:read"
      }
    },
    "/v1/news/hn/catalog": {
      "get": {
        "description": "Returns the list of 10 keywords indexed from Hacker News. Use any keyword value in the GET /v1/news/hn?keyword= parameter. Scope: news_hn:read.",
        "operationId": "get_hn_catalog_v1_news_hn_catalog_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HNCatalogResponse"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "List supported HN keywords",
        "tags": [
          "news_hn"
        ],
        "x-required-scope": "news_hn:read"
      }
    },
    "/v1/news/{symbol}": {
      "get": {
        "description": "Returns news articles that mention the given asset. symbol can be a stock ticker (AAPL, NESN) or a CoinGecko slug (bitcoin, ethereum). Data: AI-generated sentiment + summary only \u2014 title/excerpt are legally forbidden (EU droit voisin presse, Directive 2019/790 art. 15). Scope: news:read. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_news_for_symbol_v1_news__symbol__get",
        "parameters": [
          {
            "in": "path",
            "name": "symbol",
            "required": true,
            "schema": {
              "title": "Symbol",
              "type": "string"
            }
          },
          {
            "description": "Number of results [1\u2013100]. Default 20.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Number of results [1\u2013100]. Default 20.",
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Filter: only articles published on or after this date (ISO 8601).",
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter: only articles published on or after this date (ISO 8601).",
              "title": "Since"
            }
          },
          {
            "description": "Filter: only articles published on or before this date (ISO 8601).",
            "in": "query",
            "name": "until",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter: only articles published on or before this date (ISO 8601).",
              "title": "Until"
            }
          },
          {
            "description": "Minimum sentiment score (inclusive). Default -1.0.",
            "in": "query",
            "name": "sentiment_min",
            "required": false,
            "schema": {
              "default": -1.0,
              "description": "Minimum sentiment score (inclusive). Default -1.0.",
              "maximum": 1.0,
              "minimum": -1.0,
              "title": "Sentiment Min",
              "type": "number"
            }
          },
          {
            "description": "Maximum sentiment score (inclusive). Default 1.0.",
            "in": "query",
            "name": "sentiment_max",
            "required": false,
            "schema": {
              "default": 1.0,
              "description": "Maximum sentiment score (inclusive). Default 1.0.",
              "maximum": 1.0,
              "minimum": -1.0,
              "title": "Sentiment Max",
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NewsResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "News mentions for an asset",
        "tags": [
          "news"
        ],
        "x-required-scope": "news:read"
      }
    },
    "/v1/notify/halal-board-signup": {
      "post": {
        "description": "Capture email opt-in for the portfolIQ Sharia Board formation announcement. Requires explicit consent (CJUE Planet49). Idempotent: duplicate email returns 200 already_registered, not an error. Public endpoint \u2014 no API key required.",
        "operationId": "halal_board_signup_v1_notify_halal_board_signup_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HalalBoardSignupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Pre-launch opt-in for Sharia Board announcement",
        "tags": [
          "notify"
        ]
      }
    },
    "/v1/ohlcv/history": {
      "get": {
        "description": "Returns the full OHLCV history for an asset \u00d7 venue \u00d7 timeframe. Source: api_views.ohlcv_history \u2192 marts.fact_ohlcv_daily / cagg_ohlcv_*. T-846: ?timeframe=1h|4h|1d|1w|1M (default 1d). Not financial advice. Methodology disclosed.",
        "operationId": "get_ohlcv_history_v1_ohlcv_history_get",
        "parameters": [
          {
            "description": "Asset surrogate key. If omitted, returns history for all assets (paginated).",
            "in": "query",
            "name": "asset_hk",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Asset surrogate key. If omitted, returns history for all assets (paginated).",
              "title": "Asset Hk"
            }
          },
          {
            "description": "Filter by venue surrogate key.",
            "in": "query",
            "name": "venue_hk",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by venue surrogate key.",
              "title": "Venue Hk"
            }
          },
          {
            "description": "Candle timeframe. One of: 1h, 4h, 1d, 1w, 1M. Default: 1d.",
            "in": "query",
            "name": "timeframe",
            "required": false,
            "schema": {
              "default": "1d",
              "description": "Candle timeframe. One of: 1h, 4h, 1d, 1w, 1M. Default: 1d.",
              "title": "Timeframe",
              "type": "string"
            }
          },
          {
            "description": "Start date (ISO8601). Inclusive.",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date (ISO8601). Inclusive.",
              "title": "From Date"
            }
          },
          {
            "description": "End date (ISO8601). Inclusive.",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date (ISO8601). Inclusive.",
              "title": "To Date"
            }
          },
          {
            "description": "Max rows (1-1000, default 100).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Max rows (1-1000, default 100).",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/api__routers__ohlcv__OhlcvResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "OHLCV history for an asset and venue",
        "tags": [
          "ohlcv"
        ]
      }
    },
    "/v1/ohlcv/latest": {
      "get": {
        "description": "Returns the latest OHLCV candle per asset \u00d7 venue, filtered by timeframe. Source: api_views.ohlcv_latest \u2192 marts.fact_ohlcv_daily / cagg_ohlcv_*. T-846: ?timeframe=1h|4h|1d|1w|1M (default 1d). Not financial advice. Methodology disclosed.",
        "operationId": "get_ohlcv_latest_v1_ohlcv_latest_get",
        "parameters": [
          {
            "description": "Filter by asset surrogate key (hex string).",
            "in": "query",
            "name": "asset_hk",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by asset surrogate key (hex string).",
              "title": "Asset Hk"
            }
          },
          {
            "description": "Filter by venue surrogate key.",
            "in": "query",
            "name": "venue_hk",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by venue surrogate key.",
              "title": "Venue Hk"
            }
          },
          {
            "description": "Candle timeframe. One of: 1h, 4h, 1d, 1w, 1M. Default: 1d.",
            "in": "query",
            "name": "timeframe",
            "required": false,
            "schema": {
              "default": "1d",
              "description": "Candle timeframe. One of: 1h, 4h, 1d, 1w, 1M. Default: 1d.",
              "title": "Timeframe",
              "type": "string"
            }
          },
          {
            "description": "Max rows to return (1-1000, default 100).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Max rows to return (1-1000, default 100).",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/api__routers__ohlcv__OhlcvResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Latest OHLCV by asset and venue",
        "tags": [
          "ohlcv"
        ]
      }
    },
    "/v1/onchain/addresses": {
      "get": {
        "description": "Returns the curated catalogue of top well-known EVM addresses (Vitalik.eth, Binance Hot/Cold wallets, major protocol contracts) with their latest on-chain snapshot if seeded. Includes DB-backed metrics when available, catalogue stubs otherwise. Sources: BigQuery crypto_ethereum (MIT), Cloudflare RPC public, Ankr RPC. Seeded by scripts/seed-onchain-bigquery-eth.py.",
        "operationId": "list_addresses_v1_onchain_addresses_get",
        "parameters": [
          {
            "description": "Filter by chain ID. Omit for all chains.",
            "in": "query",
            "name": "chain_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by chain ID. Omit for all chains.",
              "examples": {
                "ethereum": {
                  "value": 1
                }
              },
              "title": "Chain Id"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogueResponse"
                }
              }
            },
            "description": "Address catalogue returned successfully."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "Curated top on-chain addresses catalogue",
        "tags": [
          "onchain"
        ]
      }
    },
    "/v1/onchain/{chain_id}/{address}": {
      "get": {
        "description": "Returns the latest on-chain snapshot for a single EVM address on a given chain. Includes native balance, transaction count, contract metadata, and curated label. Only returns the most recent active record (load_end_ts IS NULL). Sources: BigQuery crypto_ethereum (MIT), Cloudflare RPC public, Ankr RPC. Seeded by scripts/seed-onchain-bigquery-eth.py. Supported chains: 1=Ethereum, 56=BSC, 137=Polygon, 42161=Arbitrum, 10=Optimism, 8453=Base.",
        "operationId": "get_address_snapshot_v1_onchain__chain_id___address__get",
        "parameters": [
          {
            "description": "EVM chain ID. 1=Ethereum, 56=BSC, 137=Polygon, 42161=Arbitrum, 10=Optimism, 8453=Base.",
            "in": "path",
            "name": "chain_id",
            "required": true,
            "schema": {
              "description": "EVM chain ID. 1=Ethereum, 56=BSC, 137=Polygon, 42161=Arbitrum, 10=Optimism, 8453=Base.",
              "examples": {
                "ethereum": {
                  "value": 1
                }
              },
              "title": "Chain Id",
              "type": "integer"
            }
          },
          {
            "description": "EVM address in lowercase hex (0x + 40 chars). Example: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
            "in": "path",
            "name": "address",
            "required": true,
            "schema": {
              "description": "EVM address in lowercase hex (0x + 40 chars). Example: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
              "examples": {
                "vitalik": {
                  "value": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
                }
              },
              "title": "Address",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressSnapshotResponse"
                }
              }
            },
            "description": "On-chain snapshot returned successfully."
          },
          "400": {
            "description": "Invalid address format or unsupported chain ID."
          },
          "404": {
            "description": "No snapshot found for this address \u2014 not yet seeded."
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          },
          "503": {
            "description": "Database temporarily unavailable."
          }
        },
        "summary": "Latest on-chain metrics for one address",
        "tags": [
          "onchain"
        ]
      }
    },
    "/v1/reports/monthly": {
      "get": {
        "description": "Generate and download a factual monthly PDF report. Scope required: `pdf:export` (Business tier). Content: major markets summary, editorial events, halal verdict changes. No investment recommendations. Disclaimer \u00a75.3 on every page. LEGAL: Information factuelle uniquement. Not financial advice. SECURITY: user identity is resolved from the authenticated API key only. The ?user_id= query param is not accepted (IDOR fix \u2014 TICKET-744).",
        "operationId": "monthly_report_v1_reports_monthly_get",
        "parameters": [
          {
            "description": "Report month in YYYY-MM format (e.g. 2026-05).",
            "in": "query",
            "name": "month",
            "required": true,
            "schema": {
              "description": "Report month in YYYY-MM format (e.g. 2026-05).",
              "examples": [
                "2026-05"
              ],
              "title": "Month",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/pdf": {}
            },
            "description": "PDF file \u2014 application/pdf"
          },
          "403": {
            "description": "Missing pdf:export scope (Business tier required)."
          },
          "422": {
            "description": "Invalid month format (expected YYYY-MM)."
          },
          "503": {
            "description": "weasyprint not installed \u2014 PDF generation unavailable."
          }
        },
        "summary": "Monthly factual PDF report (pdf:export scope)",
        "tags": [
          "reports"
        ]
      }
    },
    "/v1/sanctions/screen": {
      "post": {
        "description": "Screen up to 50 legal entities (by LEI) for sanctions in one request. Returns per-entity status: 'screened', 'not_screened', or 'invalid_lei'. Served from DB cache only. Partial results: entities not in cache get status='not_screened' (the batch does not fail). **DISCLAIMER**: informational only, not a substitute for licensed compliance services.",
        "operationId": "batch_screen_sanctions_v1_sanctions_screen_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchScreenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchScreenResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Batch screen up to 50 LEIs for sanctions",
        "tags": [
          "sanctions"
        ]
      }
    },
    "/v1/star/dim/analysis-types": {
      "get": {
        "description": "Returns paginable list of analysis types from marts.dim_analysis_type. Not financial advice. Methodology disclosed.",
        "operationId": "list_dim_analysis_types_v1_star_dim_analysis_types_get",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_DimAnalysisTypeRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List analysis types (dim_analysis_type SCD1)",
        "tags": [
          "star-dims",
          "star-dims"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/dim/assets": {
      "get": {
        "description": "Returns the paginable list of assets from marts.dim_asset. By default returns only is_current=true records (current SCD2 version). Pass ?is_current=false to retrieve archived (historical) versions only. Business key: asset_id (stable integer). coingecko_id is excluded (ToS). Not financial advice. Methodology disclosed.",
        "operationId": "list_dim_assets_v1_star_dim_assets_get",
        "parameters": [
          {
            "description": "Filter SCD2 \u2014 true=current, false=archived",
            "in": "query",
            "name": "is_current",
            "required": false,
            "schema": {
              "default": true,
              "description": "Filter SCD2 \u2014 true=current, false=archived",
              "title": "Is Current",
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_DimAssetRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List assets (dim_asset SCD2)",
        "tags": [
          "star-dims",
          "star-dims"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/dim/assets/{asset_id}": {
      "get": {
        "description": "Returns the most recent SCD2 version of the given asset. In most cases this is the is_current=true version. Returns 404 if asset_id is unknown. Not financial advice. Methodology disclosed.",
        "operationId": "get_dim_asset_v1_star_dim_assets__asset_id__get",
        "parameters": [
          {
            "description": "Stable integer surrogate key from marts.dim_asset (BIGSERIAL, D-063). Type: integer. NOT a coingecko slug. Use /v1/assets/{coingecko_id}/ai-analysis/* for string-keyed lookups.",
            "in": "path",
            "name": "asset_id",
            "required": true,
            "schema": {
              "description": "Stable integer surrogate key from marts.dim_asset (BIGSERIAL, D-063). Type: integer. NOT a coingecko slug. Use /v1/assets/{coingecko_id}/ai-analysis/* for string-keyed lookups.",
              "minimum": 1,
              "title": "Asset Id",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_DimAssetRead_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get asset by asset_id (dim_asset SCD2)",
        "tags": [
          "star-dims",
          "star-dims"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/dim/chains": {
      "get": {
        "description": "Returns paginable list of blockchain chains from marts.dim_chain. Not financial advice. Methodology disclosed.",
        "operationId": "list_dim_chains_v1_star_dim_chains_get",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_DimChainRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List chains (dim_chain SCD1)",
        "tags": [
          "star-dims",
          "star-dims"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/dim/dates": {
      "get": {
        "description": "Returns calendar dates from marts.dim_date (~12k rows, ~33 years). Use ?year=2024 for a full year (up to 366 rows). Use ?from_date=2024-01-01&to_date=2024-03-31 for a custom range. Limit max 1000 \u2014 full dump without filters returns first 1000 rows. Not financial advice. Methodology disclosed.",
        "operationId": "list_dim_dates_v1_star_dim_dates_get",
        "parameters": [
          {
            "description": "Filter by year (YYYY)",
            "in": "query",
            "name": "year",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maximum": 2100,
                  "minimum": 2000,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by year (YYYY)",
              "title": "Year"
            }
          },
          {
            "description": "Start date inclusive (ISO 8601, e.g. 2024-01-01)",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date inclusive (ISO 8601, e.g. 2024-01-01)",
              "title": "From Date"
            }
          },
          {
            "description": "End date inclusive (ISO 8601, e.g. 2024-12-31)",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date inclusive (ISO 8601, e.g. 2024-12-31)",
              "title": "To Date"
            }
          },
          {
            "description": "Max rows returned (default 365, max 1000)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 365,
              "description": "Max rows returned (default 365, max 1000)",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_DimDateRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List calendar dates (dim_date)",
        "tags": [
          "star-dims",
          "star-dims"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/dim/event-types": {
      "get": {
        "description": "Returns paginable list of event types from marts.dim_event_type. Not financial advice. Methodology disclosed.",
        "operationId": "list_dim_event_types_v1_star_dim_event_types_get",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_DimEventTypeRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List event types (dim_event_type SCD1)",
        "tags": [
          "star-dims",
          "star-dims"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/dim/news-sources": {
      "get": {
        "description": "Returns paginable list of news sources from marts.dim_news_source. Not financial advice. Methodology disclosed.",
        "operationId": "list_dim_news_sources_v1_star_dim_news_sources_get",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_DimNewsSourceRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List news sources (dim_news_source SCD1)",
        "tags": [
          "star-dims",
          "star-dims"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/dim/tiers": {
      "get": {
        "description": "Returns paginable list of asset tiers from marts.dim_tier (typically 3 rows). Not financial advice. Methodology disclosed.",
        "operationId": "list_dim_tiers_v1_star_dim_tiers_get",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_DimTierRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List tiers (dim_tier SCD1)",
        "tags": [
          "star-dims",
          "star-dims"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/fact/ai-analyses": {
      "get": {
        "description": "AI-generated analyses per asset and analysis type. Content generated by Claude Haiku 4.5 (85%) / Sonnet 4.6 (15%). ai_generated=true is always present in every payload (transparency). Source: marts.fact_ai_analysis (exposure: public), JOIN dim_asset (current SCD2 version). D-103: locale is FORCED to 'en' on this endpoint. FR/AR analyses are available via /v1/{assets|stocks|etf}/{id}/ai?lang=fr|ar \u2014 not via Star Schema. Requires scope: star:ai (Starter tier and above). star:read alone is insufficient \u2014 star:ai is a distinct premium scope. Not financial advice. AI-generated analysis. Methodology disclosed.",
        "operationId": "get_ai_analyses_v1_star_fact_ai_analyses_get",
        "parameters": [
          {
            "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
            "in": "query",
            "name": "asset_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
              "title": "Asset Id"
            }
          },
          {
            "description": "Analysis type, e.g. 'sentiment_score', 'fundamental_summary'",
            "in": "query",
            "name": "analysis_type_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Analysis type, e.g. 'sentiment_score', 'fundamental_summary'",
              "title": "Analysis Type Id"
            }
          },
          {
            "description": "Start date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date inclusive (YYYY-MM-DD)",
              "title": "From Date"
            }
          },
          {
            "description": "End date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date inclusive (YYYY-MM-DD)",
              "title": "To Date"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 500,
              "maximum": 5000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_FactAiAnalysisRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "AI-generated analyses per asset \u2014 premium (EN only in BI Star Schema)",
        "tags": [
          "star-facts",
          "star-facts"
        ],
        "x-required-scope": "star:ai"
      }
    },
    "/v1/star/fact/asset-fundamentals": {
      "get": {
        "description": "P/S and P/R valuation ratios from DeFiLlama protocol fees (MIT licence). Source: marts.fact_asset_fundamentals (exposure: public_recomputed). Requires scope: star:fundamentals (Starter tier and above). star:read alone is insufficient \u2014 star:fundamentals is a distinct premium scope. Not financial advice. Factual valuation metrics only. Methodology disclosed.",
        "operationId": "get_asset_fundamentals_v1_star_fact_asset_fundamentals_get",
        "parameters": [
          {
            "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
            "in": "query",
            "name": "asset_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
              "title": "Asset Id"
            }
          },
          {
            "description": "Start date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date inclusive (YYYY-MM-DD)",
              "title": "From Date"
            }
          },
          {
            "description": "End date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date inclusive (YYYY-MM-DD)",
              "title": "To Date"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 500,
              "maximum": 5000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_FactAssetFundamentalsRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Protocol valuation fundamentals (P/S, P/R ratios) \u2014 premium",
        "tags": [
          "star-facts",
          "star-facts"
        ],
        "x-required-scope": "star:fundamentals"
      }
    },
    "/v1/star/fact/events": {
      "get": {
        "description": "Market and asset-specific events (halvings, upgrades, listings, macro events). asset_id is NULL for market-wide events (no specific asset). Source: marts.fact_event (exposure: public). Filter by asset_id, event_type_id, and/or date range. Not financial advice. Methodology disclosed.",
        "operationId": "get_events_v1_star_fact_events_get",
        "parameters": [
          {
            "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets) \u2014 omit for market-wide events",
            "in": "query",
            "name": "asset_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets) \u2014 omit for market-wide events",
              "title": "Asset Id"
            }
          },
          {
            "description": "Event type identifier, e.g. 'halving', 'upgrade'",
            "in": "query",
            "name": "event_type_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Event type identifier, e.g. 'halving', 'upgrade'",
              "title": "Event Type Id"
            }
          },
          {
            "description": "Start date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date inclusive (YYYY-MM-DD)",
              "title": "From Date"
            }
          },
          {
            "description": "End date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date inclusive (YYYY-MM-DD)",
              "title": "To Date"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 500,
              "maximum": 5000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_FactEventRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Market and asset-specific events",
        "tags": [
          "star-facts",
          "star-facts"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/fact/market-snapshots": {
      "get": {
        "description": "Daily market snapshot per asset (price, market cap, volume, 24h change, tier). Source: marts.fact_market_snapshot (exposure: public_recomputed). Header X-Attribution: portfoliq-recomputed is always present. Filter by asset_id and/or date range. Paginated. Not financial advice. Methodology disclosed.",
        "operationId": "get_market_snapshots_v1_star_fact_market_snapshots_get",
        "parameters": [
          {
            "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
            "in": "query",
            "name": "asset_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
              "title": "Asset Id"
            }
          },
          {
            "description": "Start date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date inclusive (YYYY-MM-DD)",
              "title": "From Date"
            }
          },
          {
            "description": "End date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date inclusive (YYYY-MM-DD)",
              "title": "To Date"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 500,
              "maximum": 5000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_FactMarketSnapshotRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Daily market snapshots per asset",
        "tags": [
          "star-facts",
          "star-facts"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/fact/news-mentions": {
      "get": {
        "description": "News article-asset mentions bridge table. Grain: (article_id, asset_id). One article mentioning N assets produces N rows \u2014 this is expected behavior. Filter by asset_id to get all articles mentioning a specific asset. Source: marts.fact_news_mention (exposure: public_recomputed). Not financial advice. Methodology disclosed.",
        "operationId": "get_news_mentions_v1_star_fact_news_mentions_get",
        "parameters": [
          {
            "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
            "in": "query",
            "name": "asset_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
              "title": "Asset Id"
            }
          },
          {
            "description": "Start date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date inclusive (YYYY-MM-DD)",
              "title": "From Date"
            }
          },
          {
            "description": "End date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date inclusive (YYYY-MM-DD)",
              "title": "To Date"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 500,
              "maximum": 5000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_FactNewsMentionRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "News article\u2013asset mentions bridge (many-to-many)",
        "tags": [
          "star-facts",
          "star-facts"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/fact/onchain-advanced": {
      "get": {
        "description": "Advanced on-chain metrics currently available for Bitcoin (BTC) only. Returns MVRV, NUPL, SOPR and HODL waves (age buckets). Querying a non-BTC asset returns an empty list (200 OK) \u2014 not a 404. Source: bigquery-public-data.crypto_bitcoin (MIT licence). Factual descriptive metrics. Not financial advice. Methodology disclosed.",
        "operationId": "get_onchain_advanced_v1_star_fact_onchain_advanced_get",
        "parameters": [
          {
            "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets) \u2014 currently BTC only",
            "in": "query",
            "name": "asset_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets) \u2014 currently BTC only",
              "title": "Asset Id"
            }
          },
          {
            "description": "Start date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date inclusive (YYYY-MM-DD)",
              "title": "From Date"
            }
          },
          {
            "description": "End date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date inclusive (YYYY-MM-DD)",
              "title": "To Date"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 500,
              "maximum": 5000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_FactOnchainAdvancedRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Advanced on-chain metrics (BTC-only: MVRV, NUPL, SOPR, HODL waves)",
        "tags": [
          "star-facts",
          "star-facts"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/fact/onchain-core": {
      "get": {
        "description": "Core on-chain metrics: active addresses, transaction count, volume, hash rate. Source: marts.fact_onchain_core (exposure: public_recomputed). hash_rate is NULL for non-PoW assets. Filter by asset_id and/or date range. Paginated. Not financial advice. Methodology disclosed.",
        "operationId": "get_onchain_core_v1_star_fact_onchain_core_get",
        "parameters": [
          {
            "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
            "in": "query",
            "name": "asset_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
              "title": "Asset Id"
            }
          },
          {
            "description": "Start date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date inclusive (YYYY-MM-DD)",
              "title": "From Date"
            }
          },
          {
            "description": "End date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date inclusive (YYYY-MM-DD)",
              "title": "To Date"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 500,
              "maximum": 5000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_FactOnchainCoreRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Core on-chain metrics per asset per date",
        "tags": [
          "star-facts",
          "star-facts"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/fact/protocol-economics": {
      "get": {
        "description": "Protocol fees and revenue (24h, 7d) from DeFiLlama (MIT licence). Note: protocol_id = defillama_slug (direct FK \u2014 no dim_protocol yet, see BACKLOG Sprint 20+). Source: marts.fact_protocol_economics (exposure: public). Filter by protocol_id and/or date range. Not financial advice. Methodology disclosed.",
        "operationId": "get_protocol_economics_v1_star_fact_protocol_economics_get",
        "parameters": [
          {
            "description": "DeFiLlama slug, e.g. 'uniswap', 'aave-v3'",
            "in": "query",
            "name": "protocol_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "DeFiLlama slug, e.g. 'uniswap', 'aave-v3'",
              "title": "Protocol Id"
            }
          },
          {
            "description": "Start date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date inclusive (YYYY-MM-DD)",
              "title": "From Date"
            }
          },
          {
            "description": "End date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date inclusive (YYYY-MM-DD)",
              "title": "To Date"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 500,
              "maximum": 5000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_FactProtocolEconomicsRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Protocol fees and revenue (DeFiLlama)",
        "tags": [
          "star-facts",
          "star-facts"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/fact/protocol-tvl": {
      "get": {
        "description": "Protocol TVL self-calculated from on-chain pool balances. Note: protocol_id = defillama_slug (direct FK \u2014 no dim_protocol yet, see BACKLOG Sprint 20+). Source: marts.fact_protocol_tvl (exposure: public_recomputed). Filter by protocol_id (e.g. 'uniswap', 'aave') and/or date range. Not financial advice. Methodology disclosed.",
        "operationId": "get_protocol_tvl_v1_star_fact_protocol_tvl_get",
        "parameters": [
          {
            "description": "DeFiLlama slug, e.g. 'uniswap', 'aave'",
            "in": "query",
            "name": "protocol_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "DeFiLlama slug, e.g. 'uniswap', 'aave'",
              "title": "Protocol Id"
            }
          },
          {
            "description": "Start date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date inclusive (YYYY-MM-DD)",
              "title": "From Date"
            }
          },
          {
            "description": "End date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date inclusive (YYYY-MM-DD)",
              "title": "To Date"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 500,
              "maximum": 5000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_FactProtocolTvlRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Protocol TVL snapshots (DeFiLlama)",
        "tags": [
          "star-facts",
          "star-facts"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/star/fact/vwap-consensus": {
      "get": {
        "description": "VWAP consensus computed from multiple exchanges (methodology/vwap-consensus-v1.1.md). Source: marts.fact_vwap_consensus (exposure: public). Filter by asset_id, timeframe (1d|1h), and/or date range. Paginated. Not financial advice. Methodology disclosed.",
        "operationId": "get_vwap_consensus_v1_star_fact_vwap_consensus_get",
        "parameters": [
          {
            "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
            "in": "query",
            "name": "asset_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "description": "portfolIQ integer asset_id (see GET /v1/star/dim/assets)",
              "title": "Asset Id"
            }
          },
          {
            "description": "Start date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date inclusive (YYYY-MM-DD)",
              "title": "From Date"
            }
          },
          {
            "description": "End date inclusive (YYYY-MM-DD)",
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date inclusive (YYYY-MM-DD)",
              "title": "To Date"
            }
          },
          {
            "description": "1d (daily) or 1h (hourly) \u2014 matches marts.fact_vwap_consensus.timeframe values",
            "in": "query",
            "name": "timeframe",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^(1d|1h)$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "default": "1d",
              "description": "1d (daily) or 1h (hourly) \u2014 matches marts.fact_vwap_consensus.timeframe values",
              "title": "Timeframe"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 500,
              "maximum": 5000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_list_FactVwapConsensusRead__"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "VWAP consensus price per asset per timeframe",
        "tags": [
          "star-facts",
          "star-facts"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/stock/{ticker}/krx-eod": {
      "get": {
        "description": "Returns end-of-day price history (open/high/low/close/volume in KRW) for a Korea Exchange (KRX / XKRX) listed stock. Ticker is the 6-digit KRX code (e.g. 005930 for Samsung Electronics). Source: Korea Exchange Open Data Portal (data.krx.co.kr). License: Korea Open Government Data License (\u2248 CC-BY). Not financial advice. Methodology disclosed.",
        "operationId": "get_krx_eod_v1_stock__ticker__krx_eod_get",
        "parameters": [
          {
            "description": "6-digit KRX ticker code, e.g. 005930 (Samsung Electronics).",
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "description": "6-digit KRX ticker code, e.g. 005930 (Samsung Electronics).",
              "maxLength": 10,
              "minLength": 4,
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Start date filter (ISO 8601, inclusive), e.g. 2026-05-01.",
            "in": "query",
            "name": "start_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date filter (ISO 8601, inclusive), e.g. 2026-05-01.",
              "title": "Start Date"
            }
          },
          {
            "description": "End date filter (ISO 8601, inclusive), e.g. 2026-05-26.",
            "in": "query",
            "name": "end_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date filter (ISO 8601, inclusive), e.g. 2026-05-26.",
              "title": "End Date"
            }
          },
          {
            "description": "Page number (1-indexed).",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed).",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          },
          {
            "description": "Page size (max 500).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 30,
              "description": "Page size (max 500).",
              "maximum": 500,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KrxEodResponse"
                }
              }
            },
            "description": "EOD price history returned successfully."
          },
          "404": {
            "description": "Ticker not found in XKRX hub_asset."
          },
          "422": {
            "description": "Invalid query parameters (date format or range error)."
          },
          "503": {
            "description": "Database unavailable."
          }
        },
        "summary": "KRX EOD prices for a stock",
        "tags": [
          "krx-eod"
        ]
      }
    },
    "/v1/stock/{ticker}/lse-eod": {
      "get": {
        "description": "Return LSE delayed end-of-day price bars (open/high/low/close/volume in GBP) for an XLON-listed stock. Data served from DB cache (populated by seed-lse-delayed-top25.py). Covers FTSE 100 top 25 stocks. Prices delayed 15 minutes. Source: London Stock Exchange \u2014 LSE Open Data 2024+.",
        "operationId": "get_stock_lse_eod_v1_stock__ticker__lse_eod_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Inclusive start date filter (ISO 8601, e.g. 2026-05-01)",
            "in": "query",
            "name": "start_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Inclusive start date filter (ISO 8601, e.g. 2026-05-01)",
              "title": "Start Date"
            }
          },
          {
            "description": "Inclusive end date filter (ISO 8601, e.g. 2026-05-22)",
            "in": "query",
            "name": "end_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Inclusive end date filter (ISO 8601, e.g. 2026-05-22)",
              "title": "End Date"
            }
          },
          {
            "description": "Max rows to return (1-500, default 30)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 30,
              "description": "Max rows to return (1-500, default 30)",
              "maximum": 500,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LseEodResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get LSE delayed EOD prices for an XLON stock",
        "tags": [
          "lse_eod"
        ]
      }
    },
    "/v1/stock/{ticker}/twse-eod": {
      "get": {
        "description": "Returns end-of-day price history (open/high/low/close/volume in TWD) for a Taiwan Stock Exchange (TWSE / XTAI) listed stock. Ticker is the 4-digit TWSE code (e.g. 2330 for TSMC). Source: Taiwan data.gov.tw dataset/11549 (OGD v1). Not financial advice. Methodology disclosed.",
        "operationId": "get_twse_eod_v1_stock__ticker__twse_eod_get",
        "parameters": [
          {
            "description": "4-digit TWSE ticker code, e.g. 2330 (TSMC).",
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "description": "4-digit TWSE ticker code, e.g. 2330 (TSMC).",
              "maxLength": 8,
              "minLength": 2,
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Start date filter (ISO 8601, inclusive), e.g. 2026-05-01.",
            "in": "query",
            "name": "start_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start date filter (ISO 8601, inclusive), e.g. 2026-05-01.",
              "title": "Start Date"
            }
          },
          {
            "description": "End date filter (ISO 8601, inclusive), e.g. 2026-05-26.",
            "in": "query",
            "name": "end_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End date filter (ISO 8601, inclusive), e.g. 2026-05-26.",
              "title": "End Date"
            }
          },
          {
            "description": "Page number (1-indexed).",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "description": "Page number (1-indexed).",
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          },
          {
            "description": "Page size (max 500).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 30,
              "description": "Page size (max 500).",
              "maximum": 500,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwseEodResponse"
                }
              }
            },
            "description": "EOD price history returned successfully."
          },
          "404": {
            "description": "Ticker not found in XTAI hub_asset."
          },
          "422": {
            "description": "Invalid query parameters (date format or range error)."
          },
          "503": {
            "description": "Database unavailable."
          }
        },
        "summary": "TWSE EOD prices for a stock",
        "tags": [
          "twse-eod"
        ]
      }
    },
    "/v1/stocks/batch": {
      "post": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use POST /v1/instruments/stock/batch instead. Returns the same payload with a Link header pointing to the canonical URL. Not financial advice. Methodology disclosed.",
        "operationId": "batch_stocks_alias_v1_stocks_batch_post",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Batch Stocks Alias V1 Stocks Batch Post"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Batch get stocks (alias \u2014 deprecated)",
        "tags": [
          "stocks-alias"
        ]
      }
    },
    "/v1/stocks/search": {
      "get": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use GET /v1/instruments/stock instead. Returns the same payload with a Link header pointing to the canonical URL. Not financial advice. Methodology disclosed.",
        "operationId": "search_stocks_alias_v1_stocks_search_get",
        "parameters": [
          {
            "description": "Search query",
            "in": "query",
            "name": "q",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Search query",
              "title": "Q"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Search Stocks Alias V1 Stocks Search Get"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Search stocks (alias \u2014 deprecated)",
        "tags": [
          "stocks-alias"
        ]
      }
    },
    "/v1/stocks/{ticker}": {
      "get": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use GET /v1/instruments/stock/{ticker} instead. Returns the same payload with an additional Link header pointing to the canonical URL. Pattern: Stripe /charges \u2194 /payment_intents. Not financial advice. Methodology disclosed.",
        "operationId": "get_stock_alias_v1_stocks__ticker__get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Stock Alias V1 Stocks  Ticker  Get"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get stock by ticker (alias \u2014 deprecated)",
        "tags": [
          "stocks-alias"
        ]
      }
    },
    "/v1/stocks/{ticker}/ai": {
      "get": {
        "description": "AI-generated analysis for a stock ticker. Legacy types: fundamental (default), halal_screening, sector_context. Extended types (D-102, pre-seeded from KB): growth_analysis, valuation_analysis, competitive_moat, risk_assessment, catalysts_outlook, narrative_thesis, peer_comparison. Extended types are read directly from dv.sat_asset_ai_analysis (no LLM call). Returns 404 if extended type has no seeded content yet. Returns 404 for tokenomics_deep_dive (crypto only \u2014 not applicable to stocks). PIQ exposes factual inputs ONLY. No investment verdict. Scope: pro. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_stock_ai_v1_stocks__ticker__ai_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Analysis type. 'fundamental': PE/EPS/revenue (Haiku 4.5, live generation). 'halal_screening': AAOIFI/DJIM ratio inputs (Sonnet 4.6 override). 'sector_context': GICS sector context (Haiku 4.5). Extended (D-102, pre-seeded): growth_analysis, valuation_analysis, competitive_moat, risk_assessment, catalysts_outlook, narrative_thesis, peer_comparison.",
            "in": "query",
            "name": "analysis_type",
            "required": false,
            "schema": {
              "default": "fundamental",
              "description": "Analysis type. 'fundamental': PE/EPS/revenue (Haiku 4.5, live generation). 'halal_screening': AAOIFI/DJIM ratio inputs (Sonnet 4.6 override). 'sector_context': GICS sector context (Haiku 4.5). Extended (D-102, pre-seeded): growth_analysis, valuation_analysis, competitive_moat, risk_assessment, catalysts_outlook, narrative_thesis, peer_comparison.",
              "enum": [
                "fundamental",
                "halal_screening",
                "sector_context",
                "growth_analysis",
                "valuation_analysis",
                "competitive_moat",
                "risk_assessment",
                "catalysts_outlook",
                "narrative_thesis",
                "peer_comparison"
              ],
              "title": "Analysis Type",
              "type": "string"
            }
          },
          {
            "description": "Requested locale for AI analysis: 'en' (default), 'fr' (Pro tier), 'ar' (Enterprise tier). Falls back to Accept-Language header, then 'en'. If requested locale has no data, EN is served and meta.fallback_used=true.",
            "in": "query",
            "name": "lang",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Requested locale for AI analysis: 'en' (default), 'fr' (Pro tier), 'ar' (Enterprise tier). Falls back to Accept-Language header, then 'en'. If requested locale has no data, EN is served and meta.fallback_used=true.",
              "title": "Lang"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiResponse_StockAIAnalysis_"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Stock AI analysis \u2014 fundamental + halal screening + extended types (D-102)",
        "tags": [
          "stocks-alias"
        ],
        "x-required-scope": "pro"
      }
    },
    "/v1/stocks/{ticker}/corporate-actions": {
      "get": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use GET /v1/instruments/stock/{ticker}/corporate-actions instead. Event types: split | reverse_split | merger | acquisition | rename | delisting | spinoff. HTTP 200 with data=[] if no actions ingested. HTTP 404 if ticker unknown. Scope: standard. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_stock_corporate_actions_alias_v1_stocks__ticker__corporate_actions_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Page size [1-100]",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Page size [1-100]",
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Stock Corporate Actions Alias V1 Stocks  Ticker  Corporate Actions Get"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Stock corporate action history (alias \u2014 deprecated)",
        "tags": [
          "stocks-alias"
        ]
      }
    },
    "/v1/stocks/{ticker}/dividends": {
      "get": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use GET /v1/instruments/stock/{ticker}/dividends instead. Paginated dividend history. Sources: EDGAR 8-K, Companies House UK, AMF FR. HTTP 200 with data=[] if no dividends ingested. HTTP 404 if ticker unknown. Scope: standard. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_stock_dividends_alias_v1_stocks__ticker__dividends_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "Page size [1-100]",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Page size [1-100]",
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "Pagination offset",
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "description": "Pagination offset",
              "minimum": 0,
              "title": "Offset",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Stock Dividends Alias V1 Stocks  Ticker  Dividends Get"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Stock dividend history (alias \u2014 deprecated)",
        "tags": [
          "stocks-alias"
        ]
      }
    },
    "/v1/stocks/{ticker}/fundamentals": {
      "get": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use GET /v1/instruments/stock/{ticker}/fundamentals instead. Returns raw DJIM inputs (brief HS \u00a74.1) with Link header pointing to canonical URL. Source: sat_stock_fundamentals (mig 048) + sat_stock_market_cap_history (mig 067). PIQ exposes raw inputs only \u2014 no DJIM ratio computation (D-070 arbitrage 2). Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_stock_fundamentals_alias_v1_stocks__ticker__fundamentals_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Stock Fundamentals Alias V1 Stocks  Ticker  Fundamentals Get"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Stock fundamentals (alias \u2014 deprecated) \u2014 DJIM inputs bruts",
        "tags": [
          "stocks-alias"
        ]
      }
    },
    "/v1/stocks/{ticker}/prices": {
      "get": {
        "description": "EOD price history for US equities from Databento EQUS.SUMMARY consolidated feed (api_views.stocks_us_eod, dv.sat_stock_price_eod, migration 282). Falls back to consensus (api_views.stocks_price_consensus) if Databento data absent. Candles include market_cap_usd (derived: close \u00d7 shares EDGAR \u2014 redistributable now) and close_adjusted_usd (= close_usd, adj_applied=false \u2014 splits adjustment Sprint 114). Range: 1d|7d|30d|90d|1y|2y (default 30d). Granularity: daily. LEGAL-004: price_type=raw_consolidated after Databento \u00a76 confirmation; market_cap_usd=derived always redistributable (pilier A). Cache: Redis TTL 7d historical / 1h today. Scope: star:read. DISCLAIMER: Factual data only. Not financial advice. EOD/delayed only. Not a substitute for real-time exchange proprietary feeds.",
        "operationId": "get_stock_prices_v1_stocks__ticker__prices_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          },
          {
            "description": "1d|7d|30d|90d|1y|2y",
            "in": "query",
            "name": "range",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "default": "30d",
              "description": "1d|7d|30d|90d|1y|2y",
              "title": "Range"
            }
          },
          {
            "description": "Only 'daily' in Sprint 31",
            "in": "query",
            "name": "granularity",
            "required": false,
            "schema": {
              "default": "daily",
              "description": "Only 'daily' in Sprint 31",
              "title": "Granularity",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "from_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "From Date"
            }
          },
          {
            "in": "query",
            "name": "to_date",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "To Date"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StockPriceResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Stock EOD price history \u2014 Databento EQUS.SUMMARY (Sprint 113)",
        "tags": [
          "prices-stocks"
        ],
        "x-required-scope": "star:read"
      }
    },
    "/v1/stocks/{ticker}/segments": {
      "get": {
        "deprecated": true,
        "description": "**Deprecated alias.** Use GET /v1/instruments/stock/{ticker}/segments instead. Returns the latest revenue breakdown by business segment and geography, plus GICS 4-digit sub-industry code. Source: dv.sat_stock_segments (mig 228). Data sourced from SEC EDGAR XBRL or curated 10-K annual reports (MVP). Returns 404 if ticker unknown or no segment data ingested. LEGAL: EDGAR = US public domain 17 CFR \u00a7200.80. Scope: standard. Not financial advice. Not a fatwa. Methodology disclosed.",
        "operationId": "get_stock_segments_v1_stocks__ticker__segments_get",
        "parameters": [
          {
            "in": "path",
            "name": "ticker",
            "required": true,
            "schema": {
              "title": "Ticker",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "title": "Response Get Stock Segments V1 Stocks  Ticker  Segments Get"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Stock revenue segments + geographic breakdown (DAT-007) (alias \u2014 deprecated)",
        "tags": [
          "stocks-alias"
        ]
      }
    },
    "/v1/stream/health": {
      "get": {
        "description": "Return stream service health: poll task status + active connections.\n\nPublic endpoint \u2014 no auth required (mirrors /v1/health pattern).",
        "operationId": "stream_health_v1_stream_health_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response Stream Health V1 Stream Health Get",
                  "type": "object"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Stream service health",
        "tags": [
          "stream",
          "stream"
        ]
      }
    },
    "/v1/stripe/webhook": {
      "post": {
        "description": "Receives and processes Stripe events (checkout.session.completed, invoice.paid, customer.subscription.deleted, invoice.payment_failed). Returns 503 if STRIPE_WEBHOOK_SECRET is not set (D-139 NoGo active). Verifies HMAC-SHA256 signature before processing any event.",
        "operationId": "stripe_webhook_v1_stripe_webhook_post",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Stripe webhook receiver (DORMANT \u2014 D-139)",
        "tags": [
          "stripe-webhooks"
        ]
      }
    },
    "/v1/sukuk": {
      "get": {
        "description": "Returns sukuk filtered by type and/or issuer country. With no filters, returns all 20 seeded sukuk. Results capped at 100.",
        "operationId": "list_sukuk_v1_sukuk_get",
        "parameters": [
          {
            "description": "Filter by sukuk type: sukuk_ijara | sukuk_murabaha | sukuk_mudaraba | sukuk_musharaka | sukuk_wakala | sukuk_istisna | sukuk_salam | sukuk_hybrid",
            "in": "query",
            "name": "type",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by sukuk type: sukuk_ijara | sukuk_murabaha | sukuk_mudaraba | sukuk_musharaka | sukuk_wakala | sukuk_istisna | sukuk_salam | sukuk_hybrid",
              "title": "Type"
            }
          },
          {
            "description": "Filter by issuer country ISO 3166-1 alpha-2 (e.g. 'MY', 'SA', 'AE')",
            "in": "query",
            "name": "issuer_country",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 2,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by issuer country ISO 3166-1 alpha-2 (e.g. 'MY', 'SA', 'AE')",
              "title": "Issuer Country"
            }
          },
          {
            "description": "Max results (1-100, default 50)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Max results (1-100, default 50)",
              "maximum": 100,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SukukListResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List / filter sukuk",
        "tags": [
          "sukuk"
        ]
      }
    },
    "/v1/sukuk/search": {
      "get": {
        "description": "Case-insensitive search over issuer_name and sukuk_name. Minimum 2 characters required. Returns current active rows only. Results capped at 50.",
        "operationId": "search_sukuk_v1_sukuk_search_get",
        "parameters": [
          {
            "description": "Search term (min 2 chars). Matches issuer name or sukuk name.",
            "in": "query",
            "name": "q",
            "required": true,
            "schema": {
              "description": "Search term (min 2 chars). Matches issuer name or sukuk name.",
              "maxLength": 100,
              "minLength": 2,
              "title": "Q",
              "type": "string"
            }
          },
          {
            "description": "Max results (1-50, default 20)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 20,
              "description": "Max results (1-50, default 20)",
              "maximum": 50,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SukukListResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Search sukuk by issuer name or sukuk name",
        "tags": [
          "sukuk"
        ]
      }
    },
    "/v1/sukuk/types": {
      "get": {
        "description": "Returns the 8 sukuk types defined by AAOIFI Standard 17, with plain-language descriptions and governing standard references. No DB call \u2014 static catalogue.",
        "operationId": "get_sukuk_types_v1_sukuk_types_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SukukTypesResponse"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "List sukuk types (AAOIFI Standard 17)",
        "tags": [
          "sukuk"
        ]
      }
    },
    "/v1/sukuk/{isin}": {
      "get": {
        "description": "Returns full metadata for a single sukuk identified by its ISO 6166 ISIN. Returns the current active row (load_end_ts IS NULL).",
        "operationId": "get_sukuk_by_isin_v1_sukuk__isin__get",
        "parameters": [
          {
            "in": "path",
            "name": "isin",
            "required": true,
            "schema": {
              "title": "Isin",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SukukResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get sukuk by ISIN",
        "tags": [
          "sukuk"
        ]
      }
    },
    "/v1/trial/start": {
      "post": {
        "description": "Starts a one-time 7-day Starter trial for the authenticated account. Idempotent: if the trial was already started, returns the existing trial_expires_at. Trial includes up to 5 000 API calls. No PDF export, no multi-madhab. Disclaimer: data exposed during trial is provided for informational purposes only \u2014 not financial advice.",
        "operationId": "start_trial_v1_trial_start_post",
        "parameters": [
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "title": "Authorization",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrialStartResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Start a 7-day Starter trial (no credit card required)",
        "tags": [
          "trial"
        ]
      }
    },
    "/v1/vwap/by-pair": {
      "get": {
        "description": "Returns VWAP aggregated cross-asset by trading pair. Source: api_views.vwap_by_pair \u2192 marts.fact_vwap_consensus. Not financial advice. Methodology disclosed.",
        "operationId": "get_vwap_by_pair_v1_vwap_by_pair_get",
        "parameters": [
          {
            "description": "Filter by trading pair (e.g. 'CRYPTO/USD').",
            "in": "query",
            "name": "pair",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by trading pair (e.g. 'CRYPTO/USD').",
              "title": "Pair"
            }
          },
          {
            "description": "Max rows (1-1000, default 100).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Max rows (1-1000, default 100).",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VwapByPairResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "VWAP aggregated by trading pair",
        "tags": [
          "vwap"
        ]
      }
    },
    "/v1/vwap/history": {
      "get": {
        "description": "Returns the full VWAP history for an asset \u00d7 pair \u00d7 timeframe. Source: api_views.vwap_history \u2192 dv.sat_asset_vwap_consensus. T-846: ?timeframe=1h|4h|1d|1w|1M (default 1d). Not financial advice. Methodology disclosed.",
        "operationId": "get_vwap_history_v1_vwap_history_get",
        "parameters": [
          {
            "description": "Asset surrogate key. If omitted, returns history for all assets (paginated).",
            "in": "query",
            "name": "asset_hk",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Asset surrogate key. If omitted, returns history for all assets (paginated).",
              "title": "Asset Hk"
            }
          },
          {
            "description": "Trading pair filter (e.g. 'CRYPTO/USD').",
            "in": "query",
            "name": "pair",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Trading pair filter (e.g. 'CRYPTO/USD').",
              "title": "Pair"
            }
          },
          {
            "description": "Candle timeframe. One of: 1h, 4h, 1d, 1w, 1M. Default: 1d.",
            "in": "query",
            "name": "timeframe",
            "required": false,
            "schema": {
              "default": "1d",
              "description": "Candle timeframe. One of: 1h, 4h, 1d, 1w, 1M. Default: 1d.",
              "title": "Timeframe",
              "type": "string"
            }
          },
          {
            "description": "Start timestamp (ISO8601 UTC). Inclusive.",
            "in": "query",
            "name": "from_ts",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date-time",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Start timestamp (ISO8601 UTC). Inclusive.",
              "title": "From Ts"
            }
          },
          {
            "description": "End timestamp (ISO8601 UTC). Inclusive.",
            "in": "query",
            "name": "to_ts",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date-time",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "End timestamp (ISO8601 UTC). Inclusive.",
              "title": "To Ts"
            }
          },
          {
            "description": "Max rows (1-1000, default 100).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Max rows (1-1000, default 100).",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VwapResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "VWAP history for an asset and pair",
        "tags": [
          "vwap"
        ]
      }
    },
    "/v1/vwap/latest": {
      "get": {
        "description": "Returns the latest VWAP consensus price per asset and trading pair, filtered by timeframe. Source: api_views.vwap_latest \u2192 dv.sat_asset_vwap_consensus. T-846: ?timeframe=1h|4h|1d|1w|1M (default 1d). Not financial advice. Methodology disclosed.",
        "operationId": "get_vwap_latest_v1_vwap_latest_get",
        "parameters": [
          {
            "description": "Filter by asset surrogate key (hex string).",
            "in": "query",
            "name": "asset_hk",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by asset surrogate key (hex string).",
              "title": "Asset Hk"
            }
          },
          {
            "description": "Filter by trading pair (e.g. 'CRYPTO/USD').",
            "in": "query",
            "name": "pair",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by trading pair (e.g. 'CRYPTO/USD').",
              "title": "Pair"
            }
          },
          {
            "description": "Candle timeframe. One of: 1h, 4h, 1d, 1w, 1M. Default: 1d.",
            "in": "query",
            "name": "timeframe",
            "required": false,
            "schema": {
              "default": "1d",
              "description": "Candle timeframe. One of: 1h, 4h, 1d, 1w, 1M. Default: 1d.",
              "title": "Timeframe",
              "type": "string"
            }
          },
          {
            "description": "Max rows to return (1-1000, default 100).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 100,
              "description": "Max rows to return (1-1000, default 100).",
              "maximum": 1000,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VwapResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Latest VWAP by asset and pair",
        "tags": [
          "vwap"
        ]
      }
    },
    "/v1/webhooks/list": {
      "get": {
        "description": "Return all active webhook subscriptions for the authenticated API key.",
        "operationId": "list_subscriptions_v1_webhooks_list_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "List active webhook subscriptions",
        "tags": [
          "webhooks"
        ]
      }
    },
    "/v1/webhooks/subscribe": {
      "post": {
        "description": "Create a webhook subscription.\n\nThe signing secret is returned **once** \u2014 store it securely.\nDeliveries are signed: `X-PIQ-Signature: sha256=<hmac-hex>`.",
        "operationId": "subscribe_v1_webhooks_subscribe_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscribeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscribeResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Subscribe to webhook events",
        "tags": [
          "webhooks"
        ]
      }
    },
    "/v1/webhooks/unsubscribe": {
      "post": {
        "description": "Soft-delete a webhook subscription (sets is_active = false).",
        "operationId": "unsubscribe_v1_webhooks_unsubscribe_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UnsubscribeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Unsubscribe from webhook events",
        "tags": [
          "webhooks"
        ]
      }
    },
    "/v1/zakat/calculate": {
      "post": {
        "description": "Computes Zakat due on a portfolio of assets using AAOIFI Standard 35. Pure-logic endpoint \u2014 no DB, no external APIs. Supports 5 asset classes (cash, stock, crypto, gold_grams, silver_grams). Returns a full breakdown with per-asset methodology notes and disclaimer. Available on free tier.",
        "operationId": "calculate_zakat_v1_zakat_calculate_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ZakatRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZakatResponse"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Calculate Zakat due",
        "tags": [
          "islamic-finance",
          "islamic-finance"
        ]
      }
    }
  },
  "security": [
    {
      "BearerAuth": []
    },
    {
      "ApiKeyAuth": []
    }
  ],
  "servers": [
    {
      "description": "Production",
      "url": "https://api.portfoliq.io"
    },
    {
      "description": "Staging (internal testing)",
      "url": "https://staging-api.portfoliq.io"
    },
    {
      "description": "Local development",
      "url": "http://localhost:8000"
    }
  ]
}
