{
  "openapi": "3.0.0",
  "info": {
    "title": "API Documentation",
    "description": "API for accessing our Multi-Factor Portfolios, Cross-sectional Factors and Risk Overlays",
    "version": "1.1.2",
    "contact": {
      "name": "Unravel Team",
      "url": "https://unravel.finance",
      "email": "info@unravel.finance"
    }
  },
  "servers": [
    {
      "url": "/api/v1",
      "description": "API base URL"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "name": "X-API-KEY",
        "in": "header",
        "description": "API key obtained from your account settings"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message"
          }
        }
      },
      "NormalizedSeriesResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "number",
              "nullable": true
            },
            "description": "Transformed factor data points"
          },
          "index": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Date indices for the data points"
          }
        },
        "example": {
          "data": [0.45, 0.67, 0.89, 0.23, 0.2, 0.8, 0.87],
          "index": [
            "2023-01-01",
            "2023-01-02",
            "2023-01-03",
            "2023-01-04",
            "2023-01-05",
            "2023-01-06",
            "2025-10-07"
          ]
        }
      },
      "RiskOverlayLiveResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "number",
            "nullable": true,
            "description": "Latest risk overlay data point"
          },
          "index": {
            "type": "string",
            "description": "Date of the latest risk overlay data"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of when the data was created"
          }
        },
        "example": {
          "data": 0.15,
          "index": "2025-10-07",
          "createdAt": "2023-01-07T15:30:00Z"
        }
      },
      "PriceResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number",
                "nullable": true
              }
            },
            "description": "Price data as a 2D array (rows × columns). Each row represents a date, each column represents a ticker. Null values are preserved where price data is unavailable for specific dates, ensuring consistent date ranges across all tickers."
          },
          "index": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Date indices for the price data points"
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ticker symbols corresponding to the columns"
          }
        },
        "example": {
          "data": [
            [45000.25, 3000.5],
            [46700.5, null],
            [47200.75, 3200.75],
            [null, 3150.0],
            [48200.0, 3300.5],
            [49100.5, 3400.25],
            [48700.25, 3350.75]
          ],
          "index": [
            "2023-01-01",
            "2023-01-02",
            "2023-01-03",
            "2023-01-04",
            "2023-01-05",
            "2023-01-06",
            "2025-10-07"
          ],
          "columns": ["BTC", "ETH"]
        }
      },
      "PriceResponseLegacy": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "number",
              "nullable": true
            },
            "description": "Price data points (legacy format for single ticker). Null values are filtered out along with their corresponding dates to maintain data consistency."
          },
          "index": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Date indices for the price data points"
          }
        },
        "example": {
          "data": [
            45000.25, 46700.5, 47200.75, 46800.25, 48200.0, 49100.5, 48700.25
          ],
          "index": [
            "2023-01-01",
            "2023-01-02",
            "2023-01-03",
            "2023-01-04",
            "2023-01-05",
            "2023-01-06",
            "2025-10-07"
          ]
        }
      },
      "PortfolioWeightsResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "number",
              "nullable": true
            },
            "description": "Latest portfolio weights data"
          },
          "index": {
            "type": "string",
            "description": "Date of the latest weights"
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Asset names corresponding to the weights"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of when the data was created"
          }
        },
        "example": {
          "data": [0.25, 0.35, 0.15, 0.25],
          "index": "2023-06-30",
          "columns": ["BTC", "ETH", "SOL", "AVAX"],
          "createdAt": "2023-06-30T15:30:00Z"
        }
      },
      "HistoricalPortfolioWeightsResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number",
                "nullable": true
              }
            },
            "description": "Historical portfolio weights data"
          },
          "index": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Date indices for the weights data"
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Asset names corresponding to the weights"
          }
        }
      },
      "PortfolioFactorsResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number",
                "nullable": true
              }
            },
            "description": "Factor data for the specified tickers"
          },
          "index": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Date indices for the factor data"
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ticker symbols corresponding to the factor data"
          }
        },
        "example": {
          "data": [
            [0.45, 0.67, 0.89],
            [0.23, 0.2, 0.8],
            [0.87, 0.34, 0.56]
          ],
          "index": ["2023-01-01", "2023-01-02", "2023-01-03"],
          "columns": ["BTC", "ETH", "SOL"]
        }
      },
      "PortfolioFactorsLiveResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "number",
              "nullable": true
            },
            "description": "Latest factor data for the specified tickers"
          },
          "index": {
            "type": "string",
            "description": "Date of the latest factor data"
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ticker symbols corresponding to the factor data"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of when the data was created"
          }
        },
        "example": {
          "data": [0.45, 0.67, 0.89],
          "index": "2023-01-03",
          "columns": ["BTC", "ETH", "SOL"],
          "createdAt": "2023-01-03T15:30:00Z"
        }
      },
      "PortfolioTickersResponse": {
        "type": "object",
        "properties": {
          "tickers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of ticker symbols available in the portfolio"
          }
        },
        "example": {
          "tickers": ["BTC", "ETH", "SOL", "AVAX", "MATIC"]
        }
      },
      "PortfolioUniverseResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number",
                "nullable": true
              }
            },
            "description": "Universe data showing which assets are included (1) in the portfolio over time. Null values indicate no data available."
          },
          "index": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Date indices for the universe data"
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Asset names corresponding to the universe data"
          }
        },
        "example": {
          "data": [
            [1, 1, null, 1],
            [1, 1, 1, 1],
            [null, 1, 1, 1]
          ],
          "index": ["2024-01-01", "2024-01-02", "2024-01-03"],
          "columns": ["BTC", "ETH", "SOL", "AVAX"]
        }
      }
    },
    "parameters": {
      "TickerParam": {
        "name": "ticker",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Ticker symbol(s). Can be a single ticker (e.g., BTC) or comma-separated list (e.g., BTC,ETH,SOL). Whitespace around commas is automatically trimmed."
      },
      "SeriesParam": {
        "name": "series",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Series to retrieve (e.g., exchange_outflow, sentiment_aggregate)"
      },
      "SmoothingParam": {
        "name": "smoothing",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": ["default", "0", "7", "30"],
          "default": "default"
        },
        "description": "Smoothing window for the data"
      },
      "PortfolioSmoothingParam": {
        "name": "smoothing",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": ["0", "5", "10", "15", "20", "30"]
        },
        "description": "Portfolio smoothing window for the data. Valid values are 0 (no smoothing), 5, 10, 15, 20, or 30 days. If not specified, uses the portfolio's default smoothing. Invalid values will return a 400 error. Please see Catalog for default smoothing windows and available smoothing options for each portfolio."
      },
      "StartDateParam": {
        "name": "start_date",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "format": "date"
        },
        "description": "Filter data to only include dates on or after this date (ISO format: YYYY-MM-DD)"
      },
      "EndDateParam": {
        "name": "end_date",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "format": "date"
        },
        "description": "Filter data to only include dates on or before this date (ISO format: YYYY-MM-DD)"
      },
      "FactorsParam": {
        "name": "factors",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Comma-separated list of factors to retrieve (e.g., momentum_fast,sentiment_aggregate)"
      },
      "PortfolioParam": {
        "name": "portfolio",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Portfolio Template Identifier (eg. momentum, spectra)"
      },
      "PortfolioFactorParam": {
        "name": "id",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Portfolio Factor Identifier without the universe specifier (eg. momentum instead of momentum.20)"
      },
      "UniverseSizeParam": {
        "name": "universe_size",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Universe size for the portfolio (e.g., 20, 30, 40) or 'full' to get all tickers. Note: Multi-Factor portfolios cannot use 'full' universe size."
      },
      "PortfolioSizeParam": {
        "name": "size",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string",
          "enum": ["20", "30", "40"]
        },
        "description": "Portfolio size - number of assets to include. Must be one of: 20, 30, or 40"
      },
      "TickersParam": {
        "name": "tickers",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Comma-separated list of ticker symbols (e.g., BTC,ETH,SOL)."
      },
      "ExchangeParam": {
        "name": "exchange",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "enum": ["unconstrained", "binance", "okx", "hyperliquid"],
          "default": "unconstrained"
        },
        "description": "Exchange constraint for portfolio data. Valid options are: unconstrained (default), binance, okx. If not specified, defaults to unconstrained."
      },
      "RiskOverlayParam": {
        "name": "overlay",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Risk overlay identifier - a portfolio-specific factor risk overlay"
      }
    }
  },
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/portfolio/live-weights": {
      "get": {
        "summary": "Portfolio / Weights Live",
        "description": "Retrieves the most recent weights for a specific portfolio. Updated hourly with fresh data available 5 minutes past the hour.",
        "operationId": "getLiveWeights",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioParam"
          },
          {
            "$ref": "#/components/parameters/PortfolioSmoothingParam"
          },
          {
            "$ref": "#/components/parameters/ExchangeParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortfolioWeightsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingParams": {
                    "value": {
                      "error": "portfolio param is required"
                    }
                  },
                  "demoRestriction": {
                    "value": {
                      "error": "Only [allowed portfolios] are supported for the demo key"
                    }
                  },
                  "invalidSmoothing": {
                    "value": {
                      "error": "Smoothing invalid_smoothing is not a valid smoothing option"
                    }
                  },
                  "invalidExchange": {
                    "value": {
                      "error": "Exchange invalid_exchange is not supported. Valid options are: unconstrained, binance, okx, hyperliquid"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Authorization header is missing or invalid"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - invalid API key or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Access denied"
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/portfolio/historical-weights": {
      "get": {
        "summary": "Portfolio / Weights Historical",
        "description": "Retrieves historical weights for a specific portfolio over a date range. Returns end-of-day (EOD) values.",
        "operationId": "getHistoricalWeights",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioParam"
          },
          {
            "$ref": "#/components/parameters/PortfolioSmoothingParam"
          },
          {
            "$ref": "#/components/parameters/ExchangeParam"
          },
          {
            "$ref": "#/components/parameters/StartDateParam"
          },
          {
            "$ref": "#/components/parameters/EndDateParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HistoricalPortfolioWeightsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingParams": {
                    "value": {
                      "error": "portfolio param is required"
                    }
                  },
                  "demoRestriction": {
                    "value": {
                      "error": "Only [allowed portfolios] are supported for the demo key"
                    }
                  },
                  "invalidDateFormat": {
                    "value": {
                      "error": "Invalid date format. Use YYYY-MM-DD"
                    }
                  },
                  "invalidSmoothing": {
                    "value": {
                      "error": "Smoothing invalid_smoothing is not a valid smoothing option"
                    }
                  },
                  "invalidExchange": {
                    "value": {
                      "error": "Exchange invalid_exchange is not supported. Valid options are: unconstrained, binance, okx, hyperliquid"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Authorization header is missing or invalid"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - invalid API key or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Access denied"
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/portfolio/factors": {
      "get": {
        "summary": "Portfolio / Raw Factor",
        "description": "Retrieves factor data for specific tickers within a single factor portfolio over a date range. Returns end-of-day (EOD) values.",
        "operationId": "getPortfolioFactors",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioFactorParam"
          },
          {
            "$ref": "#/components/parameters/TickersParam"
          },
          {
            "$ref": "#/components/parameters/PortfolioSmoothingParam"
          },
          {
            "$ref": "#/components/parameters/StartDateParam"
          },
          {
            "$ref": "#/components/parameters/EndDateParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortfolioFactorsResponse"
                },
                "example": {
                  "data": [
                    [0.45, 0.67, 0.89],
                    [0.23, 0.2, 0.8],
                    [0.87, 0.34, 0.56]
                  ],
                  "index": ["2023-01-01", "2023-01-02", "2023-01-03"],
                  "columns": ["BTC", "ETH", "SOL"]
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingTickers": {
                    "value": {
                      "error": "tickers param must be a non-empty string"
                    }
                  },
                  "emptyTickers": {
                    "value": {
                      "error": "tickers are empty or invalid"
                    }
                  },
                  "missingPortfolio": {
                    "value": {
                      "error": "portfolio param is required"
                    }
                  },
                  "incorrectPortfolio": {
                    "value": {
                      "error": "Incorrect portfolio id"
                    }
                  },
                  "multiFactorNotSupported": {
                    "value": {
                      "error": "Multi-Factor portfolios are not supported"
                    }
                  },
                  "invalidSmoothing": {
                    "value": {
                      "error": "Smoothing invalid is not a valid smoothing option"
                    }
                  },
                  "accessDenied": {
                    "value": {
                      "error": "Subscription does not have access to portfolio"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Authorization header is missing or invalid"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - invalid API key or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Access denied"
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/portfolio/factors-live": {
      "get": {
        "summary": "Portfolio / Raw Factor Live",
        "description": "Retrieves the latest factor data for specific tickers within a single factor portfolio. Updated hourly with fresh data available 5 minutes past the hour.",
        "operationId": "getPortfolioFactorsLive",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioFactorParam"
          },
          {
            "$ref": "#/components/parameters/TickersParam"
          },
          {
            "$ref": "#/components/parameters/PortfolioSmoothingParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortfolioFactorsLiveResponse"
                },
                "example": {
                  "data": [0.45, 0.67, 0.89],
                  "index": "2023-01-03",
                  "columns": ["BTC", "ETH", "SOL"]
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters, demo key, or date parameters provided",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "demoKeyNotSupported": {
                    "value": {
                      "error": "Demo API key is not supported for this endpoint"
                    }
                  },
                  "dateParamsNotSupported": {
                    "value": {
                      "error": "start_date and end_date are not supported for this endpoint"
                    }
                  },
                  "missingTickers": {
                    "value": {
                      "error": "tickers param must be a non-empty string"
                    }
                  },
                  "missingPortfolio": {
                    "value": {
                      "error": "portfolio param is required"
                    }
                  },
                  "incorrectPortfolio": {
                    "value": {
                      "error": "Incorrect portfolio id"
                    }
                  },
                  "multiFactorNotSupported": {
                    "value": {
                      "error": "Multi-Factor portfolios are not supported"
                    }
                  },
                  "invalidSmoothing": {
                    "value": {
                      "error": "Smoothing invalid is not a valid smoothing option"
                    }
                  },
                  "accessDenied": {
                    "value": {
                      "error": "Subscription does not have access to portfolio"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Authorization header is missing or invalid"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - invalid API key or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Access denied"
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/portfolio/tickers": {
      "get": {
        "summary": "Portfolio / Tickers",
        "description": "Retrieves the list of ticker symbols available in a specific portfolio. Multi-Factor portfolios cannot be used with 'full' universe size.",
        "operationId": "getPortfolioTickers",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioFactorParam"
          },
          {
            "$ref": "#/components/parameters/UniverseSizeParam"
          },
          {
            "$ref": "#/components/parameters/ExchangeParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortfolioTickersResponse"
                },
                "example": {
                  "tickers": ["BTC", "ETH", "SOL", "AVAX", "MATIC"]
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingParams": {
                    "value": {
                      "error": "portfolio param is required"
                    }
                  },
                  "missingUniverseSize": {
                    "value": {
                      "error": "universe_size param is required"
                    }
                  },
                  "incorrectPortfolio": {
                    "value": {
                      "error": "Incorrect portfolio id"
                    }
                  },
                  "portfolioWithUniverseSize": {
                    "value": {
                      "error": "portfolioId should not contain universe size, pass in momentum instead of momentum.20."
                    }
                  },
                  "multiFactorFullUniverseNotSupported": {
                    "value": {
                      "error": "Multi-Factor portfolios cannot be used with full universe size"
                    }
                  },
                  "invalidExchange": {
                    "value": {
                      "error": "Exchange invalid_exchange is not supported. Valid options are: unconstrained, binance, okx, hyperliquid"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Authorization header is missing or invalid"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - invalid API key or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Access denied"
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/portfolio/universe": {
      "get": {
        "summary": "Portfolio / Universe",
        "description": "Retrieves the universe data for a portfolio, showing which assets are included in the portfolio over time. The data is returned as binary values (1 for included, null for no data). Use the size parameter to specify the portfolio size (e.g., 20, 30, 40).",
        "operationId": "getPortfolioUniverse",
        "parameters": [
          {
            "$ref": "#/components/parameters/StartDateParam"
          },
          {
            "$ref": "#/components/parameters/EndDateParam"
          },
          {
            "$ref": "#/components/parameters/PortfolioSizeParam"
          },
          {
            "$ref": "#/components/parameters/ExchangeParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortfolioUniverseResponse"
                },
                "example": {
                  "data": [
                    [1, 1, 0, 1],
                    [1, 1, 1, 1],
                    [0, 1, 1, 1]
                  ],
                  "index": ["2024-01-01", "2024-01-02", "2024-01-03"],
                  "columns": ["BTC", "ETH", "SOL", "AVAX"]
                }
              },
              "PortfolioReturnsResponse": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "array",
                    "items": {
                      "type": "number",
                      "nullable": true
                    },
                    "description": "Portfolio returns data points (percentage changes)"
                  },
                  "index": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Date indices for the returns data"
                  },
                  "columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Column names for the returns data (always 'returns')"
                  }
                },
                "example": {
                  "data": [
                    0.0, 0.0234, -0.0156, 0.0456, 0.0123, -0.0089, 0.0345
                  ],
                  "index": [
                    "2023-01-01",
                    "2023-01-02",
                    "2023-01-03",
                    "2023-01-04",
                    "2023-01-05",
                    "2023-01-06",
                    "2025-10-07"
                  ],
                  "columns": ["returns"]
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingParams": {
                    "value": {
                      "error": "size param is required"
                    }
                  },
                  "missingSize": {
                    "value": {
                      "error": "size param is required"
                    }
                  },
                  "invalidSize": {
                    "value": {
                      "error": "Invalid size. Must be one of: 20, 30, or 40"
                    }
                  },
                  "invalidDateFormat": {
                    "value": {
                      "error": "Invalid date format. Use YYYY-MM-DD"
                    }
                  },
                  "invalidExchange": {
                    "value": {
                      "error": "Exchange invalid_exchange is not supported. Valid options are: unconstrained, binance, okx, hyperliquid"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Authorization header is missing or invalid"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - invalid API key or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Subscription does not have access to portfolio"
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/portfolio/returns": {
      "get": {
        "summary": "Portfolio / Returns",
        "description": "Retrieves returns data for a specific portfolio over a date range. Returns end-of-day (EOD) values.",
        "operationId": "getPortfolioReturns",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioParam"
          },
          {
            "$ref": "#/components/parameters/PortfolioSmoothingParam"
          },
          {
            "$ref": "#/components/parameters/ExchangeParam"
          },
          {
            "$ref": "#/components/parameters/StartDateParam"
          },
          {
            "$ref": "#/components/parameters/EndDateParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortfolioReturnsResponse"
                },
                "example": {
                  "data": [
                    0.0, 0.0234, -0.0156, 0.0456, 0.0123, -0.0089, 0.0345
                  ],
                  "index": [
                    "2023-01-01",
                    "2023-01-02",
                    "2023-01-03",
                    "2023-01-04",
                    "2023-01-05",
                    "2023-01-06",
                    "2025-10-07"
                  ],
                  "columns": ["returns"]
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingParams": {
                    "value": {
                      "error": "portfolio param is required"
                    }
                  },
                  "incorrectPortfolio": {
                    "value": {
                      "error": "Incorrect portfolio id"
                    }
                  },
                  "noReturnsSeries": {
                    "value": {
                      "error": "No returns series found"
                    }
                  },
                  "invalidSmoothing": {
                    "value": {
                      "error": "Smoothing invalid is not a valid smoothing option"
                    }
                  },
                  "invalidDateFormat": {
                    "value": {
                      "error": "Invalid date format. Use YYYY-MM-DD"
                    }
                  },
                  "invalidExchange": {
                    "value": {
                      "error": "Exchange invalid_exchange is not supported. Valid options are: unconstrained, binance, okx, hyperliquid"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Authorization header is missing or invalid"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - invalid API key or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "invalidKey": {
                    "value": {
                      "error": "Invalid API key"
                    }
                  },
                  "accessDenied": {
                    "value": {
                      "error": "Access denied"
                    }
                  },
                  "subscriptionAccess": {
                    "value": {
                      "error": "Subscription does not have access to portfolio"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },

    "/portfolio/risk-overlay": {
      "get": {
        "summary": "Portfolio / Risk Overlay Hist.",
        "description": "Retrieves risk overlay time series data for a specific portfolio. Risk overlays are portfolio-specific factor risk overlays. Returns end-of-day (EOD) values.",
        "operationId": "getRiskOverlay",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioParam"
          },
          {
            "$ref": "#/components/parameters/RiskOverlayParam"
          },
          {
            "$ref": "#/components/parameters/StartDateParam"
          },
          {
            "$ref": "#/components/parameters/EndDateParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NormalizedSeriesResponse"
                },
                "example": {
                  "data": [0.05, 0.12, 0.08, 0.15, 0.1, 0.18, 0.14],
                  "index": [
                    "2023-01-01",
                    "2023-01-02",
                    "2023-01-03",
                    "2023-01-04",
                    "2023-01-05",
                    "2023-01-06",
                    "2025-10-07"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingPortfolio": {
                    "value": {
                      "error": "portfolio param is required"
                    }
                  },
                  "incorrectPortfolio": {
                    "value": {
                      "error": "Incorrect portfolio id"
                    }
                  },
                  "missingOverlayId": {
                    "value": {
                      "error": "overlay param is required"
                    }
                  },
                  "incorrectOverlay": {
                    "value": {
                      "error": "Incorrect overlay id"
                    }
                  },
                  "invalidDateFormat": {
                    "value": {
                      "error": "Invalid date format. Use YYYY-MM-DD"
                    }
                  },
                  "invalidSmoothing": {
                    "value": {
                      "error": "Invalid smoothing window"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key, or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "invalidAuthorization": {
                    "value": {
                      "error": "Authorization header is missing or invalid"
                    }
                  },
                  "unavailableForSubscription": {
                    "value": {
                      "error": "Pro subscription does not have access to risk overlays or risk regimes"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - invalid API key or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Access denied"
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/portfolio/risk-overlay-live": {
      "get": {
        "summary": "Portfolio / Risk Overlay Live",
        "description": "Retrieves the latest risk overlay data point for a specific portfolio and overlay. Risk overlays are portfolio-specific factor risk overlays. Updated hourly with fresh data available 5 minutes past the hour.",
        "operationId": "getRiskOverlayLive",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioParam"
          },
          {
            "$ref": "#/components/parameters/RiskOverlayParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RiskOverlayLiveResponse"
                },
                "example": {
                  "data": 0.15,
                  "index": "2025-10-07"
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingPortfolio": {
                    "value": {
                      "error": "portfolio param is required"
                    }
                  },
                  "incorrectPortfolio": {
                    "value": {
                      "error": "Incorrect portfolio id"
                    }
                  },
                  "missingOverlayId": {
                    "value": {
                      "error": "overlay param is required"
                    }
                  },
                  "incorrectOverlay": {
                    "value": {
                      "error": "Incorrect overlay id"
                    }
                  },
                  "invalidSmoothing": {
                    "value": {
                      "error": "Invalid smoothing window"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key, or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "invalidAuthorization": {
                    "value": {
                      "error": "Authorization header is missing or invalid"
                    }
                  },
                  "unavailableForSubscription": {
                    "value": {
                      "error": "subscription does not have access to risk overlays or risk regimes"
                    }
                  },
                  "noPortfolioAccess": {
                    "value": {
                      "error": "Subscription does not have access to portfolio"
                    }
                  },
                  "noRiskAccess": {
                    "value": {
                      "error": "Subscription does not have access to risk"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/risk-regime": {
      "get": {
        "summary": "Risk Regime Historical",
        "description": "Retrieves risk regime time series data. Risk regimes are factor risk overlays applicable to all portfolios, including custom ones. Returns end-of-day (EOD) values.",
        "operationId": "getRiskRegime",
        "parameters": [
          {
            "$ref": "#/components/parameters/RiskOverlayParam"
          },
          {
            "$ref": "#/components/parameters/StartDateParam"
          },
          {
            "$ref": "#/components/parameters/EndDateParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NormalizedSeriesResponse"
                },
                "example": {
                  "data": [0.05, 0.12, 0.08, 0.15, 0.1, 0.18, 0.14],
                  "index": [
                    "2023-01-01",
                    "2023-01-02",
                    "2023-01-03",
                    "2023-01-04",
                    "2023-01-05",
                    "2023-01-06",
                    "2025-10-07"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingOverlayId": {
                    "value": {
                      "error": "overlay param is required"
                    }
                  },
                  "incorrectOverlay": {
                    "value": {
                      "error": "Incorrect overlay id"
                    }
                  },
                  "invalidDateFormat": {
                    "value": {
                      "error": "Invalid date format. Use YYYY-MM-DD"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "invalidAuthorization": {
                    "value": {
                      "error": "Authorization header is missing or invalid"
                    }
                  },
                  "unavailableForSubscription": {
                    "value": {
                      "error": "Pro subscription does not have access to risk regimes"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/risk-regime-live": {
      "get": {
        "summary": "Risk Regime Live",
        "description": "Retrieves the latest risk regime data point. Risk regimes are factor risk overlays applicable to all portfolios, including custom ones. Updated hourly with fresh data available 5 minutes past the hour.",
        "operationId": "getRiskRegimeLive",
        "parameters": [
          {
            "$ref": "#/components/parameters/RiskOverlayParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RiskOverlayLiveResponse"
                },
                "example": {
                  "data": 0.15,
                  "index": "2025-10-07"
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingOverlayId": {
                    "value": {
                      "error": "overlay param is required"
                    }
                  },
                  "incorrectOverlay": {
                    "value": {
                      "error": "Incorrect overlay id"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key, or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "invalidAuthorization": {
                    "value": {
                      "error": "Authorization header is missing or invalid"
                    }
                  },
                  "unavailableForSubscription": {
                    "value": {
                      "error": "subscription does not have access to risk regimes"
                    }
                  },
                  "noPortfolioAccess": {
                    "value": {
                      "error": "Subscription does not have access to portfolio"
                    }
                  },
                  "noRiskAccess": {
                    "value": {
                      "error": "Subscription does not have access to risk"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/price": {
      "get": {
        "summary": "Price / Closing",
        "description": "Retrieve closing price data for one or more cryptocurrency tickers. Supports single ticker requests (returns legacy format for backward compatibility) or comma-separated multiple ticker requests (returns dataframe format similar to historical-weights endpoint). \n\n**Single ticker (legacy)**: Null values are filtered out along with their corresponding dates.\n**Multiple tickers (dataframe)**: Null values are preserved in the matrix, ensuring consistent date ranges across all tickers.",
        "operationId": "getPrice",
        "parameters": [
          {
            "$ref": "#/components/parameters/TickerParam"
          },
          {
            "$ref": "#/components/parameters/StartDateParam"
          },
          {
            "$ref": "#/components/parameters/EndDateParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PriceResponseLegacy"
                    },
                    {
                      "$ref": "#/components/schemas/PriceResponse"
                    }
                  ]
                },
                "examples": {
                  "singleTicker": {
                    "summary": "Single ticker response (legacy format)",
                    "value": {
                      "data": [
                        45000.25, 46700.5, 47200.75, 46800.25, 48200.0, 49100.5,
                        48700.25
                      ],
                      "index": [
                        "2023-01-01",
                        "2023-01-02",
                        "2023-01-03",
                        "2023-01-04",
                        "2023-01-05",
                        "2023-01-06",
                        "2025-10-07"
                      ]
                    }
                  },
                  "multipleTickers": {
                    "summary": "Multiple tickers response (dataframe format)",
                    "value": {
                      "data": [
                        [45000.25, 3000.5],
                        [46700.5, 3100.25],
                        [47200.75, 3200.75],
                        [46800.25, 3150.0],
                        [48200.0, 3300.5],
                        [49100.5, 3400.25],
                        [48700.25, 3350.75]
                      ],
                      "index": [
                        "2023-01-01",
                        "2023-01-02",
                        "2023-01-03",
                        "2023-01-04",
                        "2023-01-05",
                        "2023-01-06",
                        "2025-10-07"
                      ],
                      "columns": ["BTC", "ETH"]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingParams": {
                    "value": {
                      "error": "ticker is required"
                    }
                  },
                  "emptyTickerList": {
                    "value": {
                      "error": "At least one valid ticker is required"
                    }
                  },
                  "invalidDateFormat": {
                    "value": {
                      "error": "Invalid date format. Use YYYY-MM-DD"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Authorization header is missing or invalid"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - invalid API key or insufficient subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "invalidKey": {
                    "value": {
                      "error": "Invalid API key"
                    }
                  },
                  "accessDenied": {
                    "value": {
                      "error": "Access denied"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}
