openapi: 3.0.1 info: version: 1.0.0 title: Authorization Tokens Accounts PortfolioOptimizer API description: 'Use the `oauth` endpoint to generate the secure, time-limited JSON Web Tokens (JWTs) used to authorize access to APIs and components.

To request a token, click Authorize and enter the following credentials: * Username - Your Client ID. * Password - Your Client Secret.' servers: - url: https://www.us-api.morningstar.com/token description: PROD US - url: https://www.emea-api.morningstar.com/token description: PROD EMEA - url: https://www.apac-api.morningstar.com/token description: PROD APAC security: - BasicAuth: [] tags: - name: PortfolioOptimizer paths: /portfolioanalysis/v1/portfolio-optimizer: post: tags: - PortfolioOptimizer summary: Portfolio Optimizer description: Create an optimal portfolio that will best align with the investor's asset allocation and risk tolerance. parameters: - name: langcult in: query required: false description: ISO culture code. Overrides the value in the Accept-Language HTTP header. If not provided, defaults to the language defined in the settings. schema: type: string default: en-US enum: - en-US - en-CA - fr-CA requestBody: $ref: '#/components/requestBodies/RequestPortfolioOptimizer' responses: '200': $ref: '#/components/responses/ResponsePortfolioOptimizer' '400': $ref: '#/components/responses/ErrorResponse400' '500': $ref: '#/components/responses/ErrorResponse500' components: examples: ErrorResponse500Example2: summary: Internal Server Error - Error Fetching Covariance value: statusCode: 500 errorCode: 500.portfolioOptimizer.004 message: Error fetching covariance. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de PortfolioOptimizerResponseExample2: summary: Portfolio Without Weight Specified - Optimized value: optimizedPortfolio: - name: Portfolio Without Weight Specified endDate: '2026-03-31' holdings: - securityName: Vanguard Total Intl Stock Idx Instl Sel securityId: F00000WTNS weight: 14.22472048 - securityName: Vanguard Total Bond Market Index I securityId: FOUSA00DIL weight: 53.94644095 - securityName: Vanguard Total Intl Bd Idx Admiral™ securityId: F00000NBIL weight: 31.82883858 metadata: requestId: a2859927-c9ac-499a-8f91-daa1d6ef06f4 time: '2026-04-28T14:19:35.2263747Z' ErrorResponse400Example8: summary: Bad Request - Total Weight Custom Target Asset Allocations Does Not Equal 100 value: statusCode: 400 errorCode: 400.portfolioOptimizer.010 message: The total weight of custom target asset allocations doesn't add up to 100. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de ErrorResponse400Example15: summary: Bad Request - Required Portfolios Input Missing value: statusCode: 400 errorCode: 400.portfolioOptimizer.105 message: No portfolios present in request. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de ErrorResponse400Example3: summary: Bad Request - Error While Fetching Covariance value: statusCode: 400 errorCode: 400.portfolioOptimizer.005 message: Bad Request while fetching covariance. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de PortfolioOptimizerRequestExample3: summary: Request With Custom Target Allocations value: assetClassLineupId: US targetAllocationId: moderate portfolios: - name: Portfolio ABC holdings: - SecurityId: F00000QK4O - SecurityId: F00000W0CQ - SecurityId: F000003Y6K - SecurityId: F000002YE5 - SecurityId: FOUSA00GKI - SecurityId: F00000YGWN - SecurityId: FOUSA06VZ6 - SecurityId: FOUSA06WRK - SecurityId: FOUSA06WRH customTargetAllocations: - assetClassId: stock_US weight: 47.5 - assetClassId: stock_DM_xUS weight: 10.5 - assetClassId: stock_EM weight: 2 - assetClassId: bond_US_IG weight: 26.5 - assetClassId: bond_US_HY weight: 4 - assetClassId: bond_xUS weight: 4 - assetClassId: cash weight: 5.5 ErrorResponse400Example9: summary: Bad Request - Maximum Number of Portfolios Exceeded value: statusCode: 400 errorCode: 400.portfolioOptimizer.011 message: Portfolio optimizer is only supported with one portfolio. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de ErrorResponse400Example14: summary: Bad Request - Required Portfolio Holdings Input Missing value: statusCode: 400 errorCode: 400.portfolioOptimizer.104 message: 'No holdings present in portfolio. Invalid portfolio: ''{Portfolio Name}''.' requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de PortfolioOptimizerRequestExample2: summary: Portfolio Without Weight Specified value: assetClassLineupId: US targetAllocationId: conservative portfolios: - name: Portfolio Without Weight Specified holdings: - securityName: Vanguard Total Intl Stock Idx Instl Sel securityId: F00000WTNS - securityName: Vanguard Total Bond Market Index I securityId: FOUSA00DIL - securityName: Vanguard Total Intl Bd Idx Admiral™ securityId: F00000NBIL objectives: trackingError: 0.5 ErrorResponse400Example5: summary: Bad Request - Minumum Number of Asset Classes Not Met value: statusCode: 400 errorCode: 400.portfolioOptimizer.007 message: Minimum two asset classes required for Target Allocations. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de ErrorResponse400Example10: summary: Bad Request - All Cash Portfolio Not Supported value: statusCode: 400 errorCode: 400.portfolioOptimizer.012 message: All cash portfolio not supported. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de PortfolioOptimizerResponseExample1: summary: Portfolio With Minimum and Maximum Weights - Optimized value: optimizedPortfolio: - name: Portfolio With Minimum and Maximum Weights endDate: '2026-03-31' holdings: - securityName: Vanguard Total Intl Stock Idx Instl Sel securityId: F00000WTNS weight: 4.99963084 - securityName: Vanguard Total Bond Market Index I securityId: FOUSA00DIL weight: 67.61701261 - securityName: Vanguard Total Intl Bd Idx Admiral™ securityId: F00000NBIL weight: 27.38335655 metadata: requestId: 4427c25e-f03e-440f-abb9-fd41edc1dce0 time: '2026-04-28T14:09:46.5568103Z' ErrorResponse400Example11: summary: Bad Request - Number of Holdings Does Not Meet Required Minimum value: statusCode: 400 errorCode: 400.portfolioOptimizer.013 message: At least 2 holdings are required in portfolio. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de ErrorResponse400Example2: summary: Bad Request - Required Fields Missing value: statusCode: 400 errorCode: 400.portfolioOptimizer.002 message: Either 'targetAllocationClassification' or 'customTargetAllocations' is required. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de ErrorResponse400Example6: summary: Bad Request - Configuration Not Available for Asset Class Line Up Id value: statusCode: 400 errorCode: 400.portfolioOptimizer.008 message: 'Configuration not available for assetClassLineupId: ''{assetClassLineupIdName}''.' requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de ErrorResponse500Example1: summary: Internal Server Error - Error Fetching Monthly Returns value: statusCode: 500 errorCode: 500.portfolioOptimizer.003 message: Error fetching monthly returns. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de ErrorResponse400Example4: summary: Bad Request - Target Allocation Configuration Not Available value: statusCode: 400 errorCode: 400.portfolioOptimizer.006 message: Target allocation configuration not available. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de ErrorResponse400Example1: summary: Bad Request - Configuration Not Available for Input Asset Class ID value: statusCode: 400 errorCode: 400.portfolioOptimizer.001 message: 'Configuration not available for assetClassId: {''''}' requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de PortfolioOptimizerResponseExample3: summary: Request With Custom Target Allocations value: optimizedPortfolio: - name: Portfolio ABC endDate: '2026-03-31' holdings: - securityName: AB Global Bond Z securityId: F00000QK4O weight: 1.73114627 - securityName: AB Small Cap Growth Z securityId: F00000W0CQ weight: 14.95884856 - securityName: Akre Focus ETF securityId: F000003Y6K weight: 14.95884856 - securityName: American Beacon International Eq Y securityId: F000002YE5 weight: 6.04299834 - securityName: American Century Equity Income I securityId: FOUSA00GKI weight: 0.8234858 - securityName: American Century Inflation Adjs Bond I securityId: F00000YGWN weight: 39.5278459 - securityName: American Funds AMCAP F2 securityId: FOUSA06VZ6 weight: 14.63792278 - securityName: American Funds American Mutual F2 securityId: FOUSA06WRK weight: 1.02529939 - securityName: American Funds EUPAC F2 securityId: FOUSA06WRH weight: 6.29360441 metadata: requestId: cdfa918a-8290-4de6-adc0-136e9afc0345 time: '2026-04-28T14:32:33.0318176Z' ErrorResponse400Example7: summary: Bad Request - Configuration Not Available for Target Allocation ID value: statusCode: 400 errorCode: 400.portfolioOptimizer.009 message: 'Configuration not available for targetAllocationId: ''{targetAllocationIdName}''.' requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de PortfolioOptimizerRequestExample1: summary: Portfolio with Minimum and Maximum Weights value: assetClassLineupId: US targetAllocationId: conservative portfolios: - name: Portfolio With Minimum and Maximum Weights holdings: - securityName: Vanguard Total Intl Stock Idx Instl Sel securityId: F00000WTNS maxWeight: 5 - securityName: Vanguard Total Bond Market Index I securityId: FOUSA00DIL minWeight: 3 - securityName: Vanguard Total Intl Bd Idx Admiral™ securityId: F00000NBIL minWeight: 3 objectives: trackingError: 0.5 ErrorResponse400Example12: summary: Bad Request - Portfolio Contains Duplicate Security IDs value: statusCode: 400 errorCode: 400.portfolioOptimizer.014 message: Portfolio holding has duplicate security IDs. requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de ErrorResponse400Example13: summary: Bad Request - Maximum Number of Holdings Exceeded value: statusCode: 400 errorCode: 400.portfolioOptimizer.102 message: The number of holdings exceeds the maximum allowed holdings for this endpoint (250). requestId: 33f0a7e0-8088-4ea9-b26e-d356b888e7de schemas: RequestPortfolioOptimizer: required: - assetClassLineupId - targetAllocationId - portfolios - objectives type: object description: Portfolio Optimizer Request properties: assetClassLineupId: type: string description: Identifier for a set of target allocations based on region-specific asset class preferences and risk tolerances. Configured during implementation. See Default Target Allocations for Morningstar-defined default allocations. example: MSTAR_US targetAllocationId: type: string description: Identifier for the target asset allocation to optimize against. example: Moderate portfolios: type: array description: List of holdings to pass in the request. Only one portfolio is supported per request. items: $ref: '#/components/schemas/InputPortfolio' objectives: $ref: '#/components/schemas/InputObjectives' customTargetAllocations: type: array description: A list of asset classes and allocated weights. Overrides the weights of the value specified in the targetAllocationId parameter. All weights must sum to 100. nullable: true items: $ref: '#/components/schemas/InputCustomTargetAllocation' OutputOptimizedHolding: type: object properties: securityName: type: string description: Display name of the security. nullable: true securityId: type: string description: Morningstar unique identifier for the security. nullable: true example: FOUSA00CEK weight: type: number format: double description: Optimised weight for this holding as a proportion of the portfolio (e.g. 1 = 100%). nullable: true InputPortfolio: required: - name - holdings type: object description: Portfolio input object. properties: name: type: string minLength: 1 description: Portfolio name. example: Portfolio Set 1 holdings: type: array description: List of portfolio holdings. Minimum 2 holdings required. Maximum 250 holdings allowed. Duplicate security IDs are not permitted. items: $ref: '#/components/schemas/InputPortfolioHolding' OutputMessage: type: object description: Message model. properties: type: type: string description: Type of message. enum: - Warning - Info message: type: string description: Human-readable description of the message. nullable: true code: type: string description: Unique identifier for this message type. nullable: true ids: type: array description: List of identifiers for this message. nullable: true items: type: string invalidHoldings: type: array description: List of holdings that were invalid or could not be processed. nullable: true items: $ref: '#/components/schemas/OutputInvalidHolding' referenceId: type: string description: The ID of the object this message relates to. nullable: true OutputOptimizedPortfolio: type: object properties: name: type: string description: Portfolio name echoed from the request. nullable: true endDate: type: string description: End date of the monthly returns data used in the optimisation. Format yyyy-MM-dd. nullable: true holdings: type: array description: List of optimised holdings with their calculated weights. Empty when no valid returns data is available. nullable: true items: $ref: '#/components/schemas/OutputOptimizedHolding' metadata: $ref: '#/components/schemas/OutputMetadata' InputPortfolioHolding: required: - SecurityId type: object properties: SecurityId: type: string description: Unique identifier of a security. example: FOUSA00DFS minWeight: type: number format: double description: Minimum value for the optimized weight range. default: 0 example: 0.1 nullable: true maxWeight: type: number format: double description: Maximum value for the optimized weight range. default: 1 example: 0.8 nullable: true ResponsePortfolioOptimizer: type: object description: Portfolio Optimizer Response properties: optimizedPortfolio: type: array nullable: true items: $ref: '#/components/schemas/OutputOptimizedPortfolio' metadata: $ref: '#/components/schemas/OutputMetadata' ResponseError: type: object description: Error details. properties: statusCode: type: integer format: int32 description: HTTP status code. errorCode: type: string description: Application-specific error code. nullable: true message: type: string description: Human-readable error description. nullable: true requestId: type: string description: Unique identifier of the failed request, useful for support. nullable: true InputCustomTargetAllocation: required: - assetClassId - weight type: object properties: assetClassId: type: string description: Asset class identifier. example: stock_US weight: type: number format: double description: Allocated weight for this asset class. example: 5 OutputInvalidHolding: type: object description: Describes an invalid holding returned in a warning message. properties: securityId: type: string description: Security identifier of the invalid holding. nullable: true status: type: string description: Indicates why a holding is invalid. enum: - Unknown - Invalid - NotEntitled OutputMetadata: type: object description: Metadata model. properties: requestId: type: string description: Unique identifier of the request, useful for support and debugging. nullable: true example: 33f0a7e0-8088-4ea9-b26e-d356b888e7de time: type: string format: date-time description: ISO 8601 timestamp indicating when the response was generated. readOnly: true example: '2024-05-14T16:41:24.4418482Z' messages: type: array description: List of informational or warning messages related to the response. nullable: true items: $ref: '#/components/schemas/OutputMessage' InputObjectives: required: - trackingError type: object properties: trackingError: type: number format: double description: Maximum divergence from the benchmark. default: 1 example: 2 requestBodies: RequestPortfolioOptimizer: required: true content: application/json: schema: $ref: '#/components/schemas/RequestPortfolioOptimizer' examples: PortfolioOptimizerRequestExample1: $ref: '#/components/examples/PortfolioOptimizerRequestExample1' PortfolioOptimizerRequestExample2: $ref: '#/components/examples/PortfolioOptimizerRequestExample2' PortfolioOptimizerRequestExample3: $ref: '#/components/examples/PortfolioOptimizerRequestExample3' responses: ResponsePortfolioOptimizer: description: '200: OK' content: application/json: schema: $ref: '#/components/schemas/ResponsePortfolioOptimizer' examples: PortfolioOptimizerResponseExample1: $ref: '#/components/examples/PortfolioOptimizerResponseExample1' PortfolioOptimizerResponseExample2: $ref: '#/components/examples/PortfolioOptimizerResponseExample2' PortfolioOptimizerResponseExample3: $ref: '#/components/examples/PortfolioOptimizerResponseExample3' ErrorResponse400: description: '400: Bad Request' content: application/json: schema: $ref: '#/components/schemas/ResponseError' examples: ErrorResponse400Example1: $ref: '#/components/examples/ErrorResponse400Example1' ErrorResponse400Example2: $ref: '#/components/examples/ErrorResponse400Example2' ErrorResponse400Example3: $ref: '#/components/examples/ErrorResponse400Example3' ErrorResponse400Example4: $ref: '#/components/examples/ErrorResponse400Example4' ErrorResponse400Example5: $ref: '#/components/examples/ErrorResponse400Example5' ErrorResponse400Example6: $ref: '#/components/examples/ErrorResponse400Example6' ErrorResponse400Example7: $ref: '#/components/examples/ErrorResponse400Example7' ErrorResponse400Example8: $ref: '#/components/examples/ErrorResponse400Example8' ErrorResponse400Example9: $ref: '#/components/examples/ErrorResponse400Example9' ErrorResponse400Example10: $ref: '#/components/examples/ErrorResponse400Example10' ErrorResponse400Example11: $ref: '#/components/examples/ErrorResponse400Example11' ErrorResponse400Example12: $ref: '#/components/examples/ErrorResponse400Example12' ErrorResponse400Example13: $ref: '#/components/examples/ErrorResponse400Example13' ErrorResponse400Example14: $ref: '#/components/examples/ErrorResponse400Example14' ErrorResponse400Example15: $ref: '#/components/examples/ErrorResponse400Example15' ErrorResponse500: description: '500: Internal Server Error' content: application/json: schema: $ref: '#/components/schemas/ResponseError' examples: ErrorResponse500Example1: $ref: '#/components/examples/ErrorResponse500Example1' ErrorResponse500Example2: $ref: '#/components/examples/ErrorResponse500Example2' securitySchemes: BasicAuth: type: http scheme: basic